From b85819a5c6ac1ff35a367eee9bf21472e87622ee Mon Sep 17 00:00:00 2001 From: Samson Shenglu Cao Date: Mon, 6 Mar 2017 11:53:18 +0800 Subject: [PATCH 001/203] modify --- group19/972815123/src/com/coderising/litestruts/Struts.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/group19/972815123/src/com/coderising/litestruts/Struts.java b/group19/972815123/src/com/coderising/litestruts/Struts.java index 7d908282b6..2aeaffd491 100644 --- a/group19/972815123/src/com/coderising/litestruts/Struts.java +++ b/group19/972815123/src/com/coderising/litestruts/Struts.java @@ -52,7 +52,7 @@ public class Struts { public static View runAction(String actionName, Map parameters) { HashMap> xml = parseStrutsXml(url); - HashMap login = xml.get("login"); + HashMap login = xml.get(actionName); String loginClassName = login.get("class"); System.out.println(loginClassName); From 4c61b24c65f4c10d0ec206108ee2bfb8b94306a6 Mon Sep 17 00:00:00 2001 From: x_zhaohu Date: Tue, 7 Mar 2017 21:41:52 +0800 Subject: [PATCH 002/203] xiaoti --- .../DataStructure/src/main/java/com/Main.java | 57 +------ .../basic/.LinkedList.java.swp} | Bin 12288 -> 16384 bytes .../java/com/coding/basic/LinkedList.java | 156 +++++++++++++++++- 3 files changed, 164 insertions(+), 49 deletions(-) rename group11/1178243325/DataStructure/src/main/java/com/{coderising/litestruts/.Struts.java.swp => coding/basic/.LinkedList.java.swp} (57%) diff --git a/group11/1178243325/DataStructure/src/main/java/com/Main.java b/group11/1178243325/DataStructure/src/main/java/com/Main.java index f5e5a36ebd..8d49de33c4 100644 --- a/group11/1178243325/DataStructure/src/main/java/com/Main.java +++ b/group11/1178243325/DataStructure/src/main/java/com/Main.java @@ -1,56 +1,17 @@ package com; -import java.util.*; -import com.coderising.litestruts.*; -import com.coderising.array.*; +import com.coding.basic.LinkedList; +import com.coding.basic.Iterator; public class Main { public static void main(String[] args) { - int[] array = {1, 2, 3, 4, 5}; - System.out.print("reverseArray测试:"); - ArrayUtil.reverseArray(array); - for (int i : array) - System.out.print(i + " "); - System.out.print("\nremoveZero测试:"); + LinkedList list = new LinkedList(); - int[] oldArray = {1, 3, 4, 5, 0, 0, 8 , 0, 9}; - oldArray = ArrayUtil.removeZero(oldArray); - for (int i : oldArray) { - System.out.print(i + " "); + for(int i = 0; i < 10; i++) + list.add(i); + list.remove(2, 5); + Iterator iter = list.iterator(); + while(iter.hasNext()) { + System.out.println(iter.next()); } - - System.out.print("\nmerge测试:"); - int[] a1 = {3, 5,8}; - int[] a2 = {4, 5, 6,7}; - int[] arrays = ArrayUtil.merge(a1, a2); - for (int i : arrays) - System.out.print(i + " "); - - System.out.print("\ngrow测试:"); - - int[] growArray = ArrayUtil.grow(a1, 5); - for (int i : growArray) - System.out.print(i + " "); - - System.out.print("\nfibonacci测试"); - int[] fArray = ArrayUtil.fibonacci(1); - System.out.print(fArray); - System.out.println(); - fArray = ArrayUtil.fibonacci(15); - for (int i : fArray) - System.out.print(i + " "); - System.out.print("\ngetPrimes测试:"); - int[] primesArray = ArrayUtil.getPrimes(23); - for (int i : primesArray) - System.out.print(i + " "); - System.out.print("\ngetPerfectNumbers测试:"); - int[] pArray = ArrayUtil.getPerfectNumbers(100); - for (int i : pArray) - System.out.print(i + " "); - System.out.print("\njoin测试:"); - int[] jArray = new int[]{2, 3, 8}; - System.out.print(ArrayUtil.join(jArray, "-")); - Map map = new HashMap<>(); - Struts.runAction("login", map); - } } diff --git a/group11/1178243325/DataStructure/src/main/java/com/coderising/litestruts/.Struts.java.swp b/group11/1178243325/DataStructure/src/main/java/com/coding/basic/.LinkedList.java.swp similarity index 57% rename from group11/1178243325/DataStructure/src/main/java/com/coderising/litestruts/.Struts.java.swp rename to group11/1178243325/DataStructure/src/main/java/com/coding/basic/.LinkedList.java.swp index 1f45a5f25e9bf8dcf03addb1f9a3a0a4c6fe0a2f..7ea2e295d458709c233e753f5a1bc442a43cead0 100644 GIT binary patch literal 16384 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 R{)L12RT~^;Qn}7={2RR2tVI9- literal 12288 zcmeHN-)|H}93MFDF=6Z>+URINc933 z+R}=_wrHyrG^inRZ8c&`TX<3b27eI~>Fym52A@oP($DP7^{!2+z7l4W&+gvN_t$*B z-|tMCPFMZDwsyMRXd<{a5mM8((7EAtyl*4KcfGX3_`urN|CM`F2qq7jhs~sw>$dqV z?esL%r?w}1yjQpr?m`;LaD#>R$i$rnv#?qObFvB0yFzGo$~X4)yMXJZpy+J}W? zCe3UgqRdZn4dxr%$=YG7QN_T$!$83HKeJ;aX>3T<^GQFcZ=suOI_{nMtC=bW6a$I@ z#eiZ!F`yVw3@8Q^1BAKj$XnpyKFLL^e6CyZlt0x&F`yVw3@8Q^1BwB~fMP%~pcqgL zCu#1&`UHzarN>W;Wy2*agffTPLRnoi!azRF@QUyHO)5S1Alv%X&u_@ znU3Yn>?Jhk8n|qzZkyFUNb#2Yct#P6E1)C zV@pfJFZ*udpzn5g8S#A|)F{`bJE?;^|1F$rIL?OyepE4KRg@i5+ z{uxKJ8NH607LV{1c(0?L?FShqT!=6XH(&`pYx}<0V?$cL36XZwZ4vJ3sCc$gp(exH zW%>tJ5#o{Z$;(isP3R=Vms-TyE?gRE=Wy<~v(1A|=q|$M za(b;G7OFfU|E1ujRSc>SV&2Nb3Ha$CVRRiRQmW1hSA;j6t_t{HRLb?rh(E z$J&qWFz*etDH=S!wkC;u;|(7TUkm%Dc%Oxnv!&?^#j%rUvGDS_sPN6=%;lT;;}B{x zXmoxy8Y=kWOf5PLV-Te+qTpKTt+$7Y3x&GHxr^bM0a-B+C|w^8$0x%4{O$QcN{bf? zVPPzM@6zH-esSg!9L1mEVf9Gjri<$d^htrKuCe;V-y;G%x@M z;n~4(dLqhy9xi+m^}Q=R$VR1gbn)8h@U!Fe*iz3wOQ~M`U@lx3fpj?VvEBp;uZ~7dXWg8~C_lJvWK5^W@a+8=REZ%Lx8`L60p9~< gnXfW}7_cX~*vPTZQ7e}<_<4JASl*}{mTxBi0@A~$y#N3J diff --git a/group11/1178243325/DataStructure/src/main/java/com/coding/basic/LinkedList.java b/group11/1178243325/DataStructure/src/main/java/com/coding/basic/LinkedList.java index d82349089b..5717f2226d 100644 --- a/group11/1178243325/DataStructure/src/main/java/com/coding/basic/LinkedList.java +++ b/group11/1178243325/DataStructure/src/main/java/com/coding/basic/LinkedList.java @@ -60,7 +60,6 @@ public int size(){ } public void addFirst(Object o){ - //就是这么硬! add(0, o); } @@ -132,4 +131,159 @@ Object getNext() { return next; } } + + + /** + * 把该链表逆置 + * 例如链表为 3->7->10 , 逆置后变为 10->7->3 + */ + public void reverse(){ + Object[] oldData = new Object[size]; + Node temp = head; + int index = 1; + while(temp.next != null) { + temp = temp.next; + oldData[size - index] = temp.data; + index++; + } + + index = 0; + temp = head; + while(temp.next != null) { + temp = temp.next; + temp.data = oldData[index]; + index++; + } + } + + /** + * 删除一个单链表的前半部分 + * 例如:list = 2->5->7->8 , 删除以后的值为 7->8 + * 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10 + */ + + public void removeFirstHalf(){ + int count = size; + if (count % 2 != 0) { + for (int i = 0; i <= count/2; i++) { + removeFirst(); + } + } else { + for (int i = 0; i < count/2; i++) { + removeFirst(); + } + } + } + + /** + * 从第i个元素开始, 删除length 个元素 , 注意i从0开始 + * @param i + * @param length + */ + + public void remove(int i, int length){ + if (i < 0 || length < 0) { + return; + } + if (i == 0) { + for (int k = 0; k < length; k++) + removeFirst(); + } else { + while (length > 0) { + remove(i-1); + length--; + } + } + } + + /** + * 假定当前链表和list均包含已升序排列的整数 + * 从当前链表中取出那些list所指定的元素 + * 例如当前链表 = 11->101->201->301->401->501->601->701 + * listB = 1->3->4->6 + * 返回的结果应该是[101,301,401,601] + * @param list + */ + + public static int[] getElements(LinkedList list){ + + return null; + + } + + + + /** + + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + + * 从当前链表中中删除在list中出现的元素 + + + + * @param list + + */ + + + + public void subtract(LinkedList list){ + + + + } + + + + /** + + * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 + + * 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) + + */ + + public void removeDuplicateValues(){ + + + + } + + + + /** + + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + + * 试写一高效的算法,删除表中所有值大于min且小于max的元素(若表中存在这样的元素) + + * @param min + + * @param max + + */ + + public void removeRange(int min, int max){ + + + + } + + + + /** + + * 假设当前链表和参数list指定的链表均以元素依值递增有序排列(同一表中的元素值各不相同) + + * 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列 + + * @param list + + */ + + public LinkedList intersection( LinkedList list){ + + return null; + + } } From e01ba89120b5c5b347b17d3989d76a3c333c4811 Mon Sep 17 00:00:00 2001 From: Samson Shenglu Cao Date: Sun, 12 Mar 2017 01:41:21 +0800 Subject: [PATCH 003/203] add unit test --- .../src/com/coderising/array/ArrayUtil.java | 128 ++++++++++++------ .../com/coderising/array/ArrayUtilTest.java | 120 ++++++++++++++++ .../src/com/coderising/array/Main.java | 20 +++ 3 files changed, 224 insertions(+), 44 deletions(-) create mode 100644 group19/972815123/src/com/coderising/array/ArrayUtilTest.java create mode 100644 group19/972815123/src/com/coderising/array/Main.java diff --git a/group19/972815123/src/com/coderising/array/ArrayUtil.java b/group19/972815123/src/com/coderising/array/ArrayUtil.java index fca1de56e4..b24534a1f6 100644 --- a/group19/972815123/src/com/coderising/array/ArrayUtil.java +++ b/group19/972815123/src/com/coderising/array/ArrayUtil.java @@ -16,10 +16,10 @@ public void reverseArray(int[] origin){ int tem = 0; for(int i = 0, len = origin.length; i < len/2; i ++){ tem = origin[i]; - origin[i] = origin[len - i + 1]; - origin[len - i + 1] = tem; + origin[i] = origin[len - i - 1]; + origin[len - i - 1] = tem; } - + System.out.println(join(origin, ",")); } /** @@ -33,12 +33,12 @@ public void reverseArray(int[] origin){ public int[] removeZero(int[] oldArray){ int withoutZeroSize = 0; for(int i = 0, len = oldArray.length; i < len; i ++ ){ - if( oldArray[i] == 0){ + if( oldArray[i] != 0){ withoutZeroSize ++; } } int[] newArray = new int[withoutZeroSize]; - int point = 1; + int point = 0; for(int i = 0 ,len = oldArray.length; i < len; i ++ ){ if( oldArray[i] != 0){ newArray[point] = oldArray[i]; @@ -57,19 +57,39 @@ public int[] removeZero(int[] oldArray){ */ public int[] merge(int[] array1, int[] array2){ - int point2 = 0; - int[] result = new int[array1.length + array2.length]; - int point1 = 0, len1 = array1.length; - while(point1 < len1){ - if(array1[point1] < array2[point2]){ - result[point1 + point2] = array1[point1]; - point1 ++; + int point = 0; + int point2 = 0, point1 = 0; + int len1 = array1.length, len2 = array2.length; + + int[] result = new int[len1 + len2]; + while(point1 < len1 || point2 < len2){ + if(point1 < len1 && point2 < len2){ + if(array1[point1] <= array2[point2]){ + result[point] = array1[point1]; + point++; + point1++; + }else{ + if(result[point - 1] == array2[point2]){ + point2++; + }else{ + result[point] = array2[point2]; + point++; + point2++; + } + } }else{ - result[point1 + point2] = array2[point2]; - point2 ++; + if(point1 < len1){ + result[point] = array1[point1]; + point++; + point1++; + }else{ + result[point] = array2[point2]; + point++; + point2++; + } } } - + result = removeZero(result); return result; } /** @@ -97,24 +117,26 @@ public int[] grow(int [] oldArray, int size){ * @return */ public int[] fibonacci(int max){ - int[] result = {1,1,2}; - int a1 = 1, a2 = 2; + int[] result = {1,1}; if(max <= 1){ return null; }else if(max == 2){ return result; }else{ result = grow(result, 10); - int index = 2; - while(result[index] > max){ - if(result.length < index + 2){ + int index = 1; + while(true){ + index ++; + if(result.length < index + 1){ result = grow(result, 10); } - result[index + 1] = result[index -1] + result[index]; - index ++; + result[index] = result[index -1] + result[index - 2]; + if(result[index] > max){ + break; + } } } - return result; + return removeZero(result); } /** @@ -124,32 +146,36 @@ public int[] fibonacci(int max){ * @return */ public int[] getPrimes(int max){ - int[] temArr = null; + int[] temArr = {2}; if(max < 2){ return null; }else if (max == 2){ - int[] re = {2}; - return re; + return temArr; }else{ - temArr = new int[max/2]; - temArr[0] = 2; - int index = 1; - for(int i = 3; i < max ; i= i+2){ + temArr = grow(temArr, 10); + int index = 0; + for(int i = 3;i < max; i ++){ boolean flag = true; - int isql = (int) Math.sqrt(i); - for(int j = 3; j < isql; j++){ - if(i % j == 0){ + int iSqrt = (int) Math.sqrt(i); + for(int j = 0; j < index + 1; j ++){ + if(iSqrt < temArr[j]){ + break; + } + if(i % temArr[j] == 0){ flag = false; + break; } } if(flag){ - temArr[index] = i; index ++; + if(temArr.length < index + 1){ + temArr = grow(temArr, 30); + } + temArr[index] = i; } } } - temArr = this.removeZero(temArr); - return temArr; + return removeZero(temArr); } /** @@ -163,17 +189,17 @@ public int[] getPerfectNumbers(int max){ int index = 0; if(max < 6){ return null; - }else{ - } + } + for (int n = 6; n <= max ; n ++){ - int[] allPrimeFactore = getPrimeFactors(n); + int[] allFactors = getAllFactors(n); int sum = 0; - for(int i = 0, len = allPrimeFactore.length; i < len; i ++){ - sum += allPrimeFactore[i]; + for(int i = 0, len = allFactors.length; i < len; i ++){ + sum += allFactors[i]; } if(sum == n){ if(result.length < index + 1){ - result = this.grow(result, 1); + result = this.grow(result, 3); } result[index] = n; index ++; @@ -183,10 +209,24 @@ public int[] getPerfectNumbers(int max){ return removeZero(result); } - private int[] getPrimeFactors(int n){ + public int[] getAllFactors(int n){ + int[] result = new int[n]; + int index = 0; + for(int i = 1; i < n; i++){ + if(n % i == 0){ + result[index] = i; + index ++; + } + } + return removeZero(result); + } + + //分解因式算法 + public int[] getPrimeFactors(int n){ int[] allPrimes = getPrimes(n); int[] result = new int[allPrimes.length]; - int index = 0; + int index = 1; + result[0] = 1; for(int i = 0, len = allPrimes.length; i < len; i ++){ int devide = n; while(devide % allPrimes[i] == 0){ diff --git a/group19/972815123/src/com/coderising/array/ArrayUtilTest.java b/group19/972815123/src/com/coderising/array/ArrayUtilTest.java new file mode 100644 index 0000000000..2fbd5ead5e --- /dev/null +++ b/group19/972815123/src/com/coderising/array/ArrayUtilTest.java @@ -0,0 +1,120 @@ +package com.coderising.array; + +import static org.junit.Assert.*; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import junit.framework.Assert; + +public class ArrayUtilTest { + + private ArrayUtil au; + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + au = new ArrayUtil(); + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testReverseArray() { + int[] test = {1,2,3}; + au.reverseArray(test); + String result = au.join(test, "-"); + Assert.assertEquals(result, "3-2-1"); + } + + @Test + public void testRemoveZero() { + int[] test = {1,3,4,5,0,0,6,6,0,5,4,7,6,7,0,5}; + test = au.removeZero(test); + String result = au.join(test, ","); + Assert.assertEquals(result, "1,3,4,5,6,6,5,4,7,6,7,5"); + } + + @Test + public void testMerge() { + int[] arr1 = {3, 5, 7,8}; + int[] arr2 = {4, 5, 6,7}; + int[] test = au.merge(arr1, arr2); + String result = au.join(test, ","); + System.out.println(result); + Assert.assertEquals(result, "3,4,5,6,7,8"); + } + + @Test + public void testGrow() { + int[] test = {3,5,6}; + test = au.grow(test, 2); + String result = au.join(test, ","); + System.out.println(result); + System.out.println(test.length); + Assert.assertTrue(5 == test.length); + } + + @Test + public void testFibonacci() { + int[] test = au.fibonacci(250); + String result = au.join(test, ","); + System.out.println(result); + Assert.assertEquals(result, "1,1,2,3,5,8,13,21,34,55,89,144,233,377"); + } + + @Test + public void testGetPrimes() { + //2,3,5,7,11,13,17,19 + int[] test = au.getPrimes(23); + String result = au.join(test, ","); + System.out.println(result); + Assert.assertEquals(result, "2,3,5,7,11,13,17,19"); + } + + @Test + public void testGetPerfectNumbers() { + int[] test = au.getPerfectNumbers(10000); + String result = au.join(test, ","); + System.out.println(result); + Assert.assertEquals(result, "6,28,496,8128"); + } + + + @Test + public void testGetAllFactors(){ + int[] test = au.getAllFactors(98); + String result = au.join(test, ","); + System.out.println(result); + Assert.fail(); + } + + @Test + public void testGetPrimeFactors(){ + int[] test = au.getPrimeFactors(98); + String result = au.join(test, ","); + System.out.println(result); + Assert.fail(); + } + + @Test + public void testJoin() { + int[] test = {1,2,3}; + String result = au.join(test, ","); + + Assert.assertEquals(result, "1,2,3"); + } + +} diff --git a/group19/972815123/src/com/coderising/array/Main.java b/group19/972815123/src/com/coderising/array/Main.java new file mode 100644 index 0000000000..5c8a9abcc6 --- /dev/null +++ b/group19/972815123/src/com/coderising/array/Main.java @@ -0,0 +1,20 @@ +package com.coderising.array; + +public class Main { + + public static void main(String[] args) { + ArrayUtil au = new ArrayUtil(); +// int[] test = {1,2}; +// au.reverseArray(test); +// String result = au.join(test, "-"); + + + int[] arr1 = {3, 5, 7,8}; + int[] arr2 = {4, 5, 6,7}; + int[] test = au.merge(arr1, arr2); + String result = au.join(test, ","); + + System.out.println(result); + } + +} From 9c0f02067559c9d9938a0a860d267cec66c20f26 Mon Sep 17 00:00:00 2001 From: northSmall <604322962@qq.com> Date: Wed, 15 Mar 2017 23:47:03 +0800 Subject: [PATCH 004/203] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E5=A4=9A=E7=BA=BF?= =?UTF-8?q?=E7=A8=8B=E4=B8=8B=E8=BD=BD=E4=BD=9C=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group19/604322962/learning2017/pom.xml | 33 ++++++ .../main/java/com/coding/basic/ArrayList.java | 2 +- .../java/com/coding/basic/BinaryTreeNode.java | 2 +- .../main/java/com/coding/basic/Iterator.java | 2 +- .../java/com/coding/basic/LinkedList.java | 2 +- .../src/main/java/com/coding/basic/List.java | 2 +- .../src/main/java/com/coding/basic/Queue.java | 2 +- .../src/main/java/com/coding/basic/Stack.java | 2 +- .../com/coding/download/DownloadThread.java | 56 +++++++++ .../com/coding/download/FileDownloader.java | 110 ++++++++++++++++++ .../coding/download/FileDownloaderTest.java | 61 ++++++++++ .../com/coding/download/api/Connection.java | 23 ++++ .../download/api/ConnectionException.java | 5 + .../download/api/ConnectionManager.java | 10 ++ .../coding/download/api/DownloadListener.java | 5 + .../coding/download/impl/ConnectionImpl.java | 61 ++++++++++ .../download/impl/ConnectionManagerImpl.java | 26 +++++ 17 files changed, 397 insertions(+), 7 deletions(-) create mode 100644 group19/604322962/learning2017/pom.xml create mode 100644 group19/604322962/learning2017/src/main/java/com/coding/download/DownloadThread.java create mode 100644 group19/604322962/learning2017/src/main/java/com/coding/download/FileDownloader.java create mode 100644 group19/604322962/learning2017/src/main/java/com/coding/download/FileDownloaderTest.java create mode 100644 group19/604322962/learning2017/src/main/java/com/coding/download/api/Connection.java create mode 100644 group19/604322962/learning2017/src/main/java/com/coding/download/api/ConnectionException.java create mode 100644 group19/604322962/learning2017/src/main/java/com/coding/download/api/ConnectionManager.java create mode 100644 group19/604322962/learning2017/src/main/java/com/coding/download/api/DownloadListener.java create mode 100644 group19/604322962/learning2017/src/main/java/com/coding/download/impl/ConnectionImpl.java create mode 100644 group19/604322962/learning2017/src/main/java/com/coding/download/impl/ConnectionManagerImpl.java diff --git a/group19/604322962/learning2017/pom.xml b/group19/604322962/learning2017/pom.xml new file mode 100644 index 0000000000..92292887f8 --- /dev/null +++ b/group19/604322962/learning2017/pom.xml @@ -0,0 +1,33 @@ + + + 4.0.0 + + com.north + learning2017 + 1.0-SNAPSHOT + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.6 + 1.6 + + + + + + + + + dom4j + dom4j + 1.6.1 + + + + + \ No newline at end of file diff --git a/group19/604322962/learning2017/src/main/java/com/coding/basic/ArrayList.java b/group19/604322962/learning2017/src/main/java/com/coding/basic/ArrayList.java index 3f2fa618c5..85c1826bf6 100644 --- a/group19/604322962/learning2017/src/main/java/com/coding/basic/ArrayList.java +++ b/group19/604322962/learning2017/src/main/java/com/coding/basic/ArrayList.java @@ -1,4 +1,4 @@ -package main.java.com.coding.basic; +package com.coding.basic; import java.util.Arrays; diff --git a/group19/604322962/learning2017/src/main/java/com/coding/basic/BinaryTreeNode.java b/group19/604322962/learning2017/src/main/java/com/coding/basic/BinaryTreeNode.java index 2701270b5d..d7ac820192 100644 --- a/group19/604322962/learning2017/src/main/java/com/coding/basic/BinaryTreeNode.java +++ b/group19/604322962/learning2017/src/main/java/com/coding/basic/BinaryTreeNode.java @@ -1,4 +1,4 @@ -package main.java.com.coding.basic; +package com.coding.basic; public class BinaryTreeNode { diff --git a/group19/604322962/learning2017/src/main/java/com/coding/basic/Iterator.java b/group19/604322962/learning2017/src/main/java/com/coding/basic/Iterator.java index 86643482fb..06ef6311b2 100644 --- a/group19/604322962/learning2017/src/main/java/com/coding/basic/Iterator.java +++ b/group19/604322962/learning2017/src/main/java/com/coding/basic/Iterator.java @@ -1,4 +1,4 @@ -package main.java.com.coding.basic; +package com.coding.basic; public interface Iterator { public boolean hasNext(); diff --git a/group19/604322962/learning2017/src/main/java/com/coding/basic/LinkedList.java b/group19/604322962/learning2017/src/main/java/com/coding/basic/LinkedList.java index 1d8b56ede4..a6449c8b68 100644 --- a/group19/604322962/learning2017/src/main/java/com/coding/basic/LinkedList.java +++ b/group19/604322962/learning2017/src/main/java/com/coding/basic/LinkedList.java @@ -1,4 +1,4 @@ -package main.java.com.coding.basic; +package com.coding.basic; import java.util.NoSuchElementException; diff --git a/group19/604322962/learning2017/src/main/java/com/coding/basic/List.java b/group19/604322962/learning2017/src/main/java/com/coding/basic/List.java index ce830df7b8..10d13b5832 100644 --- a/group19/604322962/learning2017/src/main/java/com/coding/basic/List.java +++ b/group19/604322962/learning2017/src/main/java/com/coding/basic/List.java @@ -1,4 +1,4 @@ -package main.java.com.coding.basic; +package com.coding.basic; public interface List { public void add(Object o); diff --git a/group19/604322962/learning2017/src/main/java/com/coding/basic/Queue.java b/group19/604322962/learning2017/src/main/java/com/coding/basic/Queue.java index 744fbb2f10..4a189c64ad 100644 --- a/group19/604322962/learning2017/src/main/java/com/coding/basic/Queue.java +++ b/group19/604322962/learning2017/src/main/java/com/coding/basic/Queue.java @@ -1,4 +1,4 @@ -package main.java.com.coding.basic; +package com.coding.basic; import org.junit.Test; diff --git a/group19/604322962/learning2017/src/main/java/com/coding/basic/Stack.java b/group19/604322962/learning2017/src/main/java/com/coding/basic/Stack.java index 98e9fd701a..67ded99344 100644 --- a/group19/604322962/learning2017/src/main/java/com/coding/basic/Stack.java +++ b/group19/604322962/learning2017/src/main/java/com/coding/basic/Stack.java @@ -1,4 +1,4 @@ -package main.java.com.coding.basic; +package com.coding.basic; import org.junit.Test; diff --git a/group19/604322962/learning2017/src/main/java/com/coding/download/DownloadThread.java b/group19/604322962/learning2017/src/main/java/com/coding/download/DownloadThread.java new file mode 100644 index 0000000000..553fc51398 --- /dev/null +++ b/group19/604322962/learning2017/src/main/java/com/coding/download/DownloadThread.java @@ -0,0 +1,56 @@ +package com.coding.download; + +import com.coding.download.api.Connection; +import com.coding.download.api.ConnectionException; +import com.coding.download.impl.ConnectionManagerImpl; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.concurrent.CountDownLatch; + +public class DownloadThread extends Thread{ + + Connection conn; + int startPos; + int endPos; + String filelocal; + CountDownLatch cdl; + public DownloadThread(Connection conn, int startPos, int endPos, String filelocal, CountDownLatch cdl){ + + this.conn = conn; + this.startPos = startPos; + this.endPos = endPos; + this.filelocal = filelocal; + this.cdl = cdl; + } + public void run(){ + /*try { + RandomAccessFile fos = new RandomAccessFile("C:\\Users\\gaokun\\Desktop\\test3.jpg", "rwd"); + byte[] read = conn.read(startPos, endPos); + fos.seek(startPos); + fos.setLength(endPos-startPos); + fos.write(read); + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + }*/ + RandomAccessFile raf = null; + try { + String url = "http://www.dabaoku.com/sucaidatu/dongwu/chongwujingling/804838.JPG"; + byte[] buf = conn.read(startPos, endPos); + raf = new RandomAccessFile(filelocal, "rwd"); + raf.seek(startPos); + raf.write(buf); + raf.close(); + cdl.countDown(); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } +} diff --git a/group19/604322962/learning2017/src/main/java/com/coding/download/FileDownloader.java b/group19/604322962/learning2017/src/main/java/com/coding/download/FileDownloader.java new file mode 100644 index 0000000000..a78c749f5c --- /dev/null +++ b/group19/604322962/learning2017/src/main/java/com/coding/download/FileDownloader.java @@ -0,0 +1,110 @@ +package com.coding.download; + +import com.coding.download.api.Connection; +import com.coding.download.api.ConnectionException; +import com.coding.download.api.ConnectionManager; +import com.coding.download.api.DownloadListener; + +import java.io.File; +import java.util.concurrent.CountDownLatch; + + +public class FileDownloader { + + String url; + + DownloadListener listener; + + ConnectionManager cm; + + + public FileDownloader(String _url) { + this.url = _url; + + } + + public void execute() throws InterruptedException, ConnectionException { + // 在这里实现你的代码, 注意: 需要用多线程实现下载 + // 这个类依赖于其他几个接口, 你需要写这几个接口的实现代码 + // (1) ConnectionManager , 可以打开一个连接,通过Connection可以读取其中的一段(用startPos, endPos来指定) + // (2) DownloadListener, 由于是多线程下载, 调用这个类的客户端不知道什么时候结束,所以你需要实现当所有 + // 线程都执行完以后, 调用listener的notifiedFinished方法, 这样客户端就能收到通知。 + // 具体的实现思路: + // 1. 需要调用ConnectionManager的open方法打开连接, 然后通过Connection.getContentLength方法获得文件的长度 + // 2. 至少启动3个线程下载, 注意每个线程需要先调用ConnectionManager的open方法 + // 然后调用read方法, read方法中有读取文件的开始位置和结束位置的参数, 返回值是byte[]数组 + // 3. 把byte数组写入到文件中 + // 4. 所有的线程都下载完成以后, 需要调用listener的notifiedFinished方法 + + // 下面的代码是示例代码, 也就是说只有一个线程, 你需要改造成多线程的。 + /*Connection conn = null; + try { + + conn = cm.open(this.url); + + int length = conn.getContentLength(); + + new DownloadThread(conn,0,length-1).start(); + + } catch (ConnectionException e) { + e.printStackTrace(); + }finally{ + if(conn != null){ + conn.close(); + } + }*/ + //Connection conn = null; + /*try { + int threadCount = 3; + Connection conn = cm.open(this.url); + int length = conn.getContentLength(); + int blockSize = length / threadCount; + for (int threadId = 1; threadId <= threadCount; threadId++) { + //第一个线程下载的开始位置 + int startIndex = (threadId - 1) * blockSize; + int endIndex = threadId * blockSize - 1; + if (threadId == threadCount) {//最后一个线程下载的长度要稍微长一点 + endIndex = length; + } + System.out.println("线程:"+threadId+"下载:---"+startIndex+"--->"+endIndex); + new DownloadThread(conn, startIndex, endIndex).start(); + } + } catch (ConnectionException e) { + e.printStackTrace(); + }*/ + + int threadCount = 3; + int startPos; + int endPos; + String filelocaltion = "C:\\Users\\gaokun\\Desktop\\demo.jpg"; + CountDownLatch cdl = new CountDownLatch(3); + for (int i = 0; i < threadCount; i++) { + Connection conn = cm.open(url); + int fileLength = conn.getContentLength(); + startPos = i*fileLength/threadCount; + endPos = (i+1)*fileLength/threadCount-1; + if (i == threadCount-1) + endPos = fileLength-1; + new DownloadThread(conn, startPos, endPos, filelocaltion, cdl).start(); + } + cdl.await(); + System.out.println("线程跑完了!"); + listener.notifyFinished(); + + } + + public void setListener(DownloadListener listener) { + this.listener = listener; + } + + + + public void setConnectionManager(ConnectionManager ucm){ + this.cm = ucm; + } + + public DownloadListener getListener(){ + return this.listener; + } + +} diff --git a/group19/604322962/learning2017/src/main/java/com/coding/download/FileDownloaderTest.java b/group19/604322962/learning2017/src/main/java/com/coding/download/FileDownloaderTest.java new file mode 100644 index 0000000000..10e70736f7 --- /dev/null +++ b/group19/604322962/learning2017/src/main/java/com/coding/download/FileDownloaderTest.java @@ -0,0 +1,61 @@ +package com.coding.download; + +import com.coding.download.api.ConnectionException; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import com.coding.download.api.ConnectionManager; +import com.coding.download.api.DownloadListener; +import com.coding.download.impl.ConnectionManagerImpl; + +public class FileDownloaderTest { + boolean downloadFinished = false; + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testDownload() throws ConnectionException, InterruptedException, ConnectionException { + + String url = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1489601005973&di=e104648a3c8dcaabb18dfb5d98870d84&imgtype=0&src=http%3A%2F%2Fimgsrc.baidu.com%2Fbaike%2Fpic%2Fitem%2F3b292df5e0fe992536be579530a85edf8cb17140.jpg"; + + FileDownloader downloader = new FileDownloader(url); + + ConnectionManager cm = new ConnectionManagerImpl(); + downloader.setConnectionManager(cm); + + downloader.setListener(new DownloadListener() { + @Override + public void notifyFinished() { + downloadFinished = true; + } + + }); + + + downloader.execute(); + + // 等待多线程下载程序执行完毕 + while (!downloadFinished) { + try { + System.out.println("还没有下载完成,休眠五秒"); + //休眠5秒 + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + System.out.println("下载完成!"); + + + + } + + void testRead(){ + + } +} diff --git a/group19/604322962/learning2017/src/main/java/com/coding/download/api/Connection.java b/group19/604322962/learning2017/src/main/java/com/coding/download/api/Connection.java new file mode 100644 index 0000000000..65f3dae9c5 --- /dev/null +++ b/group19/604322962/learning2017/src/main/java/com/coding/download/api/Connection.java @@ -0,0 +1,23 @@ +package com.coding.download.api; + +import java.io.IOException; + +public interface Connection { + /** + * 给定开始和结束位置, 读取数据, 返回值是字节数组 + * @param startPos 开始位置, 从0开始 + * @param endPos 结束位置 + * @return + */ + public byte[] read(int startPos,int endPos) throws IOException; + /** + * 得到数据内容的长度 + * @return + */ + public int getContentLength(); + + /** + * 关闭连接 + */ + public void close(); +} diff --git a/group19/604322962/learning2017/src/main/java/com/coding/download/api/ConnectionException.java b/group19/604322962/learning2017/src/main/java/com/coding/download/api/ConnectionException.java new file mode 100644 index 0000000000..1db8b093ec --- /dev/null +++ b/group19/604322962/learning2017/src/main/java/com/coding/download/api/ConnectionException.java @@ -0,0 +1,5 @@ +package com.coding.download.api; + +public class ConnectionException extends Exception { + +} diff --git a/group19/604322962/learning2017/src/main/java/com/coding/download/api/ConnectionManager.java b/group19/604322962/learning2017/src/main/java/com/coding/download/api/ConnectionManager.java new file mode 100644 index 0000000000..1d1a83caf2 --- /dev/null +++ b/group19/604322962/learning2017/src/main/java/com/coding/download/api/ConnectionManager.java @@ -0,0 +1,10 @@ +package com.coding.download.api; + +public interface ConnectionManager { + /** + * 给定一个url , 打开一个连接 + * @param url + * @return + */ + public Connection open(String url) throws ConnectionException; +} diff --git a/group19/604322962/learning2017/src/main/java/com/coding/download/api/DownloadListener.java b/group19/604322962/learning2017/src/main/java/com/coding/download/api/DownloadListener.java new file mode 100644 index 0000000000..c41045b0e8 --- /dev/null +++ b/group19/604322962/learning2017/src/main/java/com/coding/download/api/DownloadListener.java @@ -0,0 +1,5 @@ +package com.coding.download.api; + +public interface DownloadListener { + public void notifyFinished(); +} diff --git a/group19/604322962/learning2017/src/main/java/com/coding/download/impl/ConnectionImpl.java b/group19/604322962/learning2017/src/main/java/com/coding/download/impl/ConnectionImpl.java new file mode 100644 index 0000000000..85507313ad --- /dev/null +++ b/group19/604322962/learning2017/src/main/java/com/coding/download/impl/ConnectionImpl.java @@ -0,0 +1,61 @@ +package com.coding.download.impl; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; + +import com.coding.download.api.Connection; + +public class ConnectionImpl implements Connection{ + + private URLConnection urlConnection; + + public ConnectionImpl(URLConnection urlConnection) { + this.urlConnection = urlConnection; + } + + @Override + public byte[] read(int startPos, int endPos) throws IOException { + int readBytes = 0; + /*int len = endPos-startPos+1; + byte[] buffer = new byte[1024]; + urlConnection.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos); + InputStream is = urlConnection.getInputStream();//已经设置了请求的位置,返回的是当前位置对应的文件的输入流 + while (readBytes Date: Thu, 16 Mar 2017 14:42:15 +0800 Subject: [PATCH 005/203] xuweijay --- group15/1511_714512544/.idea/workspace.xml | 375 +++++++++++------- .../com/coding/basic/BinarySearchTree.class | Bin 5976 -> 6893 bytes .../coding/basic/BinarySearchTreeTest.class | Bin 3057 -> 2764 bytes .../com/coding/basic/BinarySearchTree.java | 42 +- .../src/com/coding/basic/ReConstructBST.java | 84 ++++ .../com/coding/basic/ReConstructBSTTest.java | 31 ++ .../coding/basic/BinarySearchTreeTest.java | 87 ++-- 7 files changed, 407 insertions(+), 212 deletions(-) create mode 100644 group15/1511_714512544/src/com/coding/basic/ReConstructBST.java create mode 100644 group15/1511_714512544/src/com/coding/basic/ReConstructBSTTest.java diff --git a/group15/1511_714512544/.idea/workspace.xml b/group15/1511_714512544/.idea/workspace.xml index 79ca1863c1..aff22b6c62 100644 --- a/group15/1511_714512544/.idea/workspace.xml +++ b/group15/1511_714512544/.idea/workspace.xml @@ -1,7 +1,15 @@ - + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -59,6 +94,11 @@ @@ -89,6 +129,8 @@ + + @@ -115,6 +157,10 @@ - - @@ -256,21 +304,31 @@ + - - + + + + + + + + + + + - - + - - + + - - + - + - - + - - @@ -779,19 +837,19 @@ - - - - - + + + + + - - - - - + + + + + @@ -822,6 +880,9 @@ + + + 1488937445293 @@ -869,17 +930,14 @@ - - + + - - - - - + + - - + + @@ -899,9 +957,12 @@ + + + - @@ -931,9 +992,9 @@ - + - + @@ -994,48 +1055,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1145,10 +1164,6 @@ - - - - @@ -1166,20 +1181,6 @@ - - - - - - - - - - - - - - @@ -1299,7 +1300,6 @@ - @@ -1307,10 +1307,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1319,65 +1344,115 @@ - + - - + + - - + + - - - - - - - - - + + + - + - - + + - + - - + + + + + + + + + + - - + + + + + + + + + + + + + + + + - + - - + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/group15/1511_714512544/out/production/1511_714512544/com/coding/basic/BinarySearchTree.class b/group15/1511_714512544/out/production/1511_714512544/com/coding/basic/BinarySearchTree.class index 5998f970323aaecdfb18fe58822f1d6aafb4a5a8..05ab8c349bd7f12cc3ec76235550406ff6ff1351 100644 GIT binary patch literal 6893 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 literal 5976 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 diff --git a/group15/1511_714512544/out/production/1511_714512544/test/com/coding/basic/BinarySearchTreeTest.class b/group15/1511_714512544/out/production/1511_714512544/test/com/coding/basic/BinarySearchTreeTest.class index 167f83c32c1049dac46a7c44aca17da2265a896c..8fd0bf539b995515676b24f90377d0bcef0afb70 100644 GIT binary patch literal 2764 zcma)-`%>Fh5XL`&LBi1$L&_z^1c-@&6bv-Y4ZSm zoc__7mSozQK0qI;lU-Ss54JMEjF0x5v*&ldUG0kh{{Q=508^+YFp8&r7{Qk+W)kSe z(*$NQ$JTrT&+rvn3kl@0$kuZnmUvj^VTFemJQR3X<>4g{#U8@*UpF6JQ?agMLqT`h z^%UGG8un4nu=h=?k}K=3Y2@;zr8{r7gzgyCk|V^7g1#-YV(DJp5elZyKQUW8)KBzW zO($l-@eOMSGus$)ahA_4-j+I3>MYqm`keZRoWf-7$F{ zEXKU5=_+_o^n~k?;&W7&$cwJ*afP>itRS)Ut09g()3#g{uM~`L)-BIG5<8}A(j5zy zWqZ26?O*Rya)))&n#+p=+u;<%Jxa)P`xi^WV9^fu7Y;lMj`*yqV7bDfq^2Z?K!?Wr zi?-$IrbSWs(^rnzaQ20x;2Q5Xr@N+Cwd>xdFzSv=f&=e0b6@suPCLE(eVFZff&29{ z^G^Sy=jbQG(QElPMR6i(lz`*r=@sF<5N4%HLG@MxLn%&tzi>e8cNt!vBQ&H4d39kiaibA;yVrB;|C2t;wKF{lgn%w zZ0)lp*qUT(3I}|mq9DuRU#wo}&9w@5qkJd~ihH=V6xI;cKx;Lqa0Tj#UaO0Z0|g`L zLMEaID2ep;{StYWmi8CzqhsCSTA#_B-(Bm}HB@nug1l|lgieJrlHQZ=4c57Ojj;5_ zKXmgRg)bGh+YqYhzOnRkU9VB$-j`1|QZyq)60C4{s}S|^Ox9FQbN*`c_e$)%}{D`bB zTtz?G)FL!~Oe@p0#y*McTPRuOFLeFk``zF*+T$^XOSnmv*6<|uZJN=CoG9Hs<#&2A z#mN4H?$>V-BTn{Dbj9DH=M=rWZ1+fZN|h!t$xii36WJ-%M78AILmyo^K;n`VYKr6x z;t_`E|JN`IxQuOFp=KSCq#J?syL2u_fV>eL#ZqnGu z1btxqOmyNh{_!l~y8Qfn5O*U2*VNQF^dN*R1xX&IgsGg-ASaX=%2Z!VY2&@!q0sM2 z_|ZV^S^UEgKNnO&lF|G-MdB2f+OcWMct*k|Be4@9_6tgzLg|P%kXk$MAyiCAym%xp z7xJQI_P1jnlgvp88!huuh;5TO(9U~8GN&b8w9L;!UbM_)J9d_2&Pmv4nU6zko6J-@ zZ-HdyC0?}5$&eQ;nOYi}y^P_jzrDki7Jq<>8hA-9 eT%;ym^Y0jGoDB*gNp1c)IPkNT`-IMQVfsBFVkJQU literal 3057 zcmcJQYg5}s6o!w?MMf3D2`$AmB%vYT3&d?g0*NU%2M9r6VpB4q4ei=&jHoS9NzP1u zR=$v4rup3IkLvVYA<2rB4ln~Stj->t)xOWZN8+D<|M);eQ}kS+tCW^0qfm^}3T0_R zM3V~LrJRVqQRrK`C!+gem=ePSF+3E*v>0Z@@JOb|GUX-ep4AQAnUkm^mEMu4vtaIX ziTX6%;G4}xgRW>#5!hgrIqd&y4cK({5D&>U_%xvJT~-@b0tausIl)!dS9 zFzaoZGpl;AZE?PhDr~8U>NUgWmV<38Hpbi9sf)32;A0JMk9-|7r!Sw?4%r))t23xu zGaO#yR(=l8OqQC4qc`}DZtDPBGz`;Wj&2&@N@%84%N;gxKsislDzq0&!(qCpaHm@q zFIxNDlIXg)>rY?k&Vku%Y&_7b-q82M)&4YE-RnNgv>mT}_@jBWUMZVRtIAh& zVOR1~XMa~5flAk?U!svy4_u~MmA<1nmF8(drbRJXQmH^sWLj2fg;rI1N^2@Tqji-u z>Q`w)M4KWiifBu0lo7Je)*CqSmPy6RA+Mq}uC`L1ZxYFGSiQ-Muh9~zwe%;PMPI`o zx54I9q5B21al|aq!TI#*J+p~-0WA_zuw@uQ$^GpRG4h1hM-Ul;Ab zcq8cTK|hRE^&GW&IvK?6bu>Z=eCxzd58?Ae{TM&TEQhOvYggtyN$(KE=nIV9ZZb{- zh}Dw<`jQ4Q!^?ohF?aDhTw}_?q`km&ZK;9kOC zC?s^a62_oZY#ygxD8E8O)JLPBn8a)v1PhSy3^IhoffE^?#5mrnA^HkZue(n`8@ZWb zWNsiM;BMk7(X9aGZ|o{i_AU+uyxmz344{CHx9BpYV7EaiOM+*})jJBklQayv8=$)h zx?A)L&b0{l0>YgLp~yrDM*_mXJhRFdN0`kXQ_nFe?O1n!H3qD4NJ_!9G_W$j$^vTw zSd&!3f7ljQIlx+vV2Ml=>+1mPcMq$0fmp}%Sv%4_Al(Pj6y!Vr(nCN@<97x~kAUo>N!av0ege7g#?4>qlU{ z0@fa|egf9dz+wQbgs{%<)L4LZIZpMpBfSPv4M+z-(t&gcq+ftk2T}t_2AncONauHI K9N*X&rTzm);agz< diff --git a/group15/1511_714512544/src/com/coding/basic/BinarySearchTree.java b/group15/1511_714512544/src/com/coding/basic/BinarySearchTree.java index 7f30ecd124..ea91e0325a 100644 --- a/group15/1511_714512544/src/com/coding/basic/BinarySearchTree.java +++ b/group15/1511_714512544/src/com/coding/basic/BinarySearchTree.java @@ -1,9 +1,10 @@ package com.coding.basic; -import edu.princeton.cs.algs4.BinarySearch; - +import java.util.Queue; import java.util.Stack; +import java.util.LinkedList; + /** 二叉树 5 @@ -236,6 +237,27 @@ public void postOrderWithoutRecursion(){ } } + /** + * 层次遍历 + 1.先根结点入队列 + 2.从队列中取出一个元素 + 3.访问该元素的节点 + 4.若该元素所指节点的左右子节点非空,则将左右孩子节点分别按照指针顺序入栈 + */ + public void traveralByLevel(BinarySearchTreeNode n){ + if(n == null) return; + + Queue> queue = new LinkedList>(); + queue.offer(n); + + while(!queue.isEmpty()){ + BinarySearchTreeNode node = queue.poll(); + System.out.print(node.getData() + " "); + if(node.getLeft() != null) queue.offer(node.getLeft()); + if(node.getRight() != null) queue.offer(node.getRight()); + } + } + //删除某个节点n public void delete(BinarySearchTreeNode n){ BinarySearchTreeNode p = n.getParent(); //节点的父节点 @@ -313,6 +335,22 @@ public BinarySearchTreeNode findMax(BinarySearchTreeNode n){ return current; } + /* + 求树的高度(利用后序遍历) + */ + public int postOrderGetHeight(BinarySearchTreeNode n){ + int hL = 0, hR = 0, maxH = 0; + + if(n != null){ + hL = postOrderGetHeight(n.getLeft()); //求左子树深度 + hR = postOrderGetHeight(n.getRight()); //求右子树深度 + maxH = hL> hR? hL : hR ; //求左右子树深度最大的那个 + return (maxH+1);//返回数的深度 + } + return 0; //空树返回0 + } + + } diff --git a/group15/1511_714512544/src/com/coding/basic/ReConstructBST.java b/group15/1511_714512544/src/com/coding/basic/ReConstructBST.java new file mode 100644 index 0000000000..7918170e2d --- /dev/null +++ b/group15/1511_714512544/src/com/coding/basic/ReConstructBST.java @@ -0,0 +1,84 @@ +package com.coding.basic; + +/** + * 由两种遍历结果确定二叉树(其中一个结果必须是中序遍历的结果) + */ +public class ReConstructBST{ + /** + * 前序遍历与中序遍历序列重建二叉树 + * @param preOrder 前序结果 + * @param inOrder 中序结果 + * @return root元素 + */ + public static Node construct(int[] preOrder, int[] inOrder){ + if(preOrder == null || inOrder == null || preOrder.length<=0||inOrder.length<=0) return null; + + return reConstruct(preOrder, 0 ,preOrder.length-1, inOrder,0, inOrder.length-1); + } + + /** + * + * @param preOrder 前序序列 + * @param ps 前序序列开始索引 + * @param pe 前序序列结束索引 + * @param inOrder 中序序列 + * @param is 中序序列开始索引 + * @param ie 中序序列结束索引 + * @return 本次的根节点 + */ + private static Node reConstruct(int[] preOrder, int ps, int pe, int[] inOrder, int is, int ie){ + int rootValue = preOrder[ps]; + Node root = new Node(rootValue); + //只有一个元素 + if(ps == pe){ + if(is == ie && preOrder[ps] == inOrder[is]){ + return root; + } + throw new RuntimeException("输入错误!"); + } + + //不止有一个元素,在中序遍历中找到根节点的位置 + int rootIndexInOrder = is; + while(rootIndexInOrder <= ie && inOrder[rootIndexInOrder]!=rootValue) rootIndexInOrder++; + + int lCTLengthInOrder = rootIndexInOrder - is; + int lCTEndIndexPreOrder = ps + lCTLengthInOrder; + if(lCTLengthInOrder > 0){ + //左子树有元素,构建左子树 + root.left = reConstruct(preOrder, ps+1, lCTEndIndexPreOrder, inOrder, is, rootIndexInOrder-1); + } + if(lCTLengthInOrder < (pe-ps)){ + //有字数有元素,构建右子树 + root.right = reConstruct(preOrder, lCTEndIndexPreOrder+1, pe, inOrder, rootIndexInOrder+1, ie); + } + + return root; + } + + public static void printInPostOrder(Node n){ + if(n.left != null){ + printInPostOrder(n.left); + } + + if(n.right != null){ + printInPostOrder(n.right); + } + + System.out.print(n.data+" "); + } + + + //节点 + public static class Node{ + int data; + Node left; + Node right; + public Node(int data) { + this.data = data; + this.left = null; + this.right = null; + } + } +} + + diff --git a/group15/1511_714512544/src/com/coding/basic/ReConstructBSTTest.java b/group15/1511_714512544/src/com/coding/basic/ReConstructBSTTest.java new file mode 100644 index 0000000000..861be70968 --- /dev/null +++ b/group15/1511_714512544/src/com/coding/basic/ReConstructBSTTest.java @@ -0,0 +1,31 @@ +package com.coding.basic; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * 二叉树重建测试 + */ +public class ReConstructBSTTest { + @Before + public void setUp() throws Exception { + + } + + @After + public void tearDown() throws Exception { + + } + + @Test + public void construct() throws Exception { + int[] preOrder = {1,2,4,7,3,5,6,8}; + int[] inOrder = {4,7,2,1,5,3,8,6}; + ReConstructBST.Node n = ReConstructBST.construct(preOrder,inOrder); + ReConstructBST.printInPostOrder(n); + } + +} \ No newline at end of file diff --git a/group15/1511_714512544/src/test/com/coding/basic/BinarySearchTreeTest.java b/group15/1511_714512544/src/test/com/coding/basic/BinarySearchTreeTest.java index 3b7102e5cd..f82f485e02 100644 --- a/group15/1511_714512544/src/test/com/coding/basic/BinarySearchTreeTest.java +++ b/group15/1511_714512544/src/test/com/coding/basic/BinarySearchTreeTest.java @@ -3,13 +3,15 @@ import static org.junit.Assert.*; import com.coding.basic.BinarySearchTree; +import org.junit.After; +import org.junit.Before; import org.junit.Test; public class BinarySearchTreeTest { - - @Test - public void testInsert() { - BinarySearchTree bst = new BinarySearchTree(); + BinarySearchTree bst = null; + @Before + public void setUp() throws Exception { + bst = new BinarySearchTree(); bst.insert(5); bst.insert(2); bst.insert(7); @@ -19,95 +21,60 @@ public void testInsert() { bst.insert(8); } + @After + public void tearDown() throws Exception { + + } + + @Test + public void testInsert() { + } + @Test public void testContains() { - BinarySearchTree bst = new BinarySearchTree(); - bst.insert(5); - bst.insert(2); - bst.insert(7); - bst.insert(1); - bst.insert(6); - bst.insert(4); - bst.insert(8); assertEquals(true,bst.contains(8)); } @Test public void testPreOrder(){ - BinarySearchTree bst = new BinarySearchTree(); - bst.insert(5); - bst.insert(2); - bst.insert(7); - bst.insert(1); - bst.insert(6); - bst.insert(4); - bst.insert(8); bst.preOrder(bst.getRoot()); } @Test public void testPreOrderWithoutRecursion(){ - BinarySearchTree bst = new BinarySearchTree<>(); - bst.insert(5); - bst.insert(2); - bst.insert(7); - bst.insert(1); - bst.insert(6); - bst.insert(4); - bst.insert(8); bst.preOrderWithoutRecursion(); } @Test public void testMidOrder(){ - BinarySearchTree bst = new BinarySearchTree(); - bst.insert(5); - bst.insert(2); - bst.insert(7); - bst.insert(1); - bst.insert(6); - bst.insert(4); - bst.insert(8); bst.midOrder(bst.getRoot()); } @Test public void testMidOrderWithoutRecursion(){ - BinarySearchTree bst = new BinarySearchTree<>(); - bst.insert(5); - bst.insert(2); - bst.insert(7); - bst.insert(1); - bst.insert(6); - bst.insert(4); - bst.insert(8); bst.midOrderWithoutRecursion(); } @Test public void testPostOrder(){ - BinarySearchTree bst = new BinarySearchTree(); - bst.insert(5); - bst.insert(2); - bst.insert(7); - bst.insert(1); - bst.insert(6); - bst.insert(4); - bst.insert(8); bst.postOrder(bst.getRoot()); } @Test public void testPostOrderWithoutRecursion(){ - BinarySearchTree bst = new BinarySearchTree<>(); - bst.insert(5); - bst.insert(2); - bst.insert(7); - bst.insert(1); - bst.insert(6); - bst.insert(4); - bst.insert(8); bst.postOrderWithoutRecursion(); } + @Test + public void traveralByLevel(){ + bst.traveralByLevel(bst.getRoot()); + } + + @Test + public void postOrderGetHeight(){ + int height = bst.postOrderGetHeight(bst.getRoot()); + assertEquals(3, height); + } + + } From 54769dcef6dc3bcc6a8d7b9aa31aa048362d9ac8 Mon Sep 17 00:00:00 2001 From: JayXu Date: Thu, 16 Mar 2017 15:54:06 +0800 Subject: [PATCH 006/203] xuweijay --- group15/1511_714512544/.idea/workspace.xml | 296 ++++++++---------- .../coderising/download/DownloadThread.class | Bin 2242 -> 1545 bytes .../coderising/download/FileDownloader.class | Bin 2280 -> 3352 bytes .../download/FileDownloaderTest.class | Bin 2054 -> 2168 bytes .../download/impl/ConnectionImpl.class | Bin 1929 -> 2339 bytes .../download/impl/ConnectionManagerImpl.class | Bin 1581 -> 730 bytes .../coderising/download/ConnectionTest.java | 53 ++++ .../coderising/download/DownloadThread.java | 39 +-- .../coderising/download/FileDownloader.java | 120 ++++--- .../download/FileDownloaderTest.java | 4 +- .../download/impl/ConnectionImpl.java | 64 ++-- .../download/impl/ConnectionManagerImpl.java | 17 +- 12 files changed, 328 insertions(+), 265 deletions(-) create mode 100644 group15/1511_714512544/src/com/coderising/download/ConnectionTest.java diff --git a/group15/1511_714512544/.idea/workspace.xml b/group15/1511_714512544/.idea/workspace.xml index aff22b6c62..1ded1c3738 100644 --- a/group15/1511_714512544/.idea/workspace.xml +++ b/group15/1511_714512544/.idea/workspace.xml @@ -2,13 +2,18 @@ - - - - + + + + + + - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -129,9 +109,6 @@ - - - @@ -294,6 +271,9 @@ + + + @@ -314,8 +294,11 @@ + + + - + @@ -845,10 +828,10 @@ - - - - + + + + @@ -882,7 +865,8 @@ - + + 1488937445293 @@ -926,29 +910,36 @@ - - - + + - - + + - - + + - + - + - + - + @@ -962,7 +953,7 @@ - @@ -986,20 +977,20 @@ + - - + - + - + @@ -1038,14 +1029,6 @@ - - - file://$PROJECT_DIR$/src/com/coderising/download/FileDownloaderTest.java - 39 - - - @@ -1055,13 +1038,6 @@ - - - - - - - @@ -1296,161 +1272,167 @@ - + - - + + + - + - - + + + - + - - + + + + + + + + + + + + + + + + + + + + - + + - - + + - + - - - - - - + + + - + - - - + + + + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - - - - - - - - - - - - - - - - - - - + + + - + - - + + - + - - + + - - - - + - - + + - + - - - + + + + + - + - - - + + + + + + + diff --git a/group15/1511_714512544/out/production/1511_714512544/com/coderising/download/DownloadThread.class b/group15/1511_714512544/out/production/1511_714512544/com/coderising/download/DownloadThread.class index cc15cd0084d9697de05d493d8e2e82a4c5a851da..f1a7edc3ff1ca0f0ae266d9e03f5f3f49b59e011 100644 GIT binary patch literal 1545 zcma)6U2hXd6g{)M_Bv)sg54An2p=gB$1a%C(62x!4xuqPX^2fI;%Ty8$bz#Qt=FXe z0ae~n)n8DlFO@2)IuS*{d;dqFed$Zz+nyO)O(IBzR(ogey>suJd(X`L`u8u-0F2{{ zGzM_42XEm6B|cQ*BPBjo;u9MaDV$Hk#)UnY#6>mxREbMUl$5QM#uP5wn6_~xh0oI1 zhZ!4X8&?G^Hw*%ST*VDnif&lCKEog+YUX-hTaf)j^H}=C|LLk+QWfaec zO#x9BNP0nCE2*Y@;LXc;Ss+unCm+aSLo!h{j+l>e_L7Vu--`r}cigSmZ*a@NZAFn6 z#Kozv+=lO#I;$9vJnsj7JSpJ5F}ia3)t%pDv#~{XVv5xZ^i}-8n`^Bsc~MO+HE79H zLRU5xW#lWpYqa8JpB>m8+2w8nYs--*>nz8NT5PnL(|g_VRpy}%Ha{#b$e0gc;0D;+?ACes4?4@=vM#iO*kAFsIWsRGuK)hyPrp4~|Kr=|FMfFV=lXYQ zubToVcRQ*(ixcSI%HLr@U^KU_i`}F7szp(>>n=Ml1bI^Y^0em4O=a^g5nP-AwDP3W0IXXu&2XX=?kXz7{4m>{;3 z80{kbiyq~xiOLh$xAH$Dkx6Z$XO=UIzro*pjI@clf>OWUz@EaX4LF4j>{V+XqgQ~F zY;5#e}NvEF8-Hv<}gBkhWnIi0KS#8)qFCXqjeJ zGpw`B`l>{#Djp~5ew;%NV~ic4EzdZUYtncZr*y@&Za)kx;563>6d9R?@ek7(HqO|1 P55mUTG+po0WnlbYL=<3R literal 2242 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 YT56rFyOh9rb?bR{Fd)q{2_ygh1!aT%rT_o{ literal 2280 zcma)7ZF3V<6n<{9*-g{MhP2^LtD*(c^d%IbAT8Ctp)EDgh4;}$r(TJRc35E*cpC+ze&O8ZqlZeB;#aq_ny1=Joh>0Jm>CTFaCTE;5>>k z9K}==(;Ya189B^qxEezQQ_}dT6CY!)6Z5#HAsa<5h8Py)a9s|Ia`;5UlH9u-LmVq| z_*BDc3_ZA^;WG_u0^tp>B#_A7G42|flHn9G%f4qjg)xC>)wpXd8h(+}l3n#J$MOV* zv!+|lm~P(k>?${A^6ovSqnsyz>GJV^1a)x6RERSyL zxb4{fgg`R&D!Kku0cDyT1iG@eV=Ziy*DY_wSTAuUk#$X@v}$;^wCjtCU$mqe?b-XL zRgv*AFvVoF?U=|sHZnqwuxH#BI8np1-OQ5V4gq3;Q{pP4%~|OH)z; zv1NC|Gc6guK=;Ao4NEcWcnc|(D}OmNGF)*AI!@rYj$=4Z;;kfXmn)@xxvxh$$5kD@ zcvHg{I=;kL%&(5GaZ}(}&^JwLBCB>UFG<|eF$B_Chp8hkIh}5G{I331ik@ZA`E|S@ z5iA|IrC)cWN%sV$qtF)eU}gm34UFsSci41o=o}QHz)&mR2RH8NLvbq>l|J6Af!o%* zp&Uv(PN{H#*N>mAw--B+t#_sg?!KO@-(!L1QvLG+9kLJV2uf;RzKED5w@Lxs_+Lw?!*g}167bm@v`m=;d*UOvi;Ug4jjbxqhVPhd!L5MFgDY zdAzJ}2B{jl_yHP!z|SHpa_JpJ*0!N;LQDS<{FP^jhL9b2h7N&=9mLl7BAn>lhMpVT z!l91Gzo28V_q#2;MzbqCsw9=jZfRQs@q6xq5E4!JbC&238D)_TSz`7O9c<`BfntbAl4<$K>i^{pdigy2iT~CjByy} zkii(vVv@62eoz;10jn5gBVI%imr%xKe9!d<_<)F4@DLODiMwU4mJsFM5%d!?LXT6# zO+)1;cb4dBp4A7NeVrzchqQ)yR#@h(p4|{0^W>3$?<1c79vPnJdt$u6q=pL`M#bMy z#Xsm1;w9@F)^M@54oqpdq|o<$GOSg7g8s7Vs;u?lMy+GP>I^x~?yIr7S7TM)A;b{O z#CS6-?Y~&_#Jbi3>k9QKu_lp zI~VR87H&kG;>e6Yz@0zAwSPbtf+vA-n9+qdlXK6x=X~FJKpF*dXbQ@hvCO$`eIi zRq|PRuDFrQXQR7MEg{Zb`wvfNT;H}1dg|yi035y4JV^`bGz*f=`cJE;)Iw(>c#@Um zlh8_r(_Y4UXuA8(Y$ag@)vGx2I+Y9E$_zuLNois^l@#2#!jf$lQwfqjUHu02$i zAqC1Moa*`j{uP?v!%h) zl&+qvMmT7$ZYsq?9v?O7rzebVL?9C;OsF1=Aw>5&jA{Bq<}rlUErRz^&13ZX5up01 z`s4Wtm?LFQ>6e2~p8*V^V4xjo z585!|#;C-30~*F8E*Q{}wu5nr2?HKnw1bRoE_rYnSKPR2U=r6{m`=n#lJDHb=k(uqW=REp=9*9zP5 zm5uep+WKlDUs!s!vAU6rZ$4io(E2JOZW94y1yT%rRz?l#w{Tk^X6HiL$6Lkjq>WfK zaR)gQcM+7hXW~8{SZ~#l#)l@Bkd=63Vi|esr`n~iAZWE~Z!Dqv_P=WZVfpppKpO`G z2)@)vtI?-q+K{!T2X?|dGoa8mFlXWzJ=4J(IF1vH1UiXV5u)Gk#5~)hqrfiK9dOg3 zLQya5V%Bcgjh;F#!mq%|Lv%ZTwEe^9{V%>=hc8M##gSKIKl>uHE$U1aTCTqW*K8Gf zt^zq18z{patHP7(tH3CuAy$UD)As?&YlPq9NK0cGO|5ADh?d>jkF@63%4prKeX~K7)7;nv zW;p9@x-KSM=wpFqYp+jF#XMpp5Tu?&oHPm>jFTqGhAAQ`;{Z{KQxZcG!;2E9J%2}i Th5&^%Ud diff --git a/group15/1511_714512544/out/production/1511_714512544/com/coderising/download/impl/ConnectionImpl.class b/group15/1511_714512544/out/production/1511_714512544/com/coderising/download/impl/ConnectionImpl.class index b4a5c8354f458b2d774d42e42ceb53b19bb70931..68b0f11984a0802b32c93b28d0eef1d0d188f78b 100644 GIT binary patch literal 2339 zcmb7FTXz#x6#h<{WTxp*O4?9TLb+5SZ3$7iC@r9*v=B@$w515hWs*$Gz;q@|CO{EI zMS1aw2j6^hxfU-xz*?HR#O3nYzu-S{xy0{G(j?mY;6qN%W$%5y{q1j``R%WtegSX@ zk0a>Exps78R>52ZZJ1YZK7tSy$)+)e$Cp0*7yeSS7K zD$tQRKQS>rdu=XzXK=_zxo8Ae5Sh5zu((R@6oadVM z(&*rVKyb_{8UmYhrfp1Bmh*-?ujei9L~~9-w-$8QlmwY5Xn+~f%C)d!6Of;Fz4qncXFUufnVb>^EEKeXH_f+!YdNU3&g$=vt zPl5$rFOX*uPiPaF7M3C&^sGunHA4C z>AL#Lbj53RXeW#%!^;^qwWFY<;3!2Q5NVLdFkQ4D2G6ji;gWZQ@soora0`s-hQlcJ zA`mKAPMNi#A!{0$b1H7Zm@s7>yPNq)nh!`FY1oS?4ZE;gKx-A2JlH4D-`Lx*!WwQ% zcNaw4*Dzg2A7RZ>ZN$*)8?{I;Q!y>7LQ+Vo%EvW$sL0_CwVcv$7xy%*;J${B@IYYr zf9ObHhkqNZwP6`Fe2lZ?Uc+I0qTwMv)$kcUSMW%~7x+>`7H7%YT8wOyYL=#%$8`QC zwJWgqzo6+Qvqjm^NDu@y^fPKu0jpLg{F>Fab#hTSY9Nly+oW&3Z*hV>H7 z*%GOZTE6DDz7&*mBAKm+-SAlToHgJ*YxlPpGC;I!c(casic$7vTw->;6@h&lpjZdO ze~LOO{FVlzY}T$>*LlIRd7s3Dl9w~GGeUP=)8kscaq%snrl9{ z=pR~z7!p4qF!T~_7l&67K@aqYZ=79ty`T^zP(IH_x{6v;-^bIB6b^7-dZ+OQW4_6GHv+Hd8c^_-f`bqW4#~&=FpkiP5XF6l zXs6+mq3;o>LirWyR4Us35|N9m=!j}nY}#H$XLK_s2~Mi$s$xs3is(piOAtS+BcYe* zp>1p=oY-CrUO%G5!&PjJDc@puJQxpE(R)OVsox;{6kYLfJk%CbtJwDR)$et??+}%< z_=p-;W6F={d+slv6I6|j47xbqgAOvCBF6{G?+C$9LvYv8pl(PVDeT-u`PAms;6({g6 z2^+x$yhq;ilda4iG~J@9)AX>SmleIo(i6 z2hU{&!dKKV-uLy=ThCdd4MWT*$kAew`P5(xb6?&hUT_HbvZNX3Gk##Lc32N0Fzs8- F{0$>|3?2Xg literal 1929 zcmb7ETUQ%Z6#gc+8NvYJ+6L0ndT9fcMzK;QwJKYxyweviCmweBXEWp5OoZsEd#gJoQ>i`e58h)8kVA1#)>+)s)mo1ZB5zo zI@Y7;#~mFTIzG|ysfK9LbsSNYw(Dp}b8`XJ8QXxBX3$mPK&8yZ3jZb@k9%Gr)suI(3uw{8{6wDjcMqE+6oJX`IX#*o~#s~X00MRz|{GsmZ)#&_08M zWkIi&?`e|IX zFj+ZDk>(pRW!|lMMX_irNqb)w=Bj!_6A4V27{ri&o{&rik?gmh3Sl6MM=v_CFqP>6 zyG4ogNTUu~OigiES&3x!Rc=GN4LLRRB~J!2!JyCO)UIR0RE1m?}0I`2|!l@&^~&vUm(dw_Fv^eME_v7Zrm z!d(Ev96R~*0y=o26K&|i1?~nK(aiiBcRc53WjV6s-k^^;wJcAx(f24ZR0`dHZY)1T zaPuibQ=!qH5aM-l*P(gKcPKNu#-T32sTyGe>*?$3|45RS? diff --git a/group15/1511_714512544/out/production/1511_714512544/com/coderising/download/impl/ConnectionManagerImpl.class b/group15/1511_714512544/out/production/1511_714512544/com/coderising/download/impl/ConnectionManagerImpl.class index 1aec4647ba08c5bbd5401f9ccc7dd14b1b33aedf..50e93bc174a7d6879c0dbc1fc1bf33ff878e762a 100644 GIT binary patch delta 272 zcmZ3>bBk5s)W2Q(7#J8#805GZSQ*6F8N|65m>4A386?>mq}UmxCq^EgypU0vkIS_p zIkli9Ge57Gok3>u8%7;Ab_Nbc2JMLp)hAD2VgvGI85xWwE;O1P%k0XiKXIYN@{2i>lR4)-@5giA&-2flzt#ctV@}5h z7?2p$5yAzvT$K1+M-#q?U`Xx5YWY&)k`5gs5|<+NhVc1rDYh*Pbfp7wzJlwU{HPE#+mb+`LtE)Vapg{2NY5pg)!I z@@9sXMW^JrOJ>%)kM?)wGG>b_L9RInn+pL=&* zJ8k8@^NM*pOOvs?8M~mor$t9q#qrGKbR$1pF6LB@b_F7EVAi)X->0oYkTaH!1q?@AS`;ofG4cR-ZE;8^TJ`ym3OKY(!-lTyP(lp%`>5 z518~=yxyz-@9JpD_G`*>EQeQSI9e>Jrn{A*8T(e*F8OKOzu{#$=}U@LDtK);KLN+&R*nth$oY~;NEm*72;_iKFqZ_U>Z0=+Ndhv zD30+Y@G&|GLSvCYm=73meGQ?7o>hd?y%lIL&@`2Zwl7!EoM@93L=qM38`L_qC|>>q zV-5O3Vio(Jtif1lJFtqDztaKPS|{5S360SG7{Ngda83%QW9-zx3=)z@m)A~3jaUuw89FjJJlyozoD9%!Lf|w_1^9fgt7CKJh zG^LXP^(iTaTT6waVu&*(XUOeF_>Fq*dn9_rzXT3RBqTwFggGJc8O~8lqjn$v^Q1%Q F{|{GQntuQQ diff --git a/group15/1511_714512544/src/com/coderising/download/ConnectionTest.java b/group15/1511_714512544/src/com/coderising/download/ConnectionTest.java new file mode 100644 index 0000000000..247817cf42 --- /dev/null +++ b/group15/1511_714512544/src/com/coderising/download/ConnectionTest.java @@ -0,0 +1,53 @@ +package com.coderising.download; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.coderising.download.api.Connection; +import com.coderising.download.api.ConnectionManager; +import com.coderising.download.impl.ConnectionManagerImpl; + + + +public class ConnectionTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testContentLength() throws Exception{ + ConnectionManager connMan = new ConnectionManagerImpl(); + Connection conn = connMan.open("http://www.hinews.cn/pic/0/13/91/26/13912621_821796.jpg"); + Assert.assertEquals(35470, conn.getContentLength()); + } + + @Test + public void testRead() throws Exception{ + + ConnectionManager connMan = new ConnectionManagerImpl(); + Connection conn = connMan.open("http://www.hinews.cn/pic/0/13/91/26/13912621_821796.jpg"); + + byte[] data = conn.read(0, 35469); + + Assert.assertEquals(35470, data.length); + + data = conn.read(0, 1023); + + Assert.assertEquals(1024, data.length); + + data = conn.read(1024, 2023); + + Assert.assertEquals(1000, data.length); + + + // 测试不充分,没有断言内容是否正确 + } + +} diff --git a/group15/1511_714512544/src/com/coderising/download/DownloadThread.java b/group15/1511_714512544/src/com/coderising/download/DownloadThread.java index 9173329f7b..cf3c0dcadb 100644 --- a/group15/1511_714512544/src/com/coderising/download/DownloadThread.java +++ b/group15/1511_714512544/src/com/coderising/download/DownloadThread.java @@ -1,58 +1,39 @@ package com.coderising.download; import com.coderising.download.api.Connection; -import com.coderising.download.api.DownloadListener; -import com.coderising.download.impl.ConnectionImpl; -import com.coderising.download.impl.ConnectionManagerImpl; -import java.io.IOException; import java.io.RandomAccessFile; -import java.net.URL; +import java.util.concurrent.CyclicBarrier; public class DownloadThread extends Thread{ + Connection conn; int startPos; int endPos; - String url; String savePath; - DownloadListener listener; - private static int count = 0; - private Object lock = new Object(); //对象锁 + CyclicBarrier barrier; //栅栏 - public DownloadThread(String url, String savePath, DownloadListener listener, int startPos, int endPos){ + public DownloadThread(Connection conn, int startPos, int endPos, String savePath, CyclicBarrier barrier){ this.startPos = startPos; this.endPos = endPos; - this.url = url; + this.conn = conn; this.savePath = savePath; - this.listener = listener; + this.barrier = barrier; } public void run(){ RandomAccessFile raf = null; //实现 try { - Connection conn = new ConnectionManagerImpl().open(url); - raf = new RandomAccessFile(savePath,"rwd"); - + RandomAccessFile file = new RandomAccessFile(savePath,"rw"); byte[] data= conn.read(startPos,endPos); raf.seek(startPos); raf.write(data); - synchronized (lock){ //加对象锁 - count ++; - if(count == 3){ - listener.notifyFinished(); - } - } + raf.close(); + conn.close(); + barrier.await(); //等待其他线程执行到这里,//等待别的线程完成 } catch (Exception e) { throw new RuntimeException("读取错误"); - }finally { - try { - if(raf != null){ - raf.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } } } } diff --git a/group15/1511_714512544/src/com/coderising/download/FileDownloader.java b/group15/1511_714512544/src/com/coderising/download/FileDownloader.java index c620180530..f8e78d4f7a 100644 --- a/group15/1511_714512544/src/com/coderising/download/FileDownloader.java +++ b/group15/1511_714512544/src/com/coderising/download/FileDownloader.java @@ -1,27 +1,32 @@ package com.coderising.download; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.concurrent.CyclicBarrier; + import com.coderising.download.api.Connection; -import com.coderising.download.api.ConnectionException; import com.coderising.download.api.ConnectionManager; import com.coderising.download.api.DownloadListener; -import com.coderising.download.impl.ConnectionManagerImpl; -import java.io.RandomAccessFile; -/** - * 文件下载器 - */ public class FileDownloader { - String url; //下载路径 - String savePath = "d:/1.png"; //保存路径 - DownloadListener listener ; //下载监听器 - ConnectionManager cm ; //连接管理 - public FileDownloader(String _url) { + private String url; + private String localFile; + + DownloadListener listener; + + ConnectionManager cm; + + + private static final int DOWNLOAD_TRHEAD_NUM = 3; + + public FileDownloader(String _url, String localFile) { this.url = _url; - + this.localFile = localFile; + } - + public void execute(){ // 在这里实现你的代码, 注意: 需要用多线程实现下载 // 这个类依赖于其他几个接口, 你需要写这几个接口的实现代码 @@ -34,48 +39,91 @@ public void execute(){ // 然后调用read方法, read方法中有读取文件的开始位置和结束位置的参数, 返回值是byte[]数组 // 3. 把byte数组写入到文件中 // 4. 所有的线程都下载完成以后, 需要调用listener的notifiedFinished方法 - + // 下面的代码是示例代码, 也就是说只有一个线程, 你需要改造成多线程的。 - Connection conn = null; - RandomAccessFile raf = null; + + CyclicBarrier barrier = new CyclicBarrier(DOWNLOAD_TRHEAD_NUM , new Runnable(){ + public void run(){ + listener.notifyFinished(); + } + }); + + Connection conn = null; try { - cm = new ConnectionManagerImpl(); - conn = cm.open(this.url); + + conn = cm.open(this.url); + int length = conn.getContentLength(); - raf = new RandomAccessFile(savePath,"rwd"); - if(raf.length() == 0){ - raf.setLength(length); - } - raf.close(); - - for (int i = 0; i <= 2; i++) { - int startPos = i*length/3; - int endPos = length*(i+1)/3-1; - if(i == 2) { - endPos = length-1; - } - new DownloadThread(url, savePath,listener ,startPos, endPos).start(); + createPlaceHolderFile(this.localFile, length); + + int[][] ranges = allocateDownloadRange(DOWNLOAD_TRHEAD_NUM, length); + + for(int i=0; i< DOWNLOAD_TRHEAD_NUM; i++){ + + + DownloadThread thread = new DownloadThread( + cm.open(url),ranges[i][0], ranges[i][1], localFile, barrier ); + + thread.start(); } } catch (Exception e) { e.printStackTrace(); + }finally{ + if(conn != null){ + conn.close(); + } } } - + + private void createPlaceHolderFile(String fileName, int contentLen) throws IOException{ + + RandomAccessFile file = new RandomAccessFile(fileName,"rw"); + + for(int i=0; i targetLen){ + byte[] result = bos.toByteArray(); + return Arrays.copyOf(result, targetLen); + } + return bos.toByteArray(); } /** * 得到数据内容的长度 @@ -47,22 +60,23 @@ public byte[] read(int startPos, int endPos) throws IOException { */ @Override public int getContentLength() { - return connection.getContentLength(); + HttpURLConnection conn; + + try { + conn = (HttpURLConnection) url.openConnection(); + return conn.getContentLength(); + } catch (IOException e) { + e.printStackTrace(); + } + return -1; + } /** * 关闭连接 */ @Override public void close() { - InputStream in; - try { - in = connection.getInputStream(); - if(in != null){ - in.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } + } } diff --git a/group15/1511_714512544/src/com/coderising/download/impl/ConnectionManagerImpl.java b/group15/1511_714512544/src/com/coderising/download/impl/ConnectionManagerImpl.java index 55d27dc156..ccb7907072 100644 --- a/group15/1511_714512544/src/com/coderising/download/impl/ConnectionManagerImpl.java +++ b/group15/1511_714512544/src/com/coderising/download/impl/ConnectionManagerImpl.java @@ -17,22 +17,7 @@ public class ConnectionManagerImpl implements ConnectionManager { */ @Override public Connection open(String url) throws ConnectionException { - try { - URL u = new URL(url); - HttpURLConnection conn = (HttpURLConnection) u.openConnection(); - conn.setConnectTimeout(5000); - conn.setRequestMethod("GET"); - int code = conn.getResponseCode(); - if(code == 200){ - return new ConnectionImpl(conn); - }else { - throw new RuntimeException("打开连接失败"); - } - } catch (MalformedURLException e) { - throw new RuntimeException("url非法"); - } catch (IOException e) { - throw new RuntimeException("IO异常"); - } + return new ConnectionImpl(url); } } From cd169fc47038a0fb0b15cb6ddd8bc1912e8bbe28 Mon Sep 17 00:00:00 2001 From: JayXu Date: Thu, 16 Mar 2017 18:04:07 +0800 Subject: [PATCH 007/203] xuweijay --- .../src/com/coding/basic/ReConstructBST.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/group15/1511_714512544/src/com/coding/basic/ReConstructBST.java b/group15/1511_714512544/src/com/coding/basic/ReConstructBST.java index 7918170e2d..bc9e6c75a4 100644 --- a/group15/1511_714512544/src/com/coding/basic/ReConstructBST.java +++ b/group15/1511_714512544/src/com/coding/basic/ReConstructBST.java @@ -1,5 +1,8 @@ package com.coding.basic; +import java.util.Queue; +import java.util.LinkedList; + /** * 由两种遍历结果确定二叉树(其中一个结果必须是中序遍历的结果) */ @@ -67,6 +70,20 @@ public static void printInPostOrder(Node n){ System.out.print(n.data+" "); } + public static void traveralByLevel(Node n){ + if(n == null) return; + + Queue queue = new LinkedList(); + queue.offer(n); + + while(!queue.isEmpty()){ + Node node = queue.poll(); + System.out.print(node.data + " "); + if(node.left != null) queue.offer(node.left); + if(node.right != null) queue.offer(node.right); + } + } + //节点 public static class Node{ From 35d976b8497ae3a3f4c44e93efbad59a71c84be3 Mon Sep 17 00:00:00 2001 From: JayXu Date: Thu, 16 Mar 2017 18:04:35 +0800 Subject: [PATCH 008/203] xuweijay --- .../src/com/coding/basic/ReConstructBSTTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/group15/1511_714512544/src/com/coding/basic/ReConstructBSTTest.java b/group15/1511_714512544/src/com/coding/basic/ReConstructBSTTest.java index 861be70968..623cc4c470 100644 --- a/group15/1511_714512544/src/com/coding/basic/ReConstructBSTTest.java +++ b/group15/1511_714512544/src/com/coding/basic/ReConstructBSTTest.java @@ -22,10 +22,10 @@ public void tearDown() throws Exception { @Test public void construct() throws Exception { - int[] preOrder = {1,2,4,7,3,5,6,8}; - int[] inOrder = {4,7,2,1,5,3,8,6}; + int[] preOrder = {1,2,3,4,5,6,7}; + int[] inOrder = {3,2,4,1,6,5,7}; ReConstructBST.Node n = ReConstructBST.construct(preOrder,inOrder); - ReConstructBST.printInPostOrder(n); + ReConstructBST.traveralByLevel(n); } } \ No newline at end of file From 6befcd52ff8623dd3cc386cef2a92ae684e77009 Mon Sep 17 00:00:00 2001 From: JayXu Date: Thu, 16 Mar 2017 18:10:00 +0800 Subject: [PATCH 009/203] xuweijay --- group15/1511_714512544/.idea/workspace.xml | 233 ++++++------------ .../com/coding/basic/BinarySearchTree.java | 6 +- .../src/com/coding/basic/ReConstructBST.java | 4 +- 3 files changed, 75 insertions(+), 168 deletions(-) diff --git a/group15/1511_714512544/.idea/workspace.xml b/group15/1511_714512544/.idea/workspace.xml index 1ded1c3738..9cd6e9b941 100644 --- a/group15/1511_714512544/.idea/workspace.xml +++ b/group15/1511_714512544/.idea/workspace.xml @@ -2,18 +2,9 @@ - - - - - - - - - - - + + @@ -134,10 +125,6 @@ @@ -298,7 +199,7 @@ - + @@ -828,8 +729,8 @@ - - + + @@ -866,7 +767,9 @@ - + + + 1488937445293 @@ -917,16 +820,31 @@ - - - - - - - @@ -951,9 +869,15 @@ + + + + + + - @@ -971,30 +895,30 @@ - - + - + - + + @@ -1284,7 +1208,6 @@ - @@ -1314,14 +1237,6 @@ - - - - - - - - @@ -1330,29 +1245,10 @@ - - - - - - - - - - - - - - - - - - - @@ -1360,7 +1256,6 @@ - @@ -1368,7 +1263,6 @@ - @@ -1376,7 +1270,6 @@ - @@ -1384,7 +1277,6 @@ - @@ -1392,7 +1284,6 @@ - @@ -1400,9 +1291,6 @@ - - - @@ -1410,7 +1298,6 @@ - @@ -1418,9 +1305,6 @@ - - - @@ -1428,10 +1312,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + - - diff --git a/group15/1511_714512544/src/com/coding/basic/BinarySearchTree.java b/group15/1511_714512544/src/com/coding/basic/BinarySearchTree.java index ea91e0325a..9fef229c43 100644 --- a/group15/1511_714512544/src/com/coding/basic/BinarySearchTree.java +++ b/group15/1511_714512544/src/com/coding/basic/BinarySearchTree.java @@ -248,10 +248,10 @@ public void traveralByLevel(BinarySearchTreeNode n){ if(n == null) return; Queue> queue = new LinkedList>(); - queue.offer(n); + queue.offer(n); //入队列 while(!queue.isEmpty()){ - BinarySearchTreeNode node = queue.poll(); + BinarySearchTreeNode node = queue.poll(); //出队列 System.out.print(node.getData() + " "); if(node.getLeft() != null) queue.offer(node.getLeft()); if(node.getRight() != null) queue.offer(node.getRight()); @@ -345,7 +345,7 @@ public int postOrderGetHeight(BinarySearchTreeNode n){ hL = postOrderGetHeight(n.getLeft()); //求左子树深度 hR = postOrderGetHeight(n.getRight()); //求右子树深度 maxH = hL> hR? hL : hR ; //求左右子树深度最大的那个 - return (maxH+1);//返回数的深度 + return (maxH+1);//返回树的深度 } return 0; //空树返回0 } diff --git a/group15/1511_714512544/src/com/coding/basic/ReConstructBST.java b/group15/1511_714512544/src/com/coding/basic/ReConstructBST.java index bc9e6c75a4..d8c7ac69e0 100644 --- a/group15/1511_714512544/src/com/coding/basic/ReConstructBST.java +++ b/group15/1511_714512544/src/com/coding/basic/ReConstructBST.java @@ -44,8 +44,8 @@ private static Node reConstruct(int[] preOrder, int ps, int pe, int[] inOrder, i int rootIndexInOrder = is; while(rootIndexInOrder <= ie && inOrder[rootIndexInOrder]!=rootValue) rootIndexInOrder++; - int lCTLengthInOrder = rootIndexInOrder - is; - int lCTEndIndexPreOrder = ps + lCTLengthInOrder; + int lCTLengthInOrder = rootIndexInOrder - is; //左子树长度 + int lCTEndIndexPreOrder = ps + lCTLengthInOrder; //左子树末尾节点在前序遍历序列中的位置 if(lCTLengthInOrder > 0){ //左子树有元素,构建左子树 root.left = reConstruct(preOrder, ps+1, lCTEndIndexPreOrder, inOrder, is, rootIndexInOrder-1); From 1d7c36380efd718ca1e7137b7dbd7b58f3f3166e Mon Sep 17 00:00:00 2001 From: Samson Shenglu Cao Date: Mon, 20 Mar 2017 09:32:43 +0800 Subject: [PATCH 010/203] 3rd homework --- .../src/com/coding/basic/LinkedList.java | 234 +++++++++++++++++- .../src/com/coding/basic/LinkedListTest.java | 209 ++++++++++++++++ .../src/com/download/DownloadDemo.java | 34 +++ .../src/com/download/DownloadThread.java | 58 +++++ .../src/com/download/FileDownloader.java | 88 +++++++ .../src/com/download/FileDownloaderTest.java | 52 ++++ .../src/com/download/api/Connection.java | 23 ++ .../com/download/api/ConnectionException.java | 5 + .../com/download/api/ConnectionManager.java | 10 + .../com/download/api/DownloadListener.java | 5 + .../src/com/download/impl/ConnectionImpl.java | 46 ++++ .../download/impl/ConnectionManagerImpl.java | 28 +++ 12 files changed, 786 insertions(+), 6 deletions(-) create mode 100644 group19/972815123/src/com/coding/basic/LinkedListTest.java create mode 100644 group19/972815123/src/com/download/DownloadDemo.java create mode 100644 group19/972815123/src/com/download/DownloadThread.java create mode 100644 group19/972815123/src/com/download/FileDownloader.java create mode 100644 group19/972815123/src/com/download/FileDownloaderTest.java create mode 100644 group19/972815123/src/com/download/api/Connection.java create mode 100644 group19/972815123/src/com/download/api/ConnectionException.java create mode 100644 group19/972815123/src/com/download/api/ConnectionManager.java create mode 100644 group19/972815123/src/com/download/api/DownloadListener.java create mode 100644 group19/972815123/src/com/download/impl/ConnectionImpl.java create mode 100644 group19/972815123/src/com/download/impl/ConnectionManagerImpl.java diff --git a/group19/972815123/src/com/coding/basic/LinkedList.java b/group19/972815123/src/com/coding/basic/LinkedList.java index 04de763349..b001f06305 100644 --- a/group19/972815123/src/com/coding/basic/LinkedList.java +++ b/group19/972815123/src/com/coding/basic/LinkedList.java @@ -12,13 +12,24 @@ public LinkedList() { @Override public void add(Object o) { + + Node newNode = new Node(); - Node last = head; - while(last.next != null){ - last = last.next; + newNode.data = o; + newNode.next = null; + + if(size == 0){ + head = newNode; + size = 1; + return; } - last.next = newNode; - newNode.prev = last; + + Node _last = head; + while(_last.next != null){ + _last = _last.next; + } + _last.next = newNode; + newNode.prev = _last; last = newNode; size++; } @@ -60,7 +71,7 @@ public int size() { public Object remove(int index) { Node indexNode = head ; int i = 0; - while(i == index){ + while(i != index){ indexNode = indexNode.next; i++; @@ -131,4 +142,215 @@ public Object next() { index = index.next; return tem; } + + @Override + public String toString(){ + Node node = head; + StringBuffer sb = new StringBuffer(); + while(node.next != null){ + sb.append(node.data.toString() + ","); + node = node.next; + } + sb.append(node.data.toString()); + return sb.toString(); + } + + /** + * 把该链表逆置 + * 例如链表为 3->7->10 , 逆置后变为 10->7->3 + */ + public void reverse(){ + Node index = head; + Node temPre = null; + while(true){ + Node tem = index.next; + if(index.next == null){ + head = index; + index.next = temPre; + break; + } + index.next = temPre; + temPre = index; + index = tem; + } + } + + /** + * 删除一个单链表的前半部分 + * 例如:list = 2->5->7->8 , 删除以后的值为 7->8 + * 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10 + */ + public void removeFirstHalf(){ + int i = 0; + Node node = head; + while(i < size/2 + 1){ + head = node; + node = node.next; + i++; + } + } + + /** + * 从第i个元素开始, 删除length 个元素 , 注意i从0开始 + * @param i + * @param length + */ + public void remove(int i, int length){ + //省略了数据合法性检查; + Node indexStart = head; + int index = 0; + for(int j = 0; j < i - 1; j++){ + indexStart= indexStart.next; + } + Node indexEnd = indexStart; + Node tem = null; + for(int k = 0 ; k <= length; k++){ + tem = indexEnd; + indexEnd = indexEnd.next; + } + tem.next = null; + indexStart.next = indexEnd; + } + /** + * 假定当前链表和listB均包含已升序排列的整数 + * 从当前链表中取出那些listB所指定的元素 + * 例如当前链表 = 11->101->201->301->401->501->601->701 + * listB = 1->3->4->6 + * 返回的结果应该是[101,301,401,601] + * @param list + */ + public Object[] getElements(LinkedList list){ + //省略了数据合法性检查; + Node pointHead = list.head; + Node node = head; + Object[] result = new Object[list.size]; + int point = 0; + int resultPoint = 0; + while(true){ + int temPoint = (int)pointHead.data; + if(point == temPoint){ + result[resultPoint] = node.data; + if(pointHead.next == null){ + break; + } + resultPoint++; + pointHead = pointHead.next; + } + if(node.next == null ){ + break; + } + node = node.next; + point++; + } + return result; + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 从当前链表中中删除在listB中出现的元素 + + * @param list + */ + //m * n 复杂度的算法,没有利用原链表已排序的特性; + public void subtract(LinkedList list){ + Node indexNode = head; + Node indexPreNode = null; + while(null != indexNode){ + Node pointNode = list.head; + while(null != pointNode){ + if((int)pointNode.data == (int)(indexNode.data)){ + if(indexPreNode == null){ + head = indexNode.next; + }else{ + indexPreNode.next = indexNode.next; + } + } + pointNode = pointNode.next; + } + indexPreNode = indexNode; + indexNode = indexNode.next; + } + } + + /** + * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) + */ + public void removeDuplicateValues(){ + Node indexNode = head; + Node indexPreNode = null; + while(null != indexNode){ + if(null == indexPreNode){ + indexPreNode = indexNode; + indexNode = indexNode.next; + continue; + } + if((int)indexPreNode.data == (int)indexNode.data){ + indexPreNode.next = indexNode.next; + }else{ + indexPreNode = indexNode; + } + indexNode = indexNode.next; + } + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 试写一高效的算法,删除表中所有值大于min且小于max的元素(若表中存在这样的元素) + * @param min + * @param max + */ + public void removeRange(int min, int max){ + Node indexNode = head; + Node indexPreNode = null; + Node minNode = null; + Node maxNode = null; + boolean getMin = false, getMax = false; + while(indexNode != null){ + if((int)indexNode.data >= min){ + if(!getMin){ + minNode = indexPreNode; + getMin = true; + } + } + + if((int)indexNode.data > max){ + if(!getMax){ + maxNode = indexNode; + break; + } + } + indexPreNode = indexNode; + indexNode = indexNode.next; + } + if(null == minNode && null == maxNode){ + head.data = null; + head.next = null; + }else if(null != minNode && null != maxNode){ + minNode.next = maxNode; + } + + } + + /** + * 假设当前链表和参数list指定的链表均以元素依值递增有序排列(同一表中的元素值各不相同) + * 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列 + * @param list + */ + public LinkedList intersection( LinkedList list){ + LinkedList result = new LinkedList(); + Node indexNode = head; + while(null != indexNode){ + Node pointNode = list.head; + while(null != pointNode){ + if((int)pointNode.data == (int)(indexNode.data)){ + result.add(indexNode.data); + } + pointNode = pointNode.next; + } + indexNode = indexNode.next; + } + return result; + } + } diff --git a/group19/972815123/src/com/coding/basic/LinkedListTest.java b/group19/972815123/src/com/coding/basic/LinkedListTest.java new file mode 100644 index 0000000000..1bb14396a0 --- /dev/null +++ b/group19/972815123/src/com/coding/basic/LinkedListTest.java @@ -0,0 +1,209 @@ +package com.coding.basic; + +import static org.junit.Assert.*; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import junit.framework.Assert; + +public class LinkedListTest { + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testRemove(){ + LinkedList ll = new LinkedList(); + ll.add("1"); + ll.add("2"); + ll.add("3"); + ll.add("4"); + ll.remove(3); + System.out.println(ll.toString()); + Assert.assertEquals("1,2,3,4", ll.toString()); + } + + @Test + public void testToString() { + LinkedList ll = new LinkedList(); + ll.add("1"); + ll.add("2"); + ll.add("3"); + ll.add("4"); + System.out.println(ll.toString()); + Assert.assertEquals("1,2,3,4", ll.toString()); + } + + @Test + public void testReverse() { + LinkedList ll = new LinkedList(); + ll.add("4"); + ll.add("3"); + ll.add("2"); + ll.add("1"); + System.out.println(ll.toString()); + ll.reverse(); + System.out.println(ll.toString()); + Assert.assertEquals("1,2,3,4", ll.toString()); + } + + @Test + public void testRemoveFirstHalf() { + LinkedList ll = new LinkedList(); + ll.add("4"); + ll.add("3"); + ll.add("2"); + ll.add("1"); + ll.add("0"); + System.out.println(ll.toString()); + ll.removeFirstHalf(); + System.out.println(ll.toString()); + Assert.assertEquals("2,1,0", ll.toString()); + } + + @Test + public void testRemoveIntInt() { + LinkedList ll = new LinkedList(); + ll.add("1"); + ll.add("2"); + ll.add("3"); + ll.add("4"); + ll.add("5"); + ll.add("6"); + ll.add("7"); + ll.add("8"); + ll.add("9"); + ll.remove(3,2); + System.out.println(ll.toString()); + Assert.assertEquals("1,2,3,6,7,8,9", ll.toString()); + } + + @Test + public void testGetElements() { + LinkedList ll = new LinkedList(); + ll.add("0"); + ll.add("1"); + ll.add("2"); + ll.add("3"); + ll.add("4"); + ll.add("5"); + ll.add("6"); + ll.add("7"); + ll.add("8"); + ll.add("9"); + LinkedList pointerList = new LinkedList(); + pointerList.add(1); + pointerList.add(3); + pointerList.add(5); + pointerList.add(7); + Object[] result = ll.getElements(pointerList); + for(Object o : result){ + System.out.print((String)o); + System.out.print(","); + } + Assert.assertEquals((String)result[3], "7"); + } + + @Test + public void testSubtract() { + LinkedList ll = new LinkedList(); + ll.add(0); + ll.add(1); + ll.add(2); + ll.add(3); + ll.add(4); + ll.add(5); + ll.add(6); + ll.add(7); + ll.add(8); + LinkedList pointerList = new LinkedList(); + pointerList.add(1); + pointerList.add(3); + pointerList.add(5); + pointerList.add(7); + ll.subtract(pointerList); + System.out.println(ll.toString()); + Assert.assertEquals("0,2,4,6,8", ll.toString()); + } + + @Test + public void testRemoveDuplicateValues() { + LinkedList ll = new LinkedList(); + ll.add(0); + ll.add(1); + ll.add(2); + ll.add(3); + ll.add(3); + ll.add(3); + ll.add(4); + ll.add(5); + ll.add(5); + ll.add(6); + ll.add(7); + ll.add(8); + ll.removeDuplicateValues(); + System.out.println(ll.toString()); + Assert.assertEquals("0,1,2,3,4,5,6,7,8", ll.toString()); + } + + @Test + public void testRemoveRange() { + LinkedList ll = new LinkedList(); + ll.add(0); + ll.add(1); + ll.add(2); + ll.add(3); + ll.add(3); + ll.add(3); + ll.add(4); + ll.add(5); + ll.add(5); + ll.add(6); + ll.add(7); + ll.add(8); + ll.removeRange(3,7); + System.out.println(ll.toString()); + Assert.assertEquals("0,1,2,8", ll.toString()); + } + + @Test + public void testIntersection() { + LinkedList ll = new LinkedList(); + ll.add(0); + ll.add(1); + ll.add(2); + ll.add(3); + ll.add(4); + ll.add(5); + ll.add(6); + ll.add(7); + ll.add(8); + LinkedList pointerList = new LinkedList(); + pointerList.add(1); + pointerList.add(5); + pointerList.add(3); + pointerList.add(11); + pointerList.add(7); + ll = ll.intersection(pointerList); + System.out.println(ll.toString()); + Assert.assertEquals("1,3,5,7", ll.toString()); + } + +} diff --git a/group19/972815123/src/com/download/DownloadDemo.java b/group19/972815123/src/com/download/DownloadDemo.java new file mode 100644 index 0000000000..ceb9f93309 --- /dev/null +++ b/group19/972815123/src/com/download/DownloadDemo.java @@ -0,0 +1,34 @@ +package com.coderising.download; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.RandomAccessFile; +import java.net.URL; +import java.net.URLConnection; + +public class DownloadDemo { + + public static void main(String[] args) throws Exception { + URL url = new URL("http://bpic.588ku.com/back_pic/02/66/65/68578b3fca8af67.jpg"); + URLConnection conn = url.openConnection(); + InputStream is = conn.getInputStream(); + + System.out.println("content length:" + conn.getContentLength() /1024 + " * 1024"); + System.out.println("stream avilable:" + is.available()/1024 + " * 1024"); + int length = conn.getContentLength(); + + byte[] buffer = new byte[1024]; + int hasRead = 0; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + while((hasRead = is.read(buffer)) != -1){ + out.write(buffer, 0, hasRead); + } + byte[] result = out.toByteArray(); + + RandomAccessFile file = new RandomAccessFile("demo.jpg", "rw"); + file.write(result); + file.close(); + is.close(); + } +} diff --git a/group19/972815123/src/com/download/DownloadThread.java b/group19/972815123/src/com/download/DownloadThread.java new file mode 100644 index 0000000000..c699e81f5a --- /dev/null +++ b/group19/972815123/src/com/download/DownloadThread.java @@ -0,0 +1,58 @@ +package com.coderising.download; + +import java.io.IOException; +import java.io.RandomAccessFile; + +import com.coderising.download.api.Connection; +import com.coderising.download.api.DownloadListener; + +public class DownloadThread extends Thread{ + + Connection conn; + int startPos; + int endPos; + + String fileName; + + Object obj; + private DownloadListener downLoadThread; + +// public DownloadThread setObj(Object obj){ +// this.obj = obj; +// return this; +// } + + public DownloadThread setOnThreadFinished(DownloadListener downLoadThread){ + this.downLoadThread = downLoadThread; + return this; + } + + + public DownloadThread( Connection conn, int startPos, int endPos, String fileName){ + + this.conn = conn; + this.startPos = startPos; + this.endPos = endPos; + this.fileName = fileName; + } + public void run(){ + try { + double id = Thread.currentThread().getId(); + System.out.println(id); + byte[] byArr = conn.read(startPos, endPos); + int len = byArr.length; + + Thread.sleep(2000); + + RandomAccessFile currenctPart = new RandomAccessFile(fileName, "rw"); + currenctPart.seek(startPos); + System.out.println(len + "readed length"); + currenctPart.write(byArr,0,len); + currenctPart.close(); + System.out.println(id); + downLoadThread.notifyFinished(); + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + } +} diff --git a/group19/972815123/src/com/download/FileDownloader.java b/group19/972815123/src/com/download/FileDownloader.java new file mode 100644 index 0000000000..d02b9970b8 --- /dev/null +++ b/group19/972815123/src/com/download/FileDownloader.java @@ -0,0 +1,88 @@ +package com.coderising.download; + + +import com.coderising.download.api.Connection; +import com.coderising.download.api.ConnectionException; +import com.coderising.download.api.ConnectionManager; +import com.coderising.download.api.DownloadListener; +import com.coderising.download.impl.ConnectionManagerImpl; + + +public class FileDownloader { + + String url; + DownloadListener listener; + ConnectionManager cm; + private int threadRun = 0; + + public FileDownloader(String _url) { + this.url = _url; + } + + public void execute(){ + // 在这里实现你的代码, 注意: 需要用多线程实现下载 + // 这个类依赖于其他几个接口, 你需要写这几个接口的实现代码 + // (1) ConnectionManager , 可以打开一个连接,通过Connection可以读取其中的一段(用startPos, endPos来指定) + // (2) DownloadListener, 由于是多线程下载, 调用这个类的客户端不知道什么时候结束,所以你需要实现当所有 + // 线程都执行完以后, 调用listener的notifiedFinished方法, 这样客户端就能收到通知。 + // 具体的实现思路: + // 1. 需要调用ConnectionManager的open方法打开连接, 然后通过Connection.getContentLength方法获得文件的长度 + // 2. 至少启动3个线程下载, 注意每个线程需要先调用ConnectionManager的open方法 + // 然后调用read方法, read方法中有读取文件的开始位置和结束位置的参数, 返回值是byte[]数组 + // 3. 把byte数组写入到文件中 + // 4. 所有的线程都下载完成以后, 需要调用listener的notifiedFinished方法 + + // 下面的代码是示例代码, 也就是说只有一个线程, 你需要改造成多线程的。 + Connection conn = null; + try { + cm = new ConnectionManagerImpl(); + conn = cm.open(this.url); + + int length = conn.getContentLength(); + String fileName = "test.jpg"; + Object obj = new Object(); + int part = 4; + int step = length / part; + for(int i = 0; i < part; i++){ + threadRun++; + new DownloadThread(cm.open(this.url), step * i,step * (i + 1) -1, fileName) + .setOnThreadFinished(new DownloadListener() { + + @Override + public void notifyFinished() { + synchronized (this) { + threadRun--; + if(threadRun==0){ + listener.notifyFinished(); + } + } + + } + }).start(); + } + + + } catch (ConnectionException e ) { + e.printStackTrace(); + }finally{ + if(conn != null){ + conn.close(); + } + } + } + + public void setListener(DownloadListener listener) { + this.listener = listener; + } + + + +// public void setConnectionManager(ConnectionManager ucm){ +// this.cm = ucm; +// } + + public DownloadListener getListener(){ + return this.listener; + } + +} diff --git a/group19/972815123/src/com/download/FileDownloaderTest.java b/group19/972815123/src/com/download/FileDownloaderTest.java new file mode 100644 index 0000000000..de22d5765e --- /dev/null +++ b/group19/972815123/src/com/download/FileDownloaderTest.java @@ -0,0 +1,52 @@ +package com.coderising.download; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.coderising.download.api.ConnectionManager; +import com.coderising.download.api.DownloadListener; +import com.coderising.download.impl.ConnectionManagerImpl; + +public class FileDownloaderTest { + boolean downloadFinished = false; + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testDownload() { + + String url = "http://img.sc115.com/uploads1/sc/jpgs/1504/fpic780_sc115.com.jpg"; + FileDownloader downloader = new FileDownloader(url); + +// ConnectionManager cm = new ConnectionManagerImpl(); +// downloader.setConnectionManager(cm); + + downloader.setListener(new DownloadListener() { + @Override + public void notifyFinished() { + downloadFinished = true; + } + }); + + downloader.execute(); + + // 等待多线程下载程序执行完毕 + while (!downloadFinished) { + try { + System.out.println("还没有下载完成,休眠五秒"); + //休眠5秒 + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + System.out.println("下载完成!"); + } + +} diff --git a/group19/972815123/src/com/download/api/Connection.java b/group19/972815123/src/com/download/api/Connection.java new file mode 100644 index 0000000000..0957eaf7f4 --- /dev/null +++ b/group19/972815123/src/com/download/api/Connection.java @@ -0,0 +1,23 @@ +package com.coderising.download.api; + +import java.io.IOException; + +public interface Connection { + /** + * 给定开始和结束位置, 读取数据, 返回值是字节数组 + * @param startPos 开始位置, 从0开始 + * @param endPos 结束位置 + * @return + */ + public byte[] read(int startPos,int endPos) throws IOException; + /** + * 得到数据内容的长度 + * @return + */ + public int getContentLength(); + + /** + * 关闭连接 + */ + public void close(); +} diff --git a/group19/972815123/src/com/download/api/ConnectionException.java b/group19/972815123/src/com/download/api/ConnectionException.java new file mode 100644 index 0000000000..1551a80b3d --- /dev/null +++ b/group19/972815123/src/com/download/api/ConnectionException.java @@ -0,0 +1,5 @@ +package com.coderising.download.api; + +public class ConnectionException extends Exception { + +} diff --git a/group19/972815123/src/com/download/api/ConnectionManager.java b/group19/972815123/src/com/download/api/ConnectionManager.java new file mode 100644 index 0000000000..ce045393b1 --- /dev/null +++ b/group19/972815123/src/com/download/api/ConnectionManager.java @@ -0,0 +1,10 @@ +package com.coderising.download.api; + +public interface ConnectionManager { + /** + * 给定一个url , 打开一个连接 + * @param url + * @return + */ + public Connection open(String url) throws ConnectionException; +} diff --git a/group19/972815123/src/com/download/api/DownloadListener.java b/group19/972815123/src/com/download/api/DownloadListener.java new file mode 100644 index 0000000000..bf9807b307 --- /dev/null +++ b/group19/972815123/src/com/download/api/DownloadListener.java @@ -0,0 +1,5 @@ +package com.coderising.download.api; + +public interface DownloadListener { + public void notifyFinished(); +} diff --git a/group19/972815123/src/com/download/impl/ConnectionImpl.java b/group19/972815123/src/com/download/impl/ConnectionImpl.java new file mode 100644 index 0000000000..46c5aaf387 --- /dev/null +++ b/group19/972815123/src/com/download/impl/ConnectionImpl.java @@ -0,0 +1,46 @@ +package com.coderising.download.impl; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URLConnection; + +import com.coderising.download.api.Connection; + +public class ConnectionImpl implements Connection{ + + private URLConnection connect; + public void setHttpURLConnection(URLConnection conn){ + this.connect = conn; + this.connect.setRequestProperty("Connection", "Keep-Alive"); + } + + @Override + public byte[] read(int startPos, int endPos) throws IOException { + + InputStream is = connect.getInputStream(); + is.skip(startPos); + + byte[] buffer = new byte[1024]; + int hasRead = 0; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + while(startPos < endPos && (hasRead = is.read(buffer, 0, 1024)) != -1){ + out.write(buffer, 0, hasRead); + startPos += hasRead; + } + + byte[] result = out.toByteArray(); + return result; + } + + @Override + public int getContentLength() { + return connect.getContentLength(); + } + + @Override + public void close() { + } + +} diff --git a/group19/972815123/src/com/download/impl/ConnectionManagerImpl.java b/group19/972815123/src/com/download/impl/ConnectionManagerImpl.java new file mode 100644 index 0000000000..7f16a4d1cd --- /dev/null +++ b/group19/972815123/src/com/download/impl/ConnectionManagerImpl.java @@ -0,0 +1,28 @@ +package com.coderising.download.impl; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; + +import com.coderising.download.api.Connection; +import com.coderising.download.api.ConnectionException; +import com.coderising.download.api.ConnectionManager; + +public class ConnectionManagerImpl implements ConnectionManager { + + @Override + public Connection open(String url) throws ConnectionException { + try { + URL u = new URL(url); + URLConnection conn = u.openConnection(); + ConnectionImpl connection = new ConnectionImpl(); + connection.setHttpURLConnection(conn); + return connection; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } +} From b7c11cec17f199b79802cfcefa4a3a789f945a40 Mon Sep 17 00:00:00 2001 From: x_zhaohu Date: Thu, 23 Mar 2017 23:32:15 +0800 Subject: [PATCH 011/203] =?UTF-8?q?=E5=B7=A5=E4=BD=9C=E6=B5=81=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group11/1178243325/week01/build.gradle | 9 + group11/1178243325/week01/readme.md | 15 ++ .../main/java/com/sprint/basic/Iterator.java | 6 + .../ConcurrentModificationException.java | 9 + .../basic/exception/EmptyQueueException.java | 8 + .../basic/exception/EmptyStackException.java | 8 + .../java/com/sprint/basic/list/ArrayList.java | 99 +++++++++++ .../com/sprint/basic/list/LinkedList.java | 160 ++++++++++++++++++ .../main/java/com/sprint/basic/list/List.java | 10 ++ .../java/com/sprint/basic/queue/Queue.java | 32 ++++ .../java/com/sprint/basic/stack/Stack.java | 40 +++++ .../com/sprint/basic/tree/BinaryTreeNode.java | 122 +++++++++++++ .../com/sprint/basic/list/ArrayListTest.java | 56 ++++++ .../com/sprint/basic/list/LinkedListTest.java | 56 ++++++ .../com/sprint/basic/queue/QueueTest.java | 20 +++ .../com/sprint/basic/stack/StackTest.java | 23 +++ .../sprint/basic/tree/BinaryTreeNodeTest.java | 54 ++++++ 17 files changed, 727 insertions(+) create mode 100644 group11/1178243325/week01/build.gradle create mode 100644 group11/1178243325/week01/readme.md create mode 100644 group11/1178243325/week01/src/main/java/com/sprint/basic/Iterator.java create mode 100644 group11/1178243325/week01/src/main/java/com/sprint/basic/exception/ConcurrentModificationException.java create mode 100644 group11/1178243325/week01/src/main/java/com/sprint/basic/exception/EmptyQueueException.java create mode 100644 group11/1178243325/week01/src/main/java/com/sprint/basic/exception/EmptyStackException.java create mode 100644 group11/1178243325/week01/src/main/java/com/sprint/basic/list/ArrayList.java create mode 100644 group11/1178243325/week01/src/main/java/com/sprint/basic/list/LinkedList.java create mode 100644 group11/1178243325/week01/src/main/java/com/sprint/basic/list/List.java create mode 100644 group11/1178243325/week01/src/main/java/com/sprint/basic/queue/Queue.java create mode 100644 group11/1178243325/week01/src/main/java/com/sprint/basic/stack/Stack.java create mode 100644 group11/1178243325/week01/src/main/java/com/sprint/basic/tree/BinaryTreeNode.java create mode 100644 group11/1178243325/week01/src/test/java/com/sprint/basic/list/ArrayListTest.java create mode 100644 group11/1178243325/week01/src/test/java/com/sprint/basic/list/LinkedListTest.java create mode 100644 group11/1178243325/week01/src/test/java/com/sprint/basic/queue/QueueTest.java create mode 100644 group11/1178243325/week01/src/test/java/com/sprint/basic/stack/StackTest.java create mode 100644 group11/1178243325/week01/src/test/java/com/sprint/basic/tree/BinaryTreeNodeTest.java diff --git a/group11/1178243325/week01/build.gradle b/group11/1178243325/week01/build.gradle new file mode 100644 index 0000000000..50d1380b3f --- /dev/null +++ b/group11/1178243325/week01/build.gradle @@ -0,0 +1,9 @@ +apply plugin: 'java' + +repositories { + mavenCentral(); +} + +dependencies { + testCompile("junit:junit:4.12") +} diff --git a/group11/1178243325/week01/readme.md b/group11/1178243325/week01/readme.md new file mode 100644 index 0000000000..61c31c1c9c --- /dev/null +++ b/group11/1178243325/week01/readme.md @@ -0,0 +1,15 @@ +####讲课内容: +- 17-2-15: 社群kickoff +- 17-2-19:讲解Java自测题和基本数据结构 +- 17-2-22:计算机组成原理和计算机编程语言 +- 17-2-26:程序的机器级表示 + +####第一周作业(2-15 至 2-26) +- 实现各种基本数据结构(ArrayList, Stack, LinkedList, Queue, Tree, Iterator) +- 写一篇介绍CPU,内存,硬盘,指令以及他们之间的关系 + +####完成情况: +- 除了Tree未完成,其余都基本实现 +- 文章地址 + +####我的收获: diff --git a/group11/1178243325/week01/src/main/java/com/sprint/basic/Iterator.java b/group11/1178243325/week01/src/main/java/com/sprint/basic/Iterator.java new file mode 100644 index 0000000000..1e73a2a4b9 --- /dev/null +++ b/group11/1178243325/week01/src/main/java/com/sprint/basic/Iterator.java @@ -0,0 +1,6 @@ +package com.sprint.basic; + +public interface Iterator { + public boolean hasNext(); + public Object next(); +} diff --git a/group11/1178243325/week01/src/main/java/com/sprint/basic/exception/ConcurrentModificationException.java b/group11/1178243325/week01/src/main/java/com/sprint/basic/exception/ConcurrentModificationException.java new file mode 100644 index 0000000000..c91c388bbd --- /dev/null +++ b/group11/1178243325/week01/src/main/java/com/sprint/basic/exception/ConcurrentModificationException.java @@ -0,0 +1,9 @@ +package com.sprint.basic.exception; + +public class ConcurrentModificationException extends RuntimeException { + public ConcurrentModificationException() {} + public ConcurrentModificationException(String msg) { + super(msg); + } +} + diff --git a/group11/1178243325/week01/src/main/java/com/sprint/basic/exception/EmptyQueueException.java b/group11/1178243325/week01/src/main/java/com/sprint/basic/exception/EmptyQueueException.java new file mode 100644 index 0000000000..ddf89ac120 --- /dev/null +++ b/group11/1178243325/week01/src/main/java/com/sprint/basic/exception/EmptyQueueException.java @@ -0,0 +1,8 @@ +package com.sprint.basic.exception; + +public class EmptyQueueException extends RuntimeException { + public EmptyQueueException() {} + public EmptyQueueException(String msg) { + super(msg); + } +} diff --git a/group11/1178243325/week01/src/main/java/com/sprint/basic/exception/EmptyStackException.java b/group11/1178243325/week01/src/main/java/com/sprint/basic/exception/EmptyStackException.java new file mode 100644 index 0000000000..d654c7cd16 --- /dev/null +++ b/group11/1178243325/week01/src/main/java/com/sprint/basic/exception/EmptyStackException.java @@ -0,0 +1,8 @@ +package com.sprint.basic.exception; + +public class EmptyStackException extends RuntimeException { + public EmptyStackException() {} + public EmptyStackException(String msg) { + super(msg); + } +} diff --git a/group11/1178243325/week01/src/main/java/com/sprint/basic/list/ArrayList.java b/group11/1178243325/week01/src/main/java/com/sprint/basic/list/ArrayList.java new file mode 100644 index 0000000000..fb64e93f36 --- /dev/null +++ b/group11/1178243325/week01/src/main/java/com/sprint/basic/list/ArrayList.java @@ -0,0 +1,99 @@ +package com.sprint.basic.list; + +import com.sprint.basic.exception.ConcurrentModificationException; +import com.sprint.basic.Iterator; +public class ArrayList implements List { + + private int size; + private Object[] elementData; + + public ArrayList () { + size = 0; + elementData = new Object[100]; + } + + public boolean add(Object o) { + add(size(), o); + return true; + } + + public boolean add(int index, Object o){ + if (size() == elementData.length) + ensureCapacity( size() * 2 + 1); + if (index > size() || index < 0) { //index == size时相当于在尾后插入 + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + } + for (int i = size; i > index; i--) { + elementData[i] = elementData[i-1]; + } + elementData[index] = o; + size++; + return true; + } + + private void ensureCapacity(int newCapacity) { + if (newCapacity < size()) + return; + Object[] old = elementData; + elementData = new Object[newCapacity]; + for (int i = 0; i < size(); i++) { + elementData[i] = old[i]; + } + } + + public Object get(int index){ + if (index >= size() || index < 0) { //获取时,index==size()越界 + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + } + return elementData[index]; + } + + private String outOfBoundsMsg(int index) { + return "Index:" + index + ", Size:" + size; + } + + public Object remove(int index){ + if (index >= size() || index < 0) { + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + } + Object old = elementData[index]; + for (int i = index; i < size(); i++) { + elementData[i] = elementData[i+1]; + } + size--; + return old; + } + + /*获取表内容量*/ + public int size(){ + return size; + } + + public Iterator iterator(){ + return new ArrayListIterator(); + } + + public class ArrayListIterator implements Iterator { + private final int ONLY_CAPACITY = size; + private int index; + public ArrayListIterator() { + index = 0; + } + + @Override + public boolean hasNext() { + if (ONLY_CAPACITY != size) + throw new ConcurrentModificationException("此对象没有进行修改同步"); + return index != size; + } + + @Override + public Object next() { + if (ONLY_CAPACITY != size) + throw new ConcurrentModificationException("此对象没有进行修改同步"); + if (index >= ONLY_CAPACITY) + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + return elementData[index++]; + } + } +} diff --git a/group11/1178243325/week01/src/main/java/com/sprint/basic/list/LinkedList.java b/group11/1178243325/week01/src/main/java/com/sprint/basic/list/LinkedList.java new file mode 100644 index 0000000000..503f41f65b --- /dev/null +++ b/group11/1178243325/week01/src/main/java/com/sprint/basic/list/LinkedList.java @@ -0,0 +1,160 @@ +package com.sprint.basic.list; + +import com.sprint.basic.exception.ConcurrentModificationException; +import com.sprint.basic.Iterator; +import java.util.Objects; +public class LinkedList implements List { + + private Node head; + private int size; + public LinkedList() { + head = new Node(null, null); + size = 0; + } + + public boolean add(Object o) { + add(size, o); + return true; + } + + public boolean add(int index , Object o) { + if (index > size || index < 0) { + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + } + Node frontNode = getNode(index-1); + Node newNode = new Node(o, frontNode.next); + frontNode.next = newNode; + size++; + return true; + } + + /*getNode getPreNodeByElement getNextNodeByElement的效率低些*/ + private Node getNode(int index) { + Node node = head; + int i = 0; + while(node.next != null && i <= index) { + node = node.next; + i++; + } + return node; + } + + private Node getPreNodeByElement(Object obj) { + if (obj != null) { + for (int i = 0; i < size(); i++) { + if (getNode(i).data == obj) { + return getNode(i-1); + } + } + } + return null; + } + + private Node getNextNodeByElement(Object obj) { + if (obj != null) { + for (int i = 0; i < size(); i++) { + if (getNode(i).data == obj) { + return getNode(i+1); + } + } + } + return null; + } + + public Object get(int index){ + if (index >= size || index < 0) { + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + } + + Node node = getNode(index); + return node.data; + } + + public Object remove(int index){ + if (index >= size || index < 0) { + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + } + Node frontNode = getNode(index-1); + Node oldNode = getNode(index); + frontNode.next = oldNode.next; + size--; + return oldNode.data; + } + + public int size(){ + return size; + } + + public void addFirst(Object o){ + add(0, o); + } + + public void addLast(Object o){ + add(size, o); + } + + public Object removeFirst(){ + return remove(0); + } + + public Object removeLast(){ + return remove(size-1); + } + + public Iterator iterator(){ + return new LinkedListIterator(); + } + + private class LinkedListIterator implements Iterator { + int index; + final int capacity = size; + LinkedListIterator() { + index = 0; + } + @Override + public boolean hasNext() { + if (capacity != size) + throw new ConcurrentModificationException("此对象没有修改同步"); + return index < capacity; + } + + @Override + public Object next() { + if (capacity != size) + throw new ConcurrentModificationException("此对象没有修改同步"); + if (index >= capacity) + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + return get(index++); + } + } + + private String outOfBoundsMsg(int index) { + return "index:" + index + ", size:" + size; + } + + private static class Node { + Object data; + Node next; + + Node(Object data, Node next) { + this.data = data; + this.next = next; + } + + void setData(Object data) { + this.data = data; + } + + Object getData() { + return data; + } + + void setNext(Node next) { + this.next = next; + } + + Object getNext() { + return next; + } + } +} diff --git a/group11/1178243325/week01/src/main/java/com/sprint/basic/list/List.java b/group11/1178243325/week01/src/main/java/com/sprint/basic/list/List.java new file mode 100644 index 0000000000..0e90471a48 --- /dev/null +++ b/group11/1178243325/week01/src/main/java/com/sprint/basic/list/List.java @@ -0,0 +1,10 @@ +package com.sprint.basic.list; +import com.sprint.basic.Iterator; +public interface List { + public boolean add(Object o); + public boolean add(int index, Object o); + public Object get(int index); + public Object remove(int index); + public int size(); + public Iterator iterator(); +} diff --git a/group11/1178243325/week01/src/main/java/com/sprint/basic/queue/Queue.java b/group11/1178243325/week01/src/main/java/com/sprint/basic/queue/Queue.java new file mode 100644 index 0000000000..47f7b98d96 --- /dev/null +++ b/group11/1178243325/week01/src/main/java/com/sprint/basic/queue/Queue.java @@ -0,0 +1,32 @@ +package com.sprint.basic.queue; +import com.sprint.basic.exception.EmptyQueueException; +import com.sprint.basic.list.LinkedList; +public class Queue { + + private LinkedList elementData; + + public Queue() { + elementData = new LinkedList(); + } + + public boolean enQueue(Object o){ + elementData.addLast(o); + return true; + } + + public Object deQueue(){ + if (isEmpty()) { + throw new EmptyQueueException("队空"); + } + Object result = elementData.removeFirst(); + return result; + } + + public boolean isEmpty(){ + return elementData.size() == 0; + } + + public int size(){ + return elementData.size(); + } +} diff --git a/group11/1178243325/week01/src/main/java/com/sprint/basic/stack/Stack.java b/group11/1178243325/week01/src/main/java/com/sprint/basic/stack/Stack.java new file mode 100644 index 0000000000..e399dcb850 --- /dev/null +++ b/group11/1178243325/week01/src/main/java/com/sprint/basic/stack/Stack.java @@ -0,0 +1,40 @@ +package com.sprint.basic.stack; + +import com.sprint.basic.exception.EmptyStackException; +import com.sprint.basic.list.ArrayList; +public class Stack { + + private ArrayList elementData; + public Stack() { + elementData = new ArrayList(); + } + + public boolean push(Object o){ + elementData.add(o); + return true; + } + + public Object pop(){ + if (isEmpty()) { + throw new EmptyStackException("栈空"); + } + Object result = elementData.get(size()-1); + elementData.remove(size()-1); + return result; + } + + public Object peek(){ + if (isEmpty()) { + throw new EmptyStackException("栈空"); + } + return elementData.get(0); + } + + public boolean isEmpty(){ + return elementData.size() == 0; + } + + public int size(){ + return elementData.size(); + } +} diff --git a/group11/1178243325/week01/src/main/java/com/sprint/basic/tree/BinaryTreeNode.java b/group11/1178243325/week01/src/main/java/com/sprint/basic/tree/BinaryTreeNode.java new file mode 100644 index 0000000000..efaf261521 --- /dev/null +++ b/group11/1178243325/week01/src/main/java/com/sprint/basic/tree/BinaryTreeNode.java @@ -0,0 +1,122 @@ +package com.sprint.basic.tree; + +public class BinaryTreeNode { + + private T data; + private BinaryTreeNode left; + private BinaryTreeNode right; + private int size; + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } + + public BinaryTreeNode getLeft() { + return left; + } + + public void setLeft(BinaryTreeNode left) { + this.left = left; + } + + public BinaryTreeNode getRight() { + return right; + } + + public void setRight(BinaryTreeNode right) { + this.right = right; + } + + public BinaryTreeNode insert(T data) { + if (this.data == null) { + this.data = data; + return this; + } + int compareResult = this.data.compareTo(data); + if (compareResult > 0) { + if (this.left == null) { + this.left = new BinaryTreeNode(); + this.left.data = data; + return this.left; + } else { + return this.left.insert(data); + } + } else if (compareResult < 0) { + if (this.right == null) { + this.right = new BinaryTreeNode(); + this.right.data = data; + return this.right; + } else { + return this.right.insert(data); + } + } else { + return this; + } + } + + /*没看懂*/ + public BinaryTreeNode delete(T data) { + BinaryTreeNode treeNode = search(data); + if (treeNode == null) { + return null; + } + int compareResult = this.data.compareTo(data); + if (compareResult > 0) { + return this.left.delete(data); + } else if (compareResult < 0) { + return this.right.delete(data); + } else { + if (treeNode.right == null) { + if (this.left == null) { + this.data = null; + } else { + this.left = this; + } + } else { + this.data = (T) this.right.findMin().data; + + this.right.delete(this.data); + } + } + + return this; + } + + private BinaryTreeNode findMin() { + if (this.data == null) { + return null; + } + if (this.left == null) { + return this; + } + return this.left.findMin(); + } + + public BinaryTreeNode search(T data) { + if (this.data == null) { + return null; + } + int compareResult = this.data.compareTo(data); + if (compareResult > 0) { + if (this.left == null) { + return null; + } else { + return this.left.search(data); + } + } else if (compareResult < 0) { + if (this.right == null) { + return null; + } else { + return this.right.search(data); + } + } else { + return this; + } + } + + +} diff --git a/group11/1178243325/week01/src/test/java/com/sprint/basic/list/ArrayListTest.java b/group11/1178243325/week01/src/test/java/com/sprint/basic/list/ArrayListTest.java new file mode 100644 index 0000000000..63936c288c --- /dev/null +++ b/group11/1178243325/week01/src/test/java/com/sprint/basic/list/ArrayListTest.java @@ -0,0 +1,56 @@ +package com.sprint.basic.list; + +import com.sprint.basic.Iterator; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class ArrayListTest { + private List list; + + @Before + public void init() { + list = new ArrayList(); + } + + @Test + public void add() { + for (int i = 0; i < 5; i++) { + list.add(i); + } + /*Assert.assertTrue(args): if (args != true) to failed*/ + System.out.println(list); + Assert.assertTrue(list.add(5)); + Assert.assertEquals(6, list.size()); + Assert.assertTrue(list.add(3, 10)); + Assert.assertEquals(7, list.size()); + + } + + @Test + public void remove() { + add(); + Assert.assertEquals(5, list.remove(6)); + Assert.assertEquals(6, list.size()); + } + + @Test + public void get() { + add(); + Assert.assertEquals(5, list.get(6)); + } + + @Test + public void testIterator() { + for (int i = 0; i < 10; i++) { + Assert.assertTrue(list.add(i)); + } + Iterator iter = list.iterator(); + int count = 0; + while(iter.hasNext()) { + Assert.assertEquals(count, iter.next()); + count++; + } + } + +} diff --git a/group11/1178243325/week01/src/test/java/com/sprint/basic/list/LinkedListTest.java b/group11/1178243325/week01/src/test/java/com/sprint/basic/list/LinkedListTest.java new file mode 100644 index 0000000000..c5ab12aa4e --- /dev/null +++ b/group11/1178243325/week01/src/test/java/com/sprint/basic/list/LinkedListTest.java @@ -0,0 +1,56 @@ +package com.sprint.basic.list; + +import com.sprint.basic.Iterator; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class LinkedListTest { + private List list; + + @Before + public void init() { + list = new LinkedList(); + } + + @Test + public void add() { + for (int i = 0; i < 5; i++) { + list.add(i); + } + /*Assert.assertTrue(args): if (args != true) to failed*/ + System.out.println(list); + Assert.assertTrue(list.add(5)); + Assert.assertEquals(6, list.size()); + Assert.assertTrue(list.add(3, 10)); + Assert.assertEquals(7, list.size()); + + } + + @Test + public void remove() { + add(); + Assert.assertEquals(5, list.remove(6)); + Assert.assertEquals(6, list.size()); + } + + @Test + public void get() { + add(); + Assert.assertEquals(5, list.get(6)); + } + + @Test + public void testIterator() { + for (int i = 0; i < 10; i++) { + Assert.assertTrue(list.add(i)); + } + Iterator iter = list.iterator(); + int count = 0; + while(iter.hasNext()) { + Assert.assertEquals(count, iter.next()); + count++; + } + } + +} diff --git a/group11/1178243325/week01/src/test/java/com/sprint/basic/queue/QueueTest.java b/group11/1178243325/week01/src/test/java/com/sprint/basic/queue/QueueTest.java new file mode 100644 index 0000000000..b7cfe4b32f --- /dev/null +++ b/group11/1178243325/week01/src/test/java/com/sprint/basic/queue/QueueTest.java @@ -0,0 +1,20 @@ +package com.sprint.basic.queue; + +import org.junit.Assert; +import org.junit.Test; +public class QueueTest { + + private Queue queue = new Queue(); + + @Test + public void testQueueApi() { + Assert.assertTrue(queue.enQueue(1)); + Assert.assertTrue(queue.enQueue(2)); + Assert.assertFalse(queue.isEmpty()); + Assert.assertEquals(2, queue.size()); + Assert.assertEquals(1, queue.deQueue()); + Assert.assertEquals(2, queue.deQueue()); + Assert.assertEquals(0, queue.size()); + Assert.assertTrue(queue.isEmpty()); + } +} diff --git a/group11/1178243325/week01/src/test/java/com/sprint/basic/stack/StackTest.java b/group11/1178243325/week01/src/test/java/com/sprint/basic/stack/StackTest.java new file mode 100644 index 0000000000..e267c59971 --- /dev/null +++ b/group11/1178243325/week01/src/test/java/com/sprint/basic/stack/StackTest.java @@ -0,0 +1,23 @@ +package com.sprint.basic.stack; + +import org.junit.Assert; +import org.junit.Test; + +public class StackTest { + + private Stack stack = new Stack(); + + @Test + public void testStack() { + Assert.assertTrue(stack.push(1)); + Assert.assertEquals(1, stack.pop()); + Assert.assertTrue(stack.push(2)); + Assert.assertTrue(stack.push(3)); + Assert.assertTrue(stack.push(4)); + Assert.assertEquals(4, stack.pop()); + Assert.assertEquals(2, stack.peek()); + Assert.assertEquals(2, stack.size()); + Assert.assertFalse(stack.isEmpty()); + } + +} diff --git a/group11/1178243325/week01/src/test/java/com/sprint/basic/tree/BinaryTreeNodeTest.java b/group11/1178243325/week01/src/test/java/com/sprint/basic/tree/BinaryTreeNodeTest.java new file mode 100644 index 0000000000..d9a27ab211 --- /dev/null +++ b/group11/1178243325/week01/src/test/java/com/sprint/basic/tree/BinaryTreeNodeTest.java @@ -0,0 +1,54 @@ +package com.sprint.basic.tree; + +import org.junit.Assert; +/*参考程序*/ +public class BinaryTreeNodeTest { + + private BinaryTreeNode treeNode; + + @org.junit.Before + public void setUp() throws Exception { + treeNode = new BinaryTreeNode<>(); + treeNode.insert(5); + treeNode.insert(3); + treeNode.insert(7); + treeNode.insert(1); + treeNode.insert(4); + treeNode.insert(2); + treeNode.insert(8); + treeNode.insert(6); + } + + @org.junit.Test + public void insert() { + Assert.assertEquals(treeNode.getData().intValue(), 5); + Assert.assertEquals(treeNode.getLeft().getData(), 3); + Assert.assertEquals(treeNode.getRight().getData(), 7); + Assert.assertEquals(treeNode.getLeft().getLeft().getData(), 1); + Assert.assertEquals(treeNode.getLeft().getRight().getData(), 4); + Assert.assertEquals(treeNode.getLeft().getLeft().getRight().getData(), 2); + Assert.assertEquals(treeNode.getRight().getRight().getData(), 8); + Assert.assertEquals(treeNode.getRight().getLeft().getData(), 6); + } + + @org.junit.Test + public void delete() throws Exception { + treeNode.delete(3); + for (int i = 1; i < 9; i++) { + if (i != 3) { + Assert.assertNotNull(treeNode.search(i)); + } else { + Assert.assertNull(treeNode.search(i)); + } + } + } + + @org.junit.Test + public void search() throws Exception { + for (int i = 1; i < 9; i++) { + Assert.assertNotNull(treeNode.search(i)); + } + Assert.assertNull(treeNode.search(0)); + Assert.assertNull(treeNode.search(9)); + } +} From dfa576a2a857e35729c018e07a12cfdbe668fb5a Mon Sep 17 00:00:00 2001 From: x_zhaohu Date: Fri, 24 Mar 2017 08:47:05 +0800 Subject: [PATCH 012/203] update format --- group11/1178243325/week01/readme.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/group11/1178243325/week01/readme.md b/group11/1178243325/week01/readme.md index 61c31c1c9c..8d0e6f12a2 100644 --- a/group11/1178243325/week01/readme.md +++ b/group11/1178243325/week01/readme.md @@ -1,15 +1,15 @@ -####讲课内容: +## 讲课内容: - 17-2-15: 社群kickoff - 17-2-19:讲解Java自测题和基本数据结构 - 17-2-22:计算机组成原理和计算机编程语言 - 17-2-26:程序的机器级表示 -####第一周作业(2-15 至 2-26) +## 第一周作业(2-15 至 2-26) - 实现各种基本数据结构(ArrayList, Stack, LinkedList, Queue, Tree, Iterator) - 写一篇介绍CPU,内存,硬盘,指令以及他们之间的关系 -####完成情况: +## 完成情况: - 除了Tree未完成,其余都基本实现 - 文章地址 -####我的收获: +## 我的收获: From 12b5c8d5adb4b54a66fe0fb3748c239340e9cbfa Mon Sep 17 00:00:00 2001 From: James <1310368322@qq.com> Date: Fri, 24 Mar 2017 12:18:57 +0800 Subject: [PATCH 013/203] Third_Homework --- .../BaseDataStructure}/ArrayList.java | 0 .../BaseDataStructure}/LinkedList.java | 0 .../BaseDataStructure}/ArrayUtil.java | 0 .../BaseDataStructure/LinkedList.java | 162 ++++++++++++++++++ .../Download/DownloadThread.java | 0 .../Download/FileDownloader.java | 0 .../Download/api/Connection.java | 0 .../Download/api/ConnectionException.java | 0 .../Download/api/ConnectionManager.java | 0 .../Download/api/DownloadListener.java | 0 .../Download/impl/ConnectionImpl.java | 0 .../Download/impl/ConnectionManagerImpl.java | 0 .../BaseDataStructure}/ArrayUtilTest.java | 0 .../BaseDataStructure/TestLinkedList.java | 25 +++ .../Download}/FileDownloaderTest.java | 0 15 files changed, 187 insertions(+) rename group11/1310368322/src/{ => FirstHomework/BaseDataStructure}/ArrayList.java (100%) rename group11/1310368322/src/{ => FirstHomework/BaseDataStructure}/LinkedList.java (100%) rename group11/1310368322/src/{ => SecondHomework/BaseDataStructure}/ArrayUtil.java (100%) create mode 100644 group11/1310368322/src/ThirdHomework/BaseDataStructure/LinkedList.java rename group11/1310368322/src/{ => ThirdHomework}/Download/DownloadThread.java (100%) rename group11/1310368322/src/{ => ThirdHomework}/Download/FileDownloader.java (100%) rename group11/1310368322/src/{ => ThirdHomework}/Download/api/Connection.java (100%) rename group11/1310368322/src/{ => ThirdHomework}/Download/api/ConnectionException.java (100%) rename group11/1310368322/src/{ => ThirdHomework}/Download/api/ConnectionManager.java (100%) rename group11/1310368322/src/{ => ThirdHomework}/Download/api/DownloadListener.java (100%) rename group11/1310368322/src/{ => ThirdHomework}/Download/impl/ConnectionImpl.java (100%) rename group11/1310368322/src/{ => ThirdHomework}/Download/impl/ConnectionManagerImpl.java (100%) rename group11/1310368322/test/{ => SecondHomwork/BaseDataStructure}/ArrayUtilTest.java (100%) create mode 100644 group11/1310368322/test/ThirdHomework/BaseDataStructure/TestLinkedList.java rename group11/1310368322/test/{ => ThirdHomework/Download}/FileDownloaderTest.java (100%) diff --git a/group11/1310368322/src/ArrayList.java b/group11/1310368322/src/FirstHomework/BaseDataStructure/ArrayList.java similarity index 100% rename from group11/1310368322/src/ArrayList.java rename to group11/1310368322/src/FirstHomework/BaseDataStructure/ArrayList.java diff --git a/group11/1310368322/src/LinkedList.java b/group11/1310368322/src/FirstHomework/BaseDataStructure/LinkedList.java similarity index 100% rename from group11/1310368322/src/LinkedList.java rename to group11/1310368322/src/FirstHomework/BaseDataStructure/LinkedList.java diff --git a/group11/1310368322/src/ArrayUtil.java b/group11/1310368322/src/SecondHomework/BaseDataStructure/ArrayUtil.java similarity index 100% rename from group11/1310368322/src/ArrayUtil.java rename to group11/1310368322/src/SecondHomework/BaseDataStructure/ArrayUtil.java diff --git a/group11/1310368322/src/ThirdHomework/BaseDataStructure/LinkedList.java b/group11/1310368322/src/ThirdHomework/BaseDataStructure/LinkedList.java new file mode 100644 index 0000000000..5ea6a988be --- /dev/null +++ b/group11/1310368322/src/ThirdHomework/BaseDataStructure/LinkedList.java @@ -0,0 +1,162 @@ +package DataStructure_3; + +import java.util.Stack; + +import DataStructure_1.LinkedList.Node; + +public class LinkedList { + private Node head; + static int size = 0; + public void add(Object o){ + if(null == head){ + head = new Node(); + head.data = o; + head.next = null; + }else{ + Node p = head; + while(null != p.next){ + p = p.next; + } + Node newNode = new Node(); + newNode.data = o; + p.next = newNode; + newNode.next =null; + } + size++; + } + public int size(){ + return size; + } + public void add(int index,Object o){ + if(index < 0){ + throw new RuntimeException("�±겻��Ϊ����"); + } + if(index == 0){ + addFirst(o); + size++; + return; + } + if(index > size){ + throw new RuntimeException(""); + } + int i = 0; + Node p = head; + Node q = null; + + while(i!=index){ + q = p; + p = p.next; + i++; + } + Node r = new Node(); + r.data = o; + r.next =null; + q.next = r; + r.next = p; + size++; + return; + } + + public Object get(int index){ + int i = 0; + Node p = head; + while(i != index){ + p = p.next; + i++; + } + return p.data; + } + public Object remove(int index){ + if(index < 0){ + throw new RuntimeException("�±겻��Ϊ����"); + } + if(index == 1){ + size--; + return head.data; + } + int i = 0; + Node p = head; + Node q = null; + while(i != index){ + q = p; + p = p.next; + i++; + } + q.next = p.next; + size--; + return p.data; + } + public void addFirst(Object o){ + Node p = new Node(); + p.next = head; + p.data = o; + head = p; + size++; + } + public Object removeFirst(){ + head = head.next; + size--; + return null; + } + public static class Node{ + Object data; + Node next; + } + + /** + * �Ѹ��������� + * �������� 3->7->10 �����ú��Ϊ 10->7->3 + */ + public void reverse(){ + if(null == head || null == head.next){ + return; + } + Stack s = new Stack(); + Node curNode = head; + while(curNode != null){ + s.push(curNode); + Node nextNode = curNode.next; + curNode.next = null; // �����Ͽ������� + curNode = nextNode; + } + + head = s.pop(); + curNode = head; + while(!s.isEmpty()){ + Node nextNode = s.pop(); + curNode.next = nextNode; + curNode = nextNode; + } + + } + + public String toString(){ + StringBuffer buffer = new StringBuffer(); + buffer.append("["); + Node node = head; + while(node != null){ + buffer.append(node.data); + if(node.next != null){ + buffer.append(","); + } + node = node.next; + } + buffer.append("]"); + return buffer.toString(); + } + + + + + + + + + + + + + + + +} diff --git a/group11/1310368322/src/Download/DownloadThread.java b/group11/1310368322/src/ThirdHomework/Download/DownloadThread.java similarity index 100% rename from group11/1310368322/src/Download/DownloadThread.java rename to group11/1310368322/src/ThirdHomework/Download/DownloadThread.java diff --git a/group11/1310368322/src/Download/FileDownloader.java b/group11/1310368322/src/ThirdHomework/Download/FileDownloader.java similarity index 100% rename from group11/1310368322/src/Download/FileDownloader.java rename to group11/1310368322/src/ThirdHomework/Download/FileDownloader.java diff --git a/group11/1310368322/src/Download/api/Connection.java b/group11/1310368322/src/ThirdHomework/Download/api/Connection.java similarity index 100% rename from group11/1310368322/src/Download/api/Connection.java rename to group11/1310368322/src/ThirdHomework/Download/api/Connection.java diff --git a/group11/1310368322/src/Download/api/ConnectionException.java b/group11/1310368322/src/ThirdHomework/Download/api/ConnectionException.java similarity index 100% rename from group11/1310368322/src/Download/api/ConnectionException.java rename to group11/1310368322/src/ThirdHomework/Download/api/ConnectionException.java diff --git a/group11/1310368322/src/Download/api/ConnectionManager.java b/group11/1310368322/src/ThirdHomework/Download/api/ConnectionManager.java similarity index 100% rename from group11/1310368322/src/Download/api/ConnectionManager.java rename to group11/1310368322/src/ThirdHomework/Download/api/ConnectionManager.java diff --git a/group11/1310368322/src/Download/api/DownloadListener.java b/group11/1310368322/src/ThirdHomework/Download/api/DownloadListener.java similarity index 100% rename from group11/1310368322/src/Download/api/DownloadListener.java rename to group11/1310368322/src/ThirdHomework/Download/api/DownloadListener.java diff --git a/group11/1310368322/src/Download/impl/ConnectionImpl.java b/group11/1310368322/src/ThirdHomework/Download/impl/ConnectionImpl.java similarity index 100% rename from group11/1310368322/src/Download/impl/ConnectionImpl.java rename to group11/1310368322/src/ThirdHomework/Download/impl/ConnectionImpl.java diff --git a/group11/1310368322/src/Download/impl/ConnectionManagerImpl.java b/group11/1310368322/src/ThirdHomework/Download/impl/ConnectionManagerImpl.java similarity index 100% rename from group11/1310368322/src/Download/impl/ConnectionManagerImpl.java rename to group11/1310368322/src/ThirdHomework/Download/impl/ConnectionManagerImpl.java diff --git a/group11/1310368322/test/ArrayUtilTest.java b/group11/1310368322/test/SecondHomwork/BaseDataStructure/ArrayUtilTest.java similarity index 100% rename from group11/1310368322/test/ArrayUtilTest.java rename to group11/1310368322/test/SecondHomwork/BaseDataStructure/ArrayUtilTest.java diff --git a/group11/1310368322/test/ThirdHomework/BaseDataStructure/TestLinkedList.java b/group11/1310368322/test/ThirdHomework/BaseDataStructure/TestLinkedList.java new file mode 100644 index 0000000000..343f9d6f39 --- /dev/null +++ b/group11/1310368322/test/ThirdHomework/BaseDataStructure/TestLinkedList.java @@ -0,0 +1,25 @@ +package DataStructure_3; + +import static org.junit.Assert.*; +import org.junit.Assert; +import org.junit.Test; + +public class TestLinkedList { + + @Test + public void test() { + LinkedList L = new LinkedList(); + Assert.assertEquals("[]", L.toString()); + + L.add(1); + L.reverse(); + Assert.assertEquals("[1]", L.toString()); + + L.add(2); + L.add(3); + L.add(4); + L.reverse(); + Assert.assertEquals("[4,3,2,1]",L.toString()); + } + +} diff --git a/group11/1310368322/test/FileDownloaderTest.java b/group11/1310368322/test/ThirdHomework/Download/FileDownloaderTest.java similarity index 100% rename from group11/1310368322/test/FileDownloaderTest.java rename to group11/1310368322/test/ThirdHomework/Download/FileDownloaderTest.java From 63b87fa8b58cccb78ea661463c374ea200e3c0f3 Mon Sep 17 00:00:00 2001 From: James <1310368322@qq.com> Date: Fri, 24 Mar 2017 12:24:38 +0800 Subject: [PATCH 014/203] remove --- .../BaseDataStructure/ArrayList.java | 98 ----------- .../BaseDataStructure/LinkedList.java | 113 ------------ .../BaseDataStructure/ArrayUtil.java | 83 --------- .../BaseDataStructure/LinkedList.java | 162 ------------------ .../Download/DownloadThread.java | 39 ----- .../Download/FileDownloader.java | 114 ------------ .../Download/api/Connection.java | 22 --- .../Download/api/ConnectionException.java | 7 - .../Download/api/ConnectionManager.java | 10 -- .../Download/api/DownloadListener.java | 5 - .../Download/impl/ConnectionImpl.java | 73 -------- .../Download/impl/ConnectionManagerImpl.java | 16 -- 12 files changed, 742 deletions(-) delete mode 100644 group11/1310368322/src/FirstHomework/BaseDataStructure/ArrayList.java delete mode 100644 group11/1310368322/src/FirstHomework/BaseDataStructure/LinkedList.java delete mode 100644 group11/1310368322/src/SecondHomework/BaseDataStructure/ArrayUtil.java delete mode 100644 group11/1310368322/src/ThirdHomework/BaseDataStructure/LinkedList.java delete mode 100644 group11/1310368322/src/ThirdHomework/Download/DownloadThread.java delete mode 100644 group11/1310368322/src/ThirdHomework/Download/FileDownloader.java delete mode 100644 group11/1310368322/src/ThirdHomework/Download/api/Connection.java delete mode 100644 group11/1310368322/src/ThirdHomework/Download/api/ConnectionException.java delete mode 100644 group11/1310368322/src/ThirdHomework/Download/api/ConnectionManager.java delete mode 100644 group11/1310368322/src/ThirdHomework/Download/api/DownloadListener.java delete mode 100644 group11/1310368322/src/ThirdHomework/Download/impl/ConnectionImpl.java delete mode 100644 group11/1310368322/src/ThirdHomework/Download/impl/ConnectionManagerImpl.java diff --git a/group11/1310368322/src/FirstHomework/BaseDataStructure/ArrayList.java b/group11/1310368322/src/FirstHomework/BaseDataStructure/ArrayList.java deleted file mode 100644 index b5024f1dfb..0000000000 --- a/group11/1310368322/src/FirstHomework/BaseDataStructure/ArrayList.java +++ /dev/null @@ -1,98 +0,0 @@ -package Day_2017_2_26_FirstHomework; - -public class ArrayList { - - private static final int DEFAULT_SIZE = 10; - private static final int MAX_VALUE = 2147483647; - private Object[] elementData = new Object[DEFAULT_SIZE]; - private Exception Exception; - private int size = 0; - - public ArrayList(){ - this(DEFAULT_SIZE); - } - public ArrayList(int defaultSize) { - rangCheckForConstructor(defaultSize); - elementData = new Object[defaultSize]; - } - - - private void rangCheckForConstructor(int defaultSize) { - if(defaultSize<0 || defaultSize>MAX_VALUE){ - throw new IndexOutOfBoundsException("��ֵ������"); - } - - } - - public void add(Object o){ - ensureCapacity(); - for(int i = 0; i < elementData.length; i++){ - if(null == elementData[i]){ - elementData[i] = o; - break; - } - } - size++; - } - private void ensureCapacity() { - if(size>elementData.length){ - elementData = ArrayList.grow(elementData, 10); - } - } - public void add(int index, Object o){ - rangeCheckForAdd(index); - ensureCapacity(); - int k = -1; - for(int i = index; i < elementData.length; i++){ - if(null==elementData[i]){ - k = i-1; - break; - } - } - for(int i = k; i >= index;i--){ - elementData[i+1] = elementData[i]; - } - elementData[index] = o; - size++; - } - private void rangeCheckForAdd(int index) { - if(index < 0 || index > this.size){// add ��Ԫ��ֻ���� [0,size](���Ը�sizeλ�ò�Ԫ�أ��������Ը�size���Ԫ��) - throw new IndexOutOfBoundsException("�±�Խ��"); - } - - } - public Object get(int index){ - return elementData[index]; - } - - public Object remove(int index){ - while(true){ - elementData[index] = elementData[index+++1]; - if(elementData[index]==null){ - break; - } - } - size--; - return null; - } - public int size(){ - return -1; - } - public void getElementData(){ - for(int i = 0; i < elementData.length; i++){ - System.out.println(elementData[i]); - - } - } - public static Object[] grow(Object[] elementData2, int size){ - Object []target = new Object[elementData2.length+size]; - System.arraycopy(elementData2, 0, target, 0, elementData2.length); - return target; - } - - public static void main(String[] args) { - ArrayList a = new ArrayList(); - a.getElementData(); - System.out.println(a.size); - } -} diff --git a/group11/1310368322/src/FirstHomework/BaseDataStructure/LinkedList.java b/group11/1310368322/src/FirstHomework/BaseDataStructure/LinkedList.java deleted file mode 100644 index 488f2a22a6..0000000000 --- a/group11/1310368322/src/FirstHomework/BaseDataStructure/LinkedList.java +++ /dev/null @@ -1,113 +0,0 @@ -package Day_2017_2_26_FirstHomework; - -public class LinkedList{ - private Node head; - static int size = 0; - public void add(Object o){ - if(null == head){ - head = new Node(); - head.data = o; - head.next = null; - }else{ - Node p = head; - while(null != p.next){ - p = p.next; - } - Node newNode = new Node(); - newNode.data = o; - p.next = newNode; - newNode.next =null; - } - size++; - } - public int size(){ - return size; - } - public void add(int index,Object o){ - if(index < 0){ - throw new RuntimeException("�±겻��Ϊ����"); - } - if(index == 0){ - addFirst(o); - size++; - return; - } - if(index > size){ - throw new RuntimeException(""); - } - int i = 0; - Node p = head; - Node q = null; - - while(i!=index){ - q = p; - p = p.next; - i++; - } - Node r = new Node(); - r.data = o; - r.next =null; - q.next = r; - r.next = p; - size++; - return; - } - - public Object get(int index){ - int i = 0; - Node p = head; - while(i != index){ - p = p.next; - i++; - } - return p.data; - } - public Object remove(int index){ - if(index < 0){ - throw new RuntimeException("�±겻��Ϊ����"); - } - if(index == 1){ - size--; - return head.data; - } - int i = 0; - Node p = head; - Node q = null; - while(i != index){ - q = p; - p = p.next; - i++; - } - q.next = p.next; - size--; - return p.data; - } - public void addFirst(Object o){ - Node p = new Node(); - p.next = head; - p.data = o; - head = p; - size++; - } - public Object removeFirst(){ - head = head.next; - size--; - return null; - } - public static class Node{ - Object data; - Node next; - } - - public static void main(String[] args) { - LinkedList linkedList = new LinkedList(); - linkedList.add("a"); - linkedList.add("b"); - linkedList.add("c"); - linkedList.add("d"); - linkedList.add(5, "f"); - System.out.println(linkedList.get(5)); - System.out.println(linkedList.size()); - } - -} \ No newline at end of file diff --git a/group11/1310368322/src/SecondHomework/BaseDataStructure/ArrayUtil.java b/group11/1310368322/src/SecondHomework/BaseDataStructure/ArrayUtil.java deleted file mode 100644 index 81bc431679..0000000000 --- a/group11/1310368322/src/SecondHomework/BaseDataStructure/ArrayUtil.java +++ /dev/null @@ -1,83 +0,0 @@ -package day_2017_2_26_SecondHomework; - -import java.util.Arrays; - -import javax.management.RuntimeErrorException; - -public class ArrayUtil { - - /* * - * ����һ���������� a ���Ը������ֵ�����û� - * ���磺 a = [7, 9, 30, 3], �û���Ϊ [3, 30, 9, 7] - * */ - - /*public ArrayUtil(int[] a2) { - this.a = a2; - }*/ - public void reverseArray(int [] a){ - if(null == a){ - System.out.println("��ָ��----"); - return; - } - int temp; - int last = a.length-1; - for (int i = 0; i < a.length/2; i++) { - temp = a[i]; - a[i] = a[last]; - a[last--] = temp; - } - } - public void print(int [] a){ - if(null == a){ - System.out.println("��ָ��----"); - return; - } - for (int i = 0; i < a.length; i++) { - System.out.print(a[i] + " "); - } - System.out.println(); - } - - /* * - * ���������µ�һ�����飬 int oldArr[] = {1,3,4,5,0,0,6,6,0,5,4,7,6,7,0,5} - * Ҫ�����������е�ֵΪ 0 ����ȥ��������Ϊ 0 ��ֵ����һ���µ����飬���ɵ�������Ϊ�� - * {1,3,4,5,6,6,5,4,7,6,7,5} - * @param oldArray - * @return - */ - public int [] removeZero(int [] oldArray){ - if(null == oldArray){ - return null; - } - int count = 0; - int oldArrayLength = oldArray.length; - for(int i = 0; i < oldArrayLength;){ - if(oldArray[i]==0){ - for(int j = i; j < oldArrayLength -1; j++){ - oldArray[j] = oldArray[j+1]; - } - oldArrayLength--; - count++; - }else{ - i++; - } - } - int [] target = new int[oldArray.length-count]; - System.arraycopy(oldArray, 0, target, 0, oldArray.length-count); - return target; - } - - - - - - - - - - - - - - -} diff --git a/group11/1310368322/src/ThirdHomework/BaseDataStructure/LinkedList.java b/group11/1310368322/src/ThirdHomework/BaseDataStructure/LinkedList.java deleted file mode 100644 index 5ea6a988be..0000000000 --- a/group11/1310368322/src/ThirdHomework/BaseDataStructure/LinkedList.java +++ /dev/null @@ -1,162 +0,0 @@ -package DataStructure_3; - -import java.util.Stack; - -import DataStructure_1.LinkedList.Node; - -public class LinkedList { - private Node head; - static int size = 0; - public void add(Object o){ - if(null == head){ - head = new Node(); - head.data = o; - head.next = null; - }else{ - Node p = head; - while(null != p.next){ - p = p.next; - } - Node newNode = new Node(); - newNode.data = o; - p.next = newNode; - newNode.next =null; - } - size++; - } - public int size(){ - return size; - } - public void add(int index,Object o){ - if(index < 0){ - throw new RuntimeException("�±겻��Ϊ����"); - } - if(index == 0){ - addFirst(o); - size++; - return; - } - if(index > size){ - throw new RuntimeException(""); - } - int i = 0; - Node p = head; - Node q = null; - - while(i!=index){ - q = p; - p = p.next; - i++; - } - Node r = new Node(); - r.data = o; - r.next =null; - q.next = r; - r.next = p; - size++; - return; - } - - public Object get(int index){ - int i = 0; - Node p = head; - while(i != index){ - p = p.next; - i++; - } - return p.data; - } - public Object remove(int index){ - if(index < 0){ - throw new RuntimeException("�±겻��Ϊ����"); - } - if(index == 1){ - size--; - return head.data; - } - int i = 0; - Node p = head; - Node q = null; - while(i != index){ - q = p; - p = p.next; - i++; - } - q.next = p.next; - size--; - return p.data; - } - public void addFirst(Object o){ - Node p = new Node(); - p.next = head; - p.data = o; - head = p; - size++; - } - public Object removeFirst(){ - head = head.next; - size--; - return null; - } - public static class Node{ - Object data; - Node next; - } - - /** - * �Ѹ��������� - * �������� 3->7->10 �����ú��Ϊ 10->7->3 - */ - public void reverse(){ - if(null == head || null == head.next){ - return; - } - Stack s = new Stack(); - Node curNode = head; - while(curNode != null){ - s.push(curNode); - Node nextNode = curNode.next; - curNode.next = null; // �����Ͽ������� - curNode = nextNode; - } - - head = s.pop(); - curNode = head; - while(!s.isEmpty()){ - Node nextNode = s.pop(); - curNode.next = nextNode; - curNode = nextNode; - } - - } - - public String toString(){ - StringBuffer buffer = new StringBuffer(); - buffer.append("["); - Node node = head; - while(node != null){ - buffer.append(node.data); - if(node.next != null){ - buffer.append(","); - } - node = node.next; - } - buffer.append("]"); - return buffer.toString(); - } - - - - - - - - - - - - - - - -} diff --git a/group11/1310368322/src/ThirdHomework/Download/DownloadThread.java b/group11/1310368322/src/ThirdHomework/Download/DownloadThread.java deleted file mode 100644 index af248b72b2..0000000000 --- a/group11/1310368322/src/ThirdHomework/Download/DownloadThread.java +++ /dev/null @@ -1,39 +0,0 @@ -package day_2017_3_8_ThreadHomework; - -import java.io.RandomAccessFile; -import java.util.concurrent.CyclicBarrier; - -import com.coderising.download.api.Connection; - -public class DownloadThread extends Thread{ - - Connection conn; - int startPos; - int endPos; - CyclicBarrier barrier; - String localFile; - public DownloadThread(Connection conn, int startPos, int endPos,String localFile,CyclicBarrier barrier){ - this.conn = conn; - this.startPos = startPos; - this.endPos = endPos; - this.localFile = localFile; - this.barrier = barrier; - } - public void run(){ - try { - System.out.println("Begin to read [" + startPos + "-" + endPos + "]"); - byte [] data = conn.read(startPos, endPos); - System.out.println("����һ�������ȡ�ļ��Ķ���"); - RandomAccessFile file = new RandomAccessFile(localFile,"rw"); - file.seek(startPos); - System.out.println("Ҫд������"); - file.write(data); - file.close(); - conn.close(); - System.out.println(this.currentThread().getName()+"once over"); - barrier.await(); - } catch (Exception e) { - // TODO: handle exception - } - } -} diff --git a/group11/1310368322/src/ThirdHomework/Download/FileDownloader.java b/group11/1310368322/src/ThirdHomework/Download/FileDownloader.java deleted file mode 100644 index 445ede2e3d..0000000000 --- a/group11/1310368322/src/ThirdHomework/Download/FileDownloader.java +++ /dev/null @@ -1,114 +0,0 @@ -package day_2017_3_8_ThreadHomework; - -import java.io.IOException; -import java.io.RandomAccessFile; -import java.util.concurrent.CyclicBarrier; - -import com.coderising.download.api.Connection; -import com.coderising.download.api.ConnectionManager; -import com.coderising.download.api.DownloadListener; - -public class FileDownloader { - private String url; - private String localFile; - DownloadListener listener; - ConnectionManager cm; - - private static final int DOWNLOAD_THREAD_NUM = 3; - public FileDownloader(String _url,String localFile){ - this.url = _url; - this.localFile = localFile; - } - - public void execute(){ - // ������ʵ����Ĵ��룬 ע�⣺ ��Ҫ�ö��߳�ʵ������ - // ��������������������ӿڣ�����Ҫд�⼸���ӿڵ�ʵ�ִ��� - // ��1�� ConnectionManager ���Դ�һ�����ӣ�ͨ��Connection���Զ�ȡ���е�һ�Σ���StartPos,endPos��ָ���� - // ��2��DownloadListener, �����Ƕ��߳����أ����������Ŀͻ��˲�֪��ʲôʱ���������������Ҫʵ�ֵ������̶߳�ִ�����Ժ󣬵���listener��notifiedFinished�����������ͻ��˾����յ�֪ͨ - // �����ʵ��˼·�� - // 1. ��Ҫ����ConnectionManager�� open ���������ӣ�Ȼ��ͨ�� Connection.getContentLength��������ļ��ij��� - // 2. ��������3���߳����أ�ע��ÿ���߳���Ҫ�ȵ���ConnectionManager��open���� - // Ȼ����� read ������ read �������ж�ȡ�ļ��Ŀ�ʼλ�úͽ���λ�õIJ���������ֵ��byte[] ���� - // 3.�� byte ����д�뵽�ļ��� - // 4.���е��̶߳���������Ժ���Ҫ���� listener �� notifiedFinished ���� - - // ����Ĵ�����ʵ�����룬Ҳ����˵ֻ��һ���̣߳�����Ҫ����ɶ��̵߳� - CyclicBarrier barrier = new CyclicBarrier(DOWNLOAD_THREAD_NUM,new Runnable() {// �����е�Thread������ await����ʱ����ִ�к���� barrierAction,���ú�������߳� - @Override - public void run() { - listener.notifyFinished(); - } - }); - - Connection conn = null; - try { - conn = cm.open(this.url); - int length = conn.getContentLength();// �õ���Ҫ�����ļ��ij��� - createPlaceHolderFile(this.localFile,length);//ռλ - System.out.println("ռλ���"); - int [][] ranges = allocateDownloadRange(DOWNLOAD_THREAD_NUM,length);// ��ÿ���̷߳��俪ʼλ�úͽ���λ�� - // ��ʼ�����ļ� - System.out.println("��ʼ�����ļ�"); - for(int i = 0; i < DOWNLOAD_THREAD_NUM; i++){ - DownloadThread thread = new DownloadThread( - cm.open(url), - ranges[i][0], - ranges[i][1], - localFile, - barrier); - thread.start(); - System.out.println("��" + (i+1) + "���߳��Ѿ�����"); - } - - } catch (Exception e) { - e.printStackTrace(); - }finally{ - System.out.println("�����ر�����"); - if(conn != null){ - conn.close(); - System.out.println("�ر����ӳɹ�"); - } - } - } - - public void setListener(DownloadListener listener){ - this.listener = listener; - } - public void setConnectionManager(ConnectionManager ucm){ - this.cm = ucm; - } - public DownloadListener getListener(){ - return this.listener; - } - private void createPlaceHolderFile(String fileName,int contentLen) throws IOException{ - RandomAccessFile file = new RandomAccessFile(fileName,"rw"); - for(int i = 0; i < contentLen; i++){ - file.write(0); - } - file.close(); - } - /** - * �����߳������ļ����ȣ�����һ����ά���飬��������ÿ���߳����صĿ�ʼλ�úͽ���λ�� - * @param threadNum - * @param contentLen - * @return - */ - private int [][] allocateDownloadRange(int threadNum, int contentLen){ - int [][] ranges = new int[threadNum][2];// �ö�ά�������ÿ���̵߳Ŀ�ʼλ�úͽ���λ�� - - int eachThreadSize = contentLen / threadNum;// ÿ���߳���Ҫ���ص��ļ���С - int left = contentLen % threadNum;// ʣ�µĹ����һ���߳������� - - for(int i = 0; i totalLen){ - byte[] data = baos.toByteArray(); - return Arrays.copyOf(data, totalLen); - } - return baos.toByteArray(); - } - - @Override - public int getContentLength() { - URLConnection con; - try { - con = url.openConnection(); - return con.getContentLength(); - } catch (Exception e) { - e.printStackTrace(); - } - return -1; - } - - @Override - public void close() { - - } - -} diff --git a/group11/1310368322/src/ThirdHomework/Download/impl/ConnectionManagerImpl.java b/group11/1310368322/src/ThirdHomework/Download/impl/ConnectionManagerImpl.java deleted file mode 100644 index ff92aa77fe..0000000000 --- a/group11/1310368322/src/ThirdHomework/Download/impl/ConnectionManagerImpl.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.coderising.download.impl; - -import java.net.URL; - -import com.coderising.download.api.Connection; -import com.coderising.download.api.ConnectionException; -import com.coderising.download.api.ConnectionManager; - -public class ConnectionManagerImpl implements ConnectionManager{ - - @Override - public Connection open(String url) throws ConnectionException { - return new ConnectionImpl(url); - } - -} From 27f7a294865b93a64f1663bb95c003b50fde3fab Mon Sep 17 00:00:00 2001 From: James <1310368322@qq.com> Date: Fri, 24 Mar 2017 12:28:19 +0800 Subject: [PATCH 015/203] Third_Homework --- .../BaseDataStructure/ArrayList.java | 98 +++++++++++ .../BaseDataStructure/LinkedList.java | 113 ++++++++++++ .../BaseDataStructure/ArrayUtil.java | 83 +++++++++ .../BaseDataStructure/LinkedList.java | 162 ++++++++++++++++++ .../Download/DownloadThread.java | 39 +++++ .../Download/FileDownloader.java | 114 ++++++++++++ .../Download/api/Connection.java | 22 +++ .../Download/api/ConnectionException.java | 7 + .../Download/api/ConnectionManager.java | 10 ++ .../Download/api/DownloadListener.java | 5 + .../Download/impl/ConnectionImpl.java | 73 ++++++++ .../Download/impl/ConnectionManagerImpl.java | 16 ++ 12 files changed, 742 insertions(+) create mode 100644 group11/1310368322/src/FirstHomework/BaseDataStructure/ArrayList.java create mode 100644 group11/1310368322/src/FirstHomework/BaseDataStructure/LinkedList.java create mode 100644 group11/1310368322/src/SecondHomework/BaseDataStructure/ArrayUtil.java create mode 100644 group11/1310368322/src/ThirdHomework/BaseDataStructure/LinkedList.java create mode 100644 group11/1310368322/src/ThirdHomework/Download/DownloadThread.java create mode 100644 group11/1310368322/src/ThirdHomework/Download/FileDownloader.java create mode 100644 group11/1310368322/src/ThirdHomework/Download/api/Connection.java create mode 100644 group11/1310368322/src/ThirdHomework/Download/api/ConnectionException.java create mode 100644 group11/1310368322/src/ThirdHomework/Download/api/ConnectionManager.java create mode 100644 group11/1310368322/src/ThirdHomework/Download/api/DownloadListener.java create mode 100644 group11/1310368322/src/ThirdHomework/Download/impl/ConnectionImpl.java create mode 100644 group11/1310368322/src/ThirdHomework/Download/impl/ConnectionManagerImpl.java diff --git a/group11/1310368322/src/FirstHomework/BaseDataStructure/ArrayList.java b/group11/1310368322/src/FirstHomework/BaseDataStructure/ArrayList.java new file mode 100644 index 0000000000..b5024f1dfb --- /dev/null +++ b/group11/1310368322/src/FirstHomework/BaseDataStructure/ArrayList.java @@ -0,0 +1,98 @@ +package Day_2017_2_26_FirstHomework; + +public class ArrayList { + + private static final int DEFAULT_SIZE = 10; + private static final int MAX_VALUE = 2147483647; + private Object[] elementData = new Object[DEFAULT_SIZE]; + private Exception Exception; + private int size = 0; + + public ArrayList(){ + this(DEFAULT_SIZE); + } + public ArrayList(int defaultSize) { + rangCheckForConstructor(defaultSize); + elementData = new Object[defaultSize]; + } + + + private void rangCheckForConstructor(int defaultSize) { + if(defaultSize<0 || defaultSize>MAX_VALUE){ + throw new IndexOutOfBoundsException("��ֵ������"); + } + + } + + public void add(Object o){ + ensureCapacity(); + for(int i = 0; i < elementData.length; i++){ + if(null == elementData[i]){ + elementData[i] = o; + break; + } + } + size++; + } + private void ensureCapacity() { + if(size>elementData.length){ + elementData = ArrayList.grow(elementData, 10); + } + } + public void add(int index, Object o){ + rangeCheckForAdd(index); + ensureCapacity(); + int k = -1; + for(int i = index; i < elementData.length; i++){ + if(null==elementData[i]){ + k = i-1; + break; + } + } + for(int i = k; i >= index;i--){ + elementData[i+1] = elementData[i]; + } + elementData[index] = o; + size++; + } + private void rangeCheckForAdd(int index) { + if(index < 0 || index > this.size){// add ��Ԫ��ֻ���� [0,size](���Ը�sizeλ�ò�Ԫ�أ��������Ը�size���Ԫ��) + throw new IndexOutOfBoundsException("�±�Խ��"); + } + + } + public Object get(int index){ + return elementData[index]; + } + + public Object remove(int index){ + while(true){ + elementData[index] = elementData[index+++1]; + if(elementData[index]==null){ + break; + } + } + size--; + return null; + } + public int size(){ + return -1; + } + public void getElementData(){ + for(int i = 0; i < elementData.length; i++){ + System.out.println(elementData[i]); + + } + } + public static Object[] grow(Object[] elementData2, int size){ + Object []target = new Object[elementData2.length+size]; + System.arraycopy(elementData2, 0, target, 0, elementData2.length); + return target; + } + + public static void main(String[] args) { + ArrayList a = new ArrayList(); + a.getElementData(); + System.out.println(a.size); + } +} diff --git a/group11/1310368322/src/FirstHomework/BaseDataStructure/LinkedList.java b/group11/1310368322/src/FirstHomework/BaseDataStructure/LinkedList.java new file mode 100644 index 0000000000..488f2a22a6 --- /dev/null +++ b/group11/1310368322/src/FirstHomework/BaseDataStructure/LinkedList.java @@ -0,0 +1,113 @@ +package Day_2017_2_26_FirstHomework; + +public class LinkedList{ + private Node head; + static int size = 0; + public void add(Object o){ + if(null == head){ + head = new Node(); + head.data = o; + head.next = null; + }else{ + Node p = head; + while(null != p.next){ + p = p.next; + } + Node newNode = new Node(); + newNode.data = o; + p.next = newNode; + newNode.next =null; + } + size++; + } + public int size(){ + return size; + } + public void add(int index,Object o){ + if(index < 0){ + throw new RuntimeException("�±겻��Ϊ����"); + } + if(index == 0){ + addFirst(o); + size++; + return; + } + if(index > size){ + throw new RuntimeException(""); + } + int i = 0; + Node p = head; + Node q = null; + + while(i!=index){ + q = p; + p = p.next; + i++; + } + Node r = new Node(); + r.data = o; + r.next =null; + q.next = r; + r.next = p; + size++; + return; + } + + public Object get(int index){ + int i = 0; + Node p = head; + while(i != index){ + p = p.next; + i++; + } + return p.data; + } + public Object remove(int index){ + if(index < 0){ + throw new RuntimeException("�±겻��Ϊ����"); + } + if(index == 1){ + size--; + return head.data; + } + int i = 0; + Node p = head; + Node q = null; + while(i != index){ + q = p; + p = p.next; + i++; + } + q.next = p.next; + size--; + return p.data; + } + public void addFirst(Object o){ + Node p = new Node(); + p.next = head; + p.data = o; + head = p; + size++; + } + public Object removeFirst(){ + head = head.next; + size--; + return null; + } + public static class Node{ + Object data; + Node next; + } + + public static void main(String[] args) { + LinkedList linkedList = new LinkedList(); + linkedList.add("a"); + linkedList.add("b"); + linkedList.add("c"); + linkedList.add("d"); + linkedList.add(5, "f"); + System.out.println(linkedList.get(5)); + System.out.println(linkedList.size()); + } + +} \ No newline at end of file diff --git a/group11/1310368322/src/SecondHomework/BaseDataStructure/ArrayUtil.java b/group11/1310368322/src/SecondHomework/BaseDataStructure/ArrayUtil.java new file mode 100644 index 0000000000..81bc431679 --- /dev/null +++ b/group11/1310368322/src/SecondHomework/BaseDataStructure/ArrayUtil.java @@ -0,0 +1,83 @@ +package day_2017_2_26_SecondHomework; + +import java.util.Arrays; + +import javax.management.RuntimeErrorException; + +public class ArrayUtil { + + /* * + * ����һ���������� a ���Ը������ֵ�����û� + * ���磺 a = [7, 9, 30, 3], �û���Ϊ [3, 30, 9, 7] + * */ + + /*public ArrayUtil(int[] a2) { + this.a = a2; + }*/ + public void reverseArray(int [] a){ + if(null == a){ + System.out.println("��ָ��----"); + return; + } + int temp; + int last = a.length-1; + for (int i = 0; i < a.length/2; i++) { + temp = a[i]; + a[i] = a[last]; + a[last--] = temp; + } + } + public void print(int [] a){ + if(null == a){ + System.out.println("��ָ��----"); + return; + } + for (int i = 0; i < a.length; i++) { + System.out.print(a[i] + " "); + } + System.out.println(); + } + + /* * + * ���������µ�һ�����飬 int oldArr[] = {1,3,4,5,0,0,6,6,0,5,4,7,6,7,0,5} + * Ҫ�����������е�ֵΪ 0 ����ȥ��������Ϊ 0 ��ֵ����һ���µ����飬���ɵ�������Ϊ�� + * {1,3,4,5,6,6,5,4,7,6,7,5} + * @param oldArray + * @return + */ + public int [] removeZero(int [] oldArray){ + if(null == oldArray){ + return null; + } + int count = 0; + int oldArrayLength = oldArray.length; + for(int i = 0; i < oldArrayLength;){ + if(oldArray[i]==0){ + for(int j = i; j < oldArrayLength -1; j++){ + oldArray[j] = oldArray[j+1]; + } + oldArrayLength--; + count++; + }else{ + i++; + } + } + int [] target = new int[oldArray.length-count]; + System.arraycopy(oldArray, 0, target, 0, oldArray.length-count); + return target; + } + + + + + + + + + + + + + + +} diff --git a/group11/1310368322/src/ThirdHomework/BaseDataStructure/LinkedList.java b/group11/1310368322/src/ThirdHomework/BaseDataStructure/LinkedList.java new file mode 100644 index 0000000000..5ea6a988be --- /dev/null +++ b/group11/1310368322/src/ThirdHomework/BaseDataStructure/LinkedList.java @@ -0,0 +1,162 @@ +package DataStructure_3; + +import java.util.Stack; + +import DataStructure_1.LinkedList.Node; + +public class LinkedList { + private Node head; + static int size = 0; + public void add(Object o){ + if(null == head){ + head = new Node(); + head.data = o; + head.next = null; + }else{ + Node p = head; + while(null != p.next){ + p = p.next; + } + Node newNode = new Node(); + newNode.data = o; + p.next = newNode; + newNode.next =null; + } + size++; + } + public int size(){ + return size; + } + public void add(int index,Object o){ + if(index < 0){ + throw new RuntimeException("�±겻��Ϊ����"); + } + if(index == 0){ + addFirst(o); + size++; + return; + } + if(index > size){ + throw new RuntimeException(""); + } + int i = 0; + Node p = head; + Node q = null; + + while(i!=index){ + q = p; + p = p.next; + i++; + } + Node r = new Node(); + r.data = o; + r.next =null; + q.next = r; + r.next = p; + size++; + return; + } + + public Object get(int index){ + int i = 0; + Node p = head; + while(i != index){ + p = p.next; + i++; + } + return p.data; + } + public Object remove(int index){ + if(index < 0){ + throw new RuntimeException("�±겻��Ϊ����"); + } + if(index == 1){ + size--; + return head.data; + } + int i = 0; + Node p = head; + Node q = null; + while(i != index){ + q = p; + p = p.next; + i++; + } + q.next = p.next; + size--; + return p.data; + } + public void addFirst(Object o){ + Node p = new Node(); + p.next = head; + p.data = o; + head = p; + size++; + } + public Object removeFirst(){ + head = head.next; + size--; + return null; + } + public static class Node{ + Object data; + Node next; + } + + /** + * �Ѹ��������� + * �������� 3->7->10 �����ú��Ϊ 10->7->3 + */ + public void reverse(){ + if(null == head || null == head.next){ + return; + } + Stack s = new Stack(); + Node curNode = head; + while(curNode != null){ + s.push(curNode); + Node nextNode = curNode.next; + curNode.next = null; // �����Ͽ������� + curNode = nextNode; + } + + head = s.pop(); + curNode = head; + while(!s.isEmpty()){ + Node nextNode = s.pop(); + curNode.next = nextNode; + curNode = nextNode; + } + + } + + public String toString(){ + StringBuffer buffer = new StringBuffer(); + buffer.append("["); + Node node = head; + while(node != null){ + buffer.append(node.data); + if(node.next != null){ + buffer.append(","); + } + node = node.next; + } + buffer.append("]"); + return buffer.toString(); + } + + + + + + + + + + + + + + + +} diff --git a/group11/1310368322/src/ThirdHomework/Download/DownloadThread.java b/group11/1310368322/src/ThirdHomework/Download/DownloadThread.java new file mode 100644 index 0000000000..af248b72b2 --- /dev/null +++ b/group11/1310368322/src/ThirdHomework/Download/DownloadThread.java @@ -0,0 +1,39 @@ +package day_2017_3_8_ThreadHomework; + +import java.io.RandomAccessFile; +import java.util.concurrent.CyclicBarrier; + +import com.coderising.download.api.Connection; + +public class DownloadThread extends Thread{ + + Connection conn; + int startPos; + int endPos; + CyclicBarrier barrier; + String localFile; + public DownloadThread(Connection conn, int startPos, int endPos,String localFile,CyclicBarrier barrier){ + this.conn = conn; + this.startPos = startPos; + this.endPos = endPos; + this.localFile = localFile; + this.barrier = barrier; + } + public void run(){ + try { + System.out.println("Begin to read [" + startPos + "-" + endPos + "]"); + byte [] data = conn.read(startPos, endPos); + System.out.println("����һ�������ȡ�ļ��Ķ���"); + RandomAccessFile file = new RandomAccessFile(localFile,"rw"); + file.seek(startPos); + System.out.println("Ҫд������"); + file.write(data); + file.close(); + conn.close(); + System.out.println(this.currentThread().getName()+"once over"); + barrier.await(); + } catch (Exception e) { + // TODO: handle exception + } + } +} diff --git a/group11/1310368322/src/ThirdHomework/Download/FileDownloader.java b/group11/1310368322/src/ThirdHomework/Download/FileDownloader.java new file mode 100644 index 0000000000..445ede2e3d --- /dev/null +++ b/group11/1310368322/src/ThirdHomework/Download/FileDownloader.java @@ -0,0 +1,114 @@ +package day_2017_3_8_ThreadHomework; + +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.concurrent.CyclicBarrier; + +import com.coderising.download.api.Connection; +import com.coderising.download.api.ConnectionManager; +import com.coderising.download.api.DownloadListener; + +public class FileDownloader { + private String url; + private String localFile; + DownloadListener listener; + ConnectionManager cm; + + private static final int DOWNLOAD_THREAD_NUM = 3; + public FileDownloader(String _url,String localFile){ + this.url = _url; + this.localFile = localFile; + } + + public void execute(){ + // ������ʵ����Ĵ��룬 ע�⣺ ��Ҫ�ö��߳�ʵ������ + // ��������������������ӿڣ�����Ҫд�⼸���ӿڵ�ʵ�ִ��� + // ��1�� ConnectionManager ���Դ�һ�����ӣ�ͨ��Connection���Զ�ȡ���е�һ�Σ���StartPos,endPos��ָ���� + // ��2��DownloadListener, �����Ƕ��߳����أ����������Ŀͻ��˲�֪��ʲôʱ���������������Ҫʵ�ֵ������̶߳�ִ�����Ժ󣬵���listener��notifiedFinished�����������ͻ��˾����յ�֪ͨ + // �����ʵ��˼·�� + // 1. ��Ҫ����ConnectionManager�� open ���������ӣ�Ȼ��ͨ�� Connection.getContentLength��������ļ��ij��� + // 2. ��������3���߳����أ�ע��ÿ���߳���Ҫ�ȵ���ConnectionManager��open���� + // Ȼ����� read ������ read �������ж�ȡ�ļ��Ŀ�ʼλ�úͽ���λ�õIJ���������ֵ��byte[] ���� + // 3.�� byte ����д�뵽�ļ��� + // 4.���е��̶߳���������Ժ���Ҫ���� listener �� notifiedFinished ���� + + // ����Ĵ�����ʵ�����룬Ҳ����˵ֻ��һ���̣߳�����Ҫ����ɶ��̵߳� + CyclicBarrier barrier = new CyclicBarrier(DOWNLOAD_THREAD_NUM,new Runnable() {// �����е�Thread������ await����ʱ����ִ�к���� barrierAction,���ú�������߳� + @Override + public void run() { + listener.notifyFinished(); + } + }); + + Connection conn = null; + try { + conn = cm.open(this.url); + int length = conn.getContentLength();// �õ���Ҫ�����ļ��ij��� + createPlaceHolderFile(this.localFile,length);//ռλ + System.out.println("ռλ���"); + int [][] ranges = allocateDownloadRange(DOWNLOAD_THREAD_NUM,length);// ��ÿ���̷߳��俪ʼλ�úͽ���λ�� + // ��ʼ�����ļ� + System.out.println("��ʼ�����ļ�"); + for(int i = 0; i < DOWNLOAD_THREAD_NUM; i++){ + DownloadThread thread = new DownloadThread( + cm.open(url), + ranges[i][0], + ranges[i][1], + localFile, + barrier); + thread.start(); + System.out.println("��" + (i+1) + "���߳��Ѿ�����"); + } + + } catch (Exception e) { + e.printStackTrace(); + }finally{ + System.out.println("�����ر�����"); + if(conn != null){ + conn.close(); + System.out.println("�ر����ӳɹ�"); + } + } + } + + public void setListener(DownloadListener listener){ + this.listener = listener; + } + public void setConnectionManager(ConnectionManager ucm){ + this.cm = ucm; + } + public DownloadListener getListener(){ + return this.listener; + } + private void createPlaceHolderFile(String fileName,int contentLen) throws IOException{ + RandomAccessFile file = new RandomAccessFile(fileName,"rw"); + for(int i = 0; i < contentLen; i++){ + file.write(0); + } + file.close(); + } + /** + * �����߳������ļ����ȣ�����һ����ά���飬��������ÿ���߳����صĿ�ʼλ�úͽ���λ�� + * @param threadNum + * @param contentLen + * @return + */ + private int [][] allocateDownloadRange(int threadNum, int contentLen){ + int [][] ranges = new int[threadNum][2];// �ö�ά�������ÿ���̵߳Ŀ�ʼλ�úͽ���λ�� + + int eachThreadSize = contentLen / threadNum;// ÿ���߳���Ҫ���ص��ļ���С + int left = contentLen % threadNum;// ʣ�µĹ����һ���߳������� + + for(int i = 0; i totalLen){ + byte[] data = baos.toByteArray(); + return Arrays.copyOf(data, totalLen); + } + return baos.toByteArray(); + } + + @Override + public int getContentLength() { + URLConnection con; + try { + con = url.openConnection(); + return con.getContentLength(); + } catch (Exception e) { + e.printStackTrace(); + } + return -1; + } + + @Override + public void close() { + + } + +} diff --git a/group11/1310368322/src/ThirdHomework/Download/impl/ConnectionManagerImpl.java b/group11/1310368322/src/ThirdHomework/Download/impl/ConnectionManagerImpl.java new file mode 100644 index 0000000000..ff92aa77fe --- /dev/null +++ b/group11/1310368322/src/ThirdHomework/Download/impl/ConnectionManagerImpl.java @@ -0,0 +1,16 @@ +package com.coderising.download.impl; + +import java.net.URL; + +import com.coderising.download.api.Connection; +import com.coderising.download.api.ConnectionException; +import com.coderising.download.api.ConnectionManager; + +public class ConnectionManagerImpl implements ConnectionManager{ + + @Override + public Connection open(String url) throws ConnectionException { + return new ConnectionImpl(url); + } + +} From 6306c3c32788790761c53d691fe04b315c9aa1ca Mon Sep 17 00:00:00 2001 From: x_zhaohu Date: Sat, 25 Mar 2017 19:45:40 +0800 Subject: [PATCH 016/203] =?UTF-8?q?week01=20=E6=95=B4=E7=90=86=E5=AE=8C?= =?UTF-8?q?=E6=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group11/1178243325/week01/.readme.md.swp | Bin 0 -> 12288 bytes group11/1178243325/week01/readme.md | 5 +++-- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 group11/1178243325/week01/.readme.md.swp diff --git a/group11/1178243325/week01/.readme.md.swp b/group11/1178243325/week01/.readme.md.swp new file mode 100644 index 0000000000000000000000000000000000000000..44d97db14f1c5235f5e0a65a0bdaee85c90f52de GIT binary patch literal 12288 zcmeI&OHUI~6ae6h3*CqsUAQx&Y$Tzb&J=7hQA1o93?>@IkQhzIb_%7Tt;5vDjgnZ} zYRk(9k6J*qhDJ(hKm^*t4{+(iU(h>uSeP#S1D>IPMgnnXFlUl8uY2y?bHCe7JH2nY z-F%I+nd=E`#|XL7_O0zp=P5FCn2>J2;`XXW!`|E9<~^ky@HTVf&W2^e(xOs^O6hHwK zKmim$0Te(16hHwKKmim$fqf_-!CUpFYC^^#jQ9Ur-~YcKCFCo_ID`Y@BE$uVlMt&% z2vHy&K-`141aS!BAjFTYXYE4^EExq*00mG01yBG5Pyhu`00sV;fQh@K6=(EZRL@Sa z?1+}kvqDIV4$}TfHW;Qa;;cB#(lLE*R!{fbJ=>wG{_{K^3 zYM~#U%xlSv_ByBaWm(~+HW8vr^E4ZWGC57IM|M_j-3Z75xsJP~$gpo#WkphbO1b#V zD4b<7P$eBomsXRd{)yp>d< Date: Sat, 25 Mar 2017 20:50:20 +0800 Subject: [PATCH 017/203] task1 De --- LLP/task1.html | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 LLP/task1.html diff --git a/LLP/task1.html b/LLP/task1.html new file mode 100644 index 0000000000..9b3352fa07 --- /dev/null +++ b/LLP/task1.html @@ -0,0 +1,71 @@ + + + + task1 + + +

第一个任务

+

第一个任务

+

第一个任务

+

第一个任务

+
第一个任务
+
第一个任务
+

这里就是一段文段,可以长也可以短,它还具有属性

+ 备注一下 + 再来个下划线吧 +
    +
  • 第一个
  • +
  • 第二个
  • +
  • 第三个
  • +
  • 第四个
  • +
+
    +
  1. 第1个
  2. +
  3. 第2个
  4. +
  5. 第3个
  6. +
  7. 第4个
  8. +
+ 再来个强壮一下吧 +
+ + + + + + + + + + + + + + + + + + + + +
+
+ + + + + +
+
+
可以作为标题,也可以放图片
+
放详细介绍
+
放详细介绍
+
+ + \ No newline at end of file From c4c701b1ba15a4996dd610a365172a4bd89ea556 Mon Sep 17 00:00:00 2001 From: x_zhaohu Date: Sun, 26 Mar 2017 19:57:28 +0800 Subject: [PATCH 018/203] =?UTF-8?q?week02=E6=95=B4=E7=90=86=E5=AE=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group11/1178243325/week02/build.gradle | 12 + group11/1178243325/week02/readme.md | 23 ++ .../main/java/com/sprint/array/ArrayUtil.java | 229 ++++++++++++++++++ .../com/sprint/litestruts/Configuration.java | 86 +++++++ .../litestruts/ConfigurationException.java | 18 ++ .../com/sprint/litestruts/LoginAction.java | 40 +++ .../com/sprint/litestruts/ReflectionUtil.java | 70 ++++++ .../litestruts/ReflectionUtilException.java | 20 ++ .../java/com/sprint/litestruts/Struts.java | 53 ++++ .../main/java/com/sprint/litestruts/View.java | 24 ++ .../week02/src/main/resources/struts.xml | 12 + .../java/com/sprint/array/ArrayUtilTest.java | 76 ++++++ .../sprint/litestruts/ConfigurationTest.java | 31 +++ .../sprint/litestruts/ReflectionUtilTest.java | 92 +++++++ .../com/sprint/litestruts/StrutsTest.java | 32 +++ 15 files changed, 818 insertions(+) create mode 100644 group11/1178243325/week02/build.gradle create mode 100644 group11/1178243325/week02/readme.md create mode 100644 group11/1178243325/week02/src/main/java/com/sprint/array/ArrayUtil.java create mode 100644 group11/1178243325/week02/src/main/java/com/sprint/litestruts/Configuration.java create mode 100644 group11/1178243325/week02/src/main/java/com/sprint/litestruts/ConfigurationException.java create mode 100644 group11/1178243325/week02/src/main/java/com/sprint/litestruts/LoginAction.java create mode 100644 group11/1178243325/week02/src/main/java/com/sprint/litestruts/ReflectionUtil.java create mode 100644 group11/1178243325/week02/src/main/java/com/sprint/litestruts/ReflectionUtilException.java create mode 100644 group11/1178243325/week02/src/main/java/com/sprint/litestruts/Struts.java create mode 100644 group11/1178243325/week02/src/main/java/com/sprint/litestruts/View.java create mode 100644 group11/1178243325/week02/src/main/resources/struts.xml create mode 100644 group11/1178243325/week02/src/test/java/com/sprint/array/ArrayUtilTest.java create mode 100644 group11/1178243325/week02/src/test/java/com/sprint/litestruts/ConfigurationTest.java create mode 100644 group11/1178243325/week02/src/test/java/com/sprint/litestruts/ReflectionUtilTest.java create mode 100644 group11/1178243325/week02/src/test/java/com/sprint/litestruts/StrutsTest.java diff --git a/group11/1178243325/week02/build.gradle b/group11/1178243325/week02/build.gradle new file mode 100644 index 0000000000..f6ebbb892e --- /dev/null +++ b/group11/1178243325/week02/build.gradle @@ -0,0 +1,12 @@ +apply plugin: 'java' + + +repositories { + maven { url "http://maven.aliyun.com/nexus/content/groups/public" } + mavenCentral() +} + +dependencies { + compile("org.jdom:jdom2:2.0.5") + testCompile("junit:junit:4.12") +} diff --git a/group11/1178243325/week02/readme.md b/group11/1178243325/week02/readme.md new file mode 100644 index 0000000000..a4f9adc15a --- /dev/null +++ b/group11/1178243325/week02/readme.md @@ -0,0 +1,23 @@ +## 讲课内容: +- 17-03-01:第一周作业讲评 +- 17-03-05:漫谈进程和线程和布置第三周作业 + +## 第二周作业(2-27 至 3-5) +- 实现第一个大作业:读取struts.xml,执行Action +- 5道数据结构习题 + +## 完成情况: +- struts大作业完成 +- 数据结构习题完成 + +## 我的收获: +- TDD +- 操作系统抽象概念 +- 进程在虚拟存储器表示 +- 进程调度 +- 进程同步 +- 线程 + + +![99.jpg](http://upload-images.jianshu.io/upload_images/2031765-d3740acf4d284e93.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + diff --git a/group11/1178243325/week02/src/main/java/com/sprint/array/ArrayUtil.java b/group11/1178243325/week02/src/main/java/com/sprint/array/ArrayUtil.java new file mode 100644 index 0000000000..01d7d5f0da --- /dev/null +++ b/group11/1178243325/week02/src/main/java/com/sprint/array/ArrayUtil.java @@ -0,0 +1,229 @@ +package com.sprint.array; + +public class ArrayUtil { + + /** + * 给定一个整形数组a , 对该数组的值进行置换 + 例如: a = [7, 9 , 30, 3] , 置换后为 [3, 30, 9,7] + 如果 a = [7, 9, 30, 3, 4] , 置换后为 [4,3, 30 , 9,7] + * @param origin + * @return + */ + public static void reverseArray(int[] origin){ + if (origin == null) { + return; + } + + int length = origin.length; + int[] temp = new int[length]; + for (int i = 0; i < length; i++) + temp[i] = origin[i]; + for (int i = length - 1, j = 0; i >= 0 && j < length; i--, j++) + origin[j] = temp[i]; + } + + /** + * 现在有如下的一个数组: int oldArr[]={1,3,4,5,0,0,6,6,0,5,4,7,6,7,0,5} + * 要求将以上数组中值为0的项去掉,将不为0的值存入一个新的数组,生成的新数组为: + * {1,3,4,5,6,6,5,4,7,6,7,5} + * @param oldArray + * @return + */ + + public static int[] removeZero(int[] oldArray){ + if (oldArray == null) { + return new int[0]; + } + + int zeroCount = 0; + for (int i = 0; i < oldArray.length; i++) { + if (oldArray[i] == 0) + zeroCount++; + } + int[] newArray = new int[oldArray.length-zeroCount]; + for (int i = 0, j = 0; i < oldArray.length && j < newArray.length; i++) { + if (oldArray[i] != 0) { + newArray[j] = oldArray[i]; + j++; + } + } + return newArray; + } + + /** + * 给定两个已经排序好的整形数组, a1和a2 , 创建一个新的数组a3, 使得a3 包含a1和a2 的所有元素, 并且仍然是有序的 + * 例如 a1 = [3, 5, 7,8] a2 = [4, 5, 6,7] 则 a3 为[3,4,5,6,7,8] , 注意: 已经消除了重复 + * @param array1 + * @param array2 + * @return + */ + + public static int[] merge(int[] array1, int[] array2){ + if (array1 == null && array2 == null) + return new int[0]; + int index1 = 0, index2 = 0; + int[] array3 = new int[array1.length + array2.length]; + int index = 0; + while (index1 != array1.length && index2 != array2.length) { + if (array1[index1] < array2[index2]) { + array3[index++] = array1[index1++]; + } else if (array1[index1] > array2[index2]) { + array3[index++] = array2[index2++]; + } else if (array1[index1] == array2[index2]){ + array3[index++] = array1[index1++]; + index2++; + } + } + + if (index1 == array1.length && index2 != array2.length) { + for (int i = index2; i < array2.length; i++) + array3[index++] = array2[i]; + } else if (index2 == array2.length && index1 != array1.length) { + for (int i = index1; i < array1.length; i++) { + array3[index++] = array1[i]; + } + } + + int[] newArray = new int[index]; + for (int i = 0; i < newArray.length; i++) + newArray[i] = array3[i]; + return newArray; + } + /** + * 把一个已经存满数据的数组 oldArray的容量进行扩展, 扩展后的新数据大小为oldArray.length + size + * 注意,老数组的元素在新数组中需要保持 + * 例如 oldArray = [2,3,6] , size = 3,则返回的新数组为 + * [2,3,6,0,0,0] + * + * @param oldArray + * @param size + * @return + */ + public static int[] grow(int [] oldArray, int size){ + if (size <= 0) + return new int[0]; + int[] newArray = new int[oldArray.length + size]; + for (int i = 0; i < oldArray.length; i++) { + newArray[i] = oldArray[i]; + } + return newArray; + } + + /** + * 斐波那契数列为:1,1,2,3,5,8,13,21...... ,给定一个最大值, 返回小于该值的数列 + * 例如, max = 15 , 则返回的数组应该为 [1,1,2,3,5,8,13] + * max = 1, 则返回空数组 [] + * @param max + * @return + */ + public static int[] fibonacci(int max){ + if (max < 1) + return new int[0]; + if (max == 1) + return new int[0]; + int[] array = new int[max]; + int i = 0; + int value = fibonaccis(i+1); + while ( value < max) { + array[i++] = value; + value = fibonaccis(i+1); + } + int[] newArray = new int[i]; + for (int j = 0; j < newArray.length; j++) { + newArray[j] = array[j]; + } + return newArray; + } + + private static int fibonaccis(int n) { + if (n <=0) + return 0; + if (n == 1 || n ==2 ) + return 1; + return fibonaccis(n-1)+fibonaccis(n-2); + } + + /** + * 返回小于给定最大值max的所有素数数组 + * 例如max = 23, 返回的数组为[2,3,5,7,11,13,17,19] + * @param max + * @return + */ + public static int[] getPrimes(int max){ + if (max <= 1) { + return new int[0]; + } + int[] array = new int[max]; + int index = 0; + for (int i = 2; i < max; i++) { + if (i == 2 || i == 3 || i == 5 || i == 7) + array[index++] = i; + if (i%2 !=0 && i%3 != 0 && i%5 != 0 && i%7 != 0) + array[index++] = i; + } + int[] newArray = new int[index]; + for (int i = 0; i < newArray.length; i++) { + newArray[i] = array[i]; + } + + return newArray; + } + + /** + * 所谓“完数”, 是指这个数恰好等于它的因子之和,例如6=1+2+3 + * 给定一个最大值max, 返回一个数组, 数组中是小于max 的所有完数 + * @param max + * @return + */ + public static int[] getPerfectNumbers(int max){ + if (max <= 0) + return new int[0]; + int[] array = new int[max]; + int index = 0; + for (int i = 1; i < max; i++) { + if (isPerfectNumber(i)) + array[index++] = i; + } + + int[] newArray = new int[index]; + for (int i = 0; i < newArray.length; i++) + newArray[i] = array[i]; + + return newArray; + } + + private static boolean isPerfectNumber(int n) { + int sum = 0; + int i = 1; + while (i < n) { + if (n%i == 0) + sum += i; + i++; + } + if (sum == n) + return true; + return false; + } + /** + * 用seperator 把数组 array给连接起来 + * 例如array= [3,8,9], seperator = "-" + * 则返回值为"3-8-9" + * @param array + * @param s + * @return + */ + public static String join(int[] array, String seperator){ + if (array == null) + return null; + StringBuilder str = new StringBuilder(); + for (int i = 0; i < array.length; i++) { + if (i == array.length-1) + str.append(array[i]); + else + str.append(array[i] + seperator); + } + return str.toString(); + } + + +} diff --git a/group11/1178243325/week02/src/main/java/com/sprint/litestruts/Configuration.java b/group11/1178243325/week02/src/main/java/com/sprint/litestruts/Configuration.java new file mode 100644 index 0000000000..0f10458fc3 --- /dev/null +++ b/group11/1178243325/week02/src/main/java/com/sprint/litestruts/Configuration.java @@ -0,0 +1,86 @@ +package com.sprint.litestruts; + +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + + +import org.jdom2.Document; +import org.jdom2.Element; +import org.jdom2.JDOMException; +import org.jdom2.input.SAXBuilder; +public class Configuration { + Map actions = new HashMap<>(); + public Configuration(String fileName) { + InputStream is = this.getClass().getClassLoader().getResourceAsStream(fileName); + parseXML(is); + try { + is.close(); + } catch (IOException e) { + throw new ConfigurationException(e); + } + } + + private void parseXML(InputStream is) { + SAXBuilder builder = new SAXBuilder(); + try { + Document doc = builder.build(is); + Element root = doc.getRootElement(); + for (Element actionElement : root.getChildren("action")) { + String actionName = actionElement.getAttributeValue("name"); + String clzName = actionElement.getAttributeValue("class"); + + ActionConfig ac = new ActionConfig(actionName, clzName); + for (Element resultElement : actionElement.getChildren("result")) { + String resultName = resultElement.getAttributeValue("name"); + String viewName = resultElement.getText().trim(); + ac.addViewResult(resultName, viewName); + } + this.actions.put(actionName, ac); + } + } catch (JDOMException e) { + throw new ConfigurationException(e); + } catch (IOException e) { + throw new ConfigurationException(e); + } + } + + public String getClassName(String actionName) { + ActionConfig ac = this.actions.get(actionName); + if(ac == null) { + return null; + } + return ac.getClassName(); + } + + public String getResultView(String actionName, String resultName) { + ActionConfig ac = this.actions.get(actionName); + if (ac == null) { + return null; + } + return ac.getViewName(resultName); + } + private static class ActionConfig { + String name; + String clzName; + Map viewResult = new HashMap<>(); + + public ActionConfig(String actionName, String clzName) { + this.name = actionName; + this.clzName = clzName; + } + + public String getClassName() { + return clzName; + } + + public void addViewResult(String name, String viewName) { + viewResult.put(name, viewName); + } + + public String getViewName(String resultName) { + return viewResult.get(resultName); + } + } +} diff --git a/group11/1178243325/week02/src/main/java/com/sprint/litestruts/ConfigurationException.java b/group11/1178243325/week02/src/main/java/com/sprint/litestruts/ConfigurationException.java new file mode 100644 index 0000000000..25c6784f43 --- /dev/null +++ b/group11/1178243325/week02/src/main/java/com/sprint/litestruts/ConfigurationException.java @@ -0,0 +1,18 @@ +package com.sprint.litestruts; + +import java.io.IOException; +import org.jdom2.JDOMException; +public class ConfigurationException extends RuntimeException { + + public ConfigurationException(String msg) { + super(msg); + } + + public ConfigurationException(JDOMException e) { + super(e); + } + + public ConfigurationException(IOException e) { + super(e); + } +} diff --git a/group11/1178243325/week02/src/main/java/com/sprint/litestruts/LoginAction.java b/group11/1178243325/week02/src/main/java/com/sprint/litestruts/LoginAction.java new file mode 100644 index 0000000000..4b4f2b8e38 --- /dev/null +++ b/group11/1178243325/week02/src/main/java/com/sprint/litestruts/LoginAction.java @@ -0,0 +1,40 @@ +package com.sprint.litestruts; + +/** + * 这是一个展示业务逻辑的类,其中用户名是硬编码 + * @author xingzhaohu + */ + +public class LoginAction { + private String name; + private String password; + private String message; + + public String execute() { + if ("test".equals(name) && "1234".equals(password)) { + this.message = "login successful"; + return "success"; + } + this.message = "login failed,please check your user/pwd"; + return "fail"; + } + public void setName(String name) { + this.name = name; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getName() { + return name; + } + + public String getPassword() { + return password; + } + + public String getMessage() { + return message; + } +} diff --git a/group11/1178243325/week02/src/main/java/com/sprint/litestruts/ReflectionUtil.java b/group11/1178243325/week02/src/main/java/com/sprint/litestruts/ReflectionUtil.java new file mode 100644 index 0000000000..822355655b --- /dev/null +++ b/group11/1178243325/week02/src/main/java/com/sprint/litestruts/ReflectionUtil.java @@ -0,0 +1,70 @@ +package com.sprint.litestruts; + +import java.lang.reflect.Method; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +public class ReflectionUtil { + + public static List getSetterMethods(Class clz) { + return getMethods(clz, "set"); + } + + public static List getGetterMethods(Class clz) { + return getMethods(clz, "get"); + } + + private static List getMethods(Class clz, String startWithName) { + List methods = new ArrayList<>(); + for (Method m : clz.getDeclaredMethods()) { + if (m.getName().startsWith(startWithName)) { + methods.add(m); + } + } + return methods; + } + + public static void setParameters(Object o, Map params) { + List methods = getSetterMethods(o.getClass()); + for (String name : params.keySet()) { + String methodName = "set" + name; + for (Method m : methods) { + if (m.getName().equalsIgnoreCase(methodName)) { + try { + m.invoke(o, params.get(name)); + } catch (IllegalAccessException e) { + throw new ReflectionUtilException(e); + } catch (IllegalArgumentException e) { + throw new ReflectionUtilException(e); + } catch (InvocationTargetException e) { + throw new ReflectionUtilException(e); + } + } + } + } + + } + + public static Map getParameterMap(Object o) { + Map params = new HashMap<>(); + List methods = getGetterMethods(o.getClass()); + for (Method m : methods) { + String methodName = m.getName(); + String name = methodName.replaceFirst("get", "").toLowerCase(); + try { + Object value = m.invoke(o); + params.put(name, value); + } catch (IllegalAccessException e) { + throw new ReflectionUtilException(e); + } catch (IllegalArgumentException e) { + throw new ReflectionUtilException(e); + } catch (InvocationTargetException e) { + throw new ReflectionUtilException(e); + } + } + return params; + } + +} diff --git a/group11/1178243325/week02/src/main/java/com/sprint/litestruts/ReflectionUtilException.java b/group11/1178243325/week02/src/main/java/com/sprint/litestruts/ReflectionUtilException.java new file mode 100644 index 0000000000..65cbfdf322 --- /dev/null +++ b/group11/1178243325/week02/src/main/java/com/sprint/litestruts/ReflectionUtilException.java @@ -0,0 +1,20 @@ +package com.sprint.litestruts; + +import java.lang.reflect.InvocationTargetException; +public class ReflectionUtilException extends RuntimeException { + + public ReflectionUtilException(String msg) { + super(msg); + } + public ReflectionUtilException(IllegalAccessException e) { + super(e); + } + + public ReflectionUtilException(IllegalArgumentException e) { + super(e); + } + + public ReflectionUtilException(InvocationTargetException e) { + super(e); + } +} diff --git a/group11/1178243325/week02/src/main/java/com/sprint/litestruts/Struts.java b/group11/1178243325/week02/src/main/java/com/sprint/litestruts/Struts.java new file mode 100644 index 0000000000..bff4dec33b --- /dev/null +++ b/group11/1178243325/week02/src/main/java/com/sprint/litestruts/Struts.java @@ -0,0 +1,53 @@ +package com.sprint.litestruts; + +import java.lang.reflect.Method; +import java.util.Map; +public class Struts { + private final static Configuration cfg = new Configuration("struts.xml"); + public static View runAction(String actionName, Map parameters) { + /* + + 0. 读取配置文件struts.xml + + 1. 根据actionName找到相对应的class , 例如LoginAction, 通过反射实例化(创建对象) + 据parameters中的数据,调用对象的setter方法, 例如parameters中的数据是 + ("name"="test" , "password"="1234") , + 那就应该调用 setName和setPassword方法 + + 2. 通过反射调用对象的exectue 方法, 并获得返回值,例如"success" + + 3. 通过反射找到对象的所有getter方法(例如 getMessage), + 通过反射来调用, 把值和属性形成一个HashMap , 例如 {"message": "登录成功"} , + 放到View对象的parameters + + 4. 根据struts.xml中的 配置,以及execute的返回值, 确定哪一个jsp, + 放到View对象的jsp字段中。 + + */ + + String clzName = cfg.getClassName(actionName); + if (clzName == null) { + return null; + } + + try { + Class clz = Class.forName(clzName); + Object action = clz.newInstance(); + + ReflectionUtil.setParameters(action, parameters); + + Method m = clz.getDeclaredMethod("execute"); + String resultName = (String)m.invoke(action); + + Map params = ReflectionUtil.getParameterMap(action); + String resultView = cfg.getResultView(actionName, resultName); + View view = new View(); + view.setParameters(params); + view.setJsp(resultView); + return view; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/group11/1178243325/week02/src/main/java/com/sprint/litestruts/View.java b/group11/1178243325/week02/src/main/java/com/sprint/litestruts/View.java new file mode 100644 index 0000000000..fb380de515 --- /dev/null +++ b/group11/1178243325/week02/src/main/java/com/sprint/litestruts/View.java @@ -0,0 +1,24 @@ +package com.sprint.litestruts; + +import java.util.Map; +public class View { + private String jsp; + private Map parameters; + + public void setJsp(String jsp) { + this.jsp = jsp; + } + + public String getJsp() { + return jsp; + } + + public void setParameters(Map parameters) { + this.parameters = parameters; + } + + public Map getParameters() { + return parameters; + } + +} diff --git a/group11/1178243325/week02/src/main/resources/struts.xml b/group11/1178243325/week02/src/main/resources/struts.xml new file mode 100644 index 0000000000..c82c7d1574 --- /dev/null +++ b/group11/1178243325/week02/src/main/resources/struts.xml @@ -0,0 +1,12 @@ + + + + /jsp/homepage.jsp + /jsp/showLogin.jsp + + + /jsp/welcome.jsp + /jsp/error.jsp + + + diff --git a/group11/1178243325/week02/src/test/java/com/sprint/array/ArrayUtilTest.java b/group11/1178243325/week02/src/test/java/com/sprint/array/ArrayUtilTest.java new file mode 100644 index 0000000000..9cba21f7cf --- /dev/null +++ b/group11/1178243325/week02/src/test/java/com/sprint/array/ArrayUtilTest.java @@ -0,0 +1,76 @@ +package com.sprint.array; + +import java.util.Arrays; +import org.junit.Assert; +import org.junit.Test; +public class ArrayUtilTest { + + @Test + public void testReverseArray() { + int[] a = new int[]{7, 9, 30, 3}; + int[] expected = new int[]{3, 30, 9, 7}; + ArrayUtil.reverseArray(a); + Assert.assertArrayEquals(a, expected); + a = new int[]{7, 9, 30, 3, 4}; + expected = new int[]{4, 3, 30, 9, 7}; + ArrayUtil.reverseArray(a); + Assert.assertArrayEquals(a, expected); + } + + @Test + public void testRemoveZero() { + int[] oldArr = new int[]{1,3,4,5,0,0,6,6,0,5,4,7,6,7,0,5}; + int[] expected = new int[]{1,3,4,5,6,6,5,4,7,6,7,5}; + Assert.assertArrayEquals(ArrayUtil.removeZero(oldArr), expected); + oldArr = new int[]{1, 0, 2, 0, 3, 0}; + expected = new int[]{1, 2, 3}; + Assert.assertArrayEquals(ArrayUtil.removeZero(oldArr), expected); + } + + @Test + public void testMerge() { + int[] a1 = {3, 5, 7, 8}; + int[] a2 = {4, 5, 6, 7}; + int[] a3 = {3, 4, 5, 6, 7, 8}; + Assert.assertArrayEquals(ArrayUtil.merge(a1, a2), a3); + } + + @Test + public void testGrow() { + int[] oldArray = new int[]{2, 3, 6}; + int[] expected = new int[]{2, 3, 6, 0, 0, 0}; + Assert.assertArrayEquals(ArrayUtil.grow(oldArray, 3), expected); + } + + @Test + public void testFibonacci() { + int[] expected = new int[]{1, 1, 2, 3, 5, 8, 13}; + Assert.assertArrayEquals(ArrayUtil.fibonacci(15), expected); + expected = new int[0]; + Assert.assertArrayEquals(ArrayUtil.fibonacci(1), expected); + /*GET 新技能: [] == new int[0]*/ + System.out.println(Arrays.toString(expected)); + } + + @Test + public void testGetPrimes() { + int[] expected = new int[]{2,3,5,7,11,13,17,19}; + Assert.assertArrayEquals(ArrayUtil.getPrimes(23), expected); + } + + @Test + public void testGetPerfectNumbers() { + int[] result = new int[]{6}; + int length = ArrayUtil.getPerfectNumbers(7).length; + System.out.println(length); + Assert.assertArrayEquals(ArrayUtil.getPerfectNumbers(7), result); + } + + @Test + public void tetJoin() { + String result = "3-8-9"; + int[] array = {3, 8, 9}; + Assert.assertEquals(ArrayUtil.join(array, "-"), result); + } + +} diff --git a/group11/1178243325/week02/src/test/java/com/sprint/litestruts/ConfigurationTest.java b/group11/1178243325/week02/src/test/java/com/sprint/litestruts/ConfigurationTest.java new file mode 100644 index 0000000000..f4b5f91668 --- /dev/null +++ b/group11/1178243325/week02/src/test/java/com/sprint/litestruts/ConfigurationTest.java @@ -0,0 +1,31 @@ +package com.sprint.litestruts; + +import org.junit.Test; +import org.junit.Assert; +public class ConfigurationTest { + Configuration cfg = new Configuration("struts.xml"); + + @Test + public void testGetClassName() { + String clzName = cfg.getClassName("login"); + Assert.assertEquals("com.sprint.litestruts.LoginAction", clzName); + clzName = cfg.getClassName("logout"); + Assert.assertEquals("com.sprint.litestruts.LoginAction", clzName); + } + + @Test + public void testGetResultView() { + String jsp = cfg.getResultView("login", "success"); + Assert.assertEquals("/jsp/homepage.jsp", jsp); + + jsp = cfg.getResultView("login", "fail"); + Assert.assertEquals("/jsp/showLogin.jsp", jsp); + + jsp = cfg.getResultView("logout", "success"); + Assert.assertEquals("/jsp/welcome.jsp", jsp); + + jsp = cfg.getResultView("logout", "error"); + Assert.assertEquals("/jsp/error.jsp", jsp); + } + +} diff --git a/group11/1178243325/week02/src/test/java/com/sprint/litestruts/ReflectionUtilTest.java b/group11/1178243325/week02/src/test/java/com/sprint/litestruts/ReflectionUtilTest.java new file mode 100644 index 0000000000..c6fb04bda6 --- /dev/null +++ b/group11/1178243325/week02/src/test/java/com/sprint/litestruts/ReflectionUtilTest.java @@ -0,0 +1,92 @@ +package com.sprint.litestruts; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.HashSet; +import java.util.HashMap; +import java.util.Set; +import java.util.Map; + + +import org.junit.Test; +import org.junit.Assert; +public class ReflectionUtilTest { + + @Test + public void testGetSetterMethod() throws Exception{ + String name = "com.sprint.litestruts.LoginAction"; + Class clz = Class.forName(name); + List methods = ReflectionUtil.getSetterMethods(clz); + + Assert.assertEquals(2, methods.size()); + + List expectedNames = new ArrayList<>(); + expectedNames.add("setName"); + expectedNames.add("setPassword"); + + Set acctualNames = new HashSet<>(); + for (Method m : methods) { + acctualNames.add(m.getName()); + } + Assert.assertTrue(acctualNames.containsAll(expectedNames)); + } + + @Test + public void testGetGetterMethod() throws Exception { + String name = "com.sprint.litestruts.LoginAction"; + Class clz = Class.forName(name); + List methods = ReflectionUtil.getGetterMethods(clz); + + Assert.assertEquals(3, methods.size()); + + List expectedNames = new ArrayList<>(); + expectedNames.add("getName"); + expectedNames.add("getPassword"); + expectedNames.add("getMessage"); + + Set acctualNames = new HashSet<>(); + for (Method m : methods) { + acctualNames.add(m.getName()); + } + Assert.assertTrue(acctualNames.containsAll(expectedNames)); + } + + @Test + public void testSetParameters() throws Exception { + String name = "com.sprint.litestruts.LoginAction"; + Class clz = Class.forName(name); + Object o = clz.newInstance(); + + Map params = new HashMap<>(); + params.put("name", "test"); + params.put("password", "1234"); + + ReflectionUtil.setParameters(o, params); + Field f = clz.getDeclaredField("name"); + f.setAccessible(true); + Assert.assertEquals("test", f.get(o)); + + f = clz.getDeclaredField("password"); + f.setAccessible(true); + Assert.assertEquals("1234", f.get(o)); + } + + @Test + public void testGetParameters() throws Exception { + String name = "com.sprint.litestruts.LoginAction"; + Class clz = Class.forName(name); + LoginAction action = (LoginAction)clz.newInstance(); + action.setName("test"); + action.setPassword("123456"); + + Map params = ReflectionUtil.getParameterMap(action); + Assert.assertEquals(3, params.size()); + Assert.assertEquals(null, params.get("message")); + Assert.assertEquals("test", params.get("name")); + Assert.assertEquals("123456", params.get("password")); + + } + +} diff --git a/group11/1178243325/week02/src/test/java/com/sprint/litestruts/StrutsTest.java b/group11/1178243325/week02/src/test/java/com/sprint/litestruts/StrutsTest.java new file mode 100644 index 0000000000..d8c68d2807 --- /dev/null +++ b/group11/1178243325/week02/src/test/java/com/sprint/litestruts/StrutsTest.java @@ -0,0 +1,32 @@ +package com.sprint.litestruts; + +import java.util.HashMap; +import java.util.Map; +import org.junit.Assert; +import org.junit.Test; +public class StrutsTest { + + @Test + public void testLoginActionSuccess() { + String actionName = "login"; + Map params = new HashMap<>(); + params.put("name", "test"); + params.put("password", "1234"); + + View view = Struts.runAction(actionName, params); + Assert.assertEquals("/jsp/homepage.jsp", view.getJsp()); + Assert.assertEquals("login successful", view.getParameters().get("message")); + } + + @Test + public void testLoginActionFailed() { + String actionName = "login"; + Map params = new HashMap<>(); + params.put("name", "test"); + params.put("password", "123456"); //密码不一致 + + View view = Struts.runAction(actionName, params); + Assert.assertEquals("/jsp/showLogin.jsp", view.getJsp()); + Assert.assertEquals("login failed,please check your user/pwd", view.getParameters().get("message")); + } +} From 555e2b0f099805682b8ae7b87738ff62d691f9d7 Mon Sep 17 00:00:00 2001 From: chzh88 Date: Mon, 27 Mar 2017 09:39:18 +0800 Subject: [PATCH 019/203] test --- group19/2558178127/src/com/cn/kevin/Test.java | 5 ---- .../2558178127/src/com/cn/kevin/Test1.java | 30 +++++++++++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) delete mode 100644 group19/2558178127/src/com/cn/kevin/Test.java create mode 100644 group19/2558178127/src/com/cn/kevin/Test1.java diff --git a/group19/2558178127/src/com/cn/kevin/Test.java b/group19/2558178127/src/com/cn/kevin/Test.java deleted file mode 100644 index 0fea033fc1..0000000000 --- a/group19/2558178127/src/com/cn/kevin/Test.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.cn.kevin; - -public class Test { - -} diff --git a/group19/2558178127/src/com/cn/kevin/Test1.java b/group19/2558178127/src/com/cn/kevin/Test1.java new file mode 100644 index 0000000000..12fdabde4f --- /dev/null +++ b/group19/2558178127/src/com/cn/kevin/Test1.java @@ -0,0 +1,30 @@ +package com.cn.kevin; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.junit.Test; +public class Test1 { +@Test + public void res(){ + System.out.println("111"); + String regext = "(回Q关闭通知)"; + String con = "【回Q关闭通知,回复按标准资费】"; + System.out.println(regexPattern(regext,con)); + } + +public static boolean regexPattern(String regex, String content) { + boolean isMatch = false; + + try{ + Pattern p = Pattern.compile(regex + ".*"); + Matcher m = p.matcher(content); + if (m.find()) { + isMatch = true; + } + }catch(Exception e){//NOSONAR +// logger.info("marchet err: regex:{}",regex); + return isMatch; + } + return isMatch; +} +} From 0e6cf0946b7a939641df0d6569d0b5d406622efe Mon Sep 17 00:00:00 2001 From: x_zhaohu Date: Mon, 27 Mar 2017 12:00:21 +0800 Subject: [PATCH 020/203] =?UTF-8?q?=E6=95=B4=E7=90=86=E7=AC=AC=E4=B8=89?= =?UTF-8?q?=E5=91=A8=E7=9A=84=E7=9F=A5=E8=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group11/1178243325/week03/build.gradle | 9 + group11/1178243325/week03/readme.md | 16 + .../main/java/com/sprint/basic/Iterator.java | 6 + .../java/com/sprint/basic/LinkedList.java | 319 ++++++++++++++++++ .../src/main/java/com/sprint/basic/List.java | 9 + .../ConcurrentModificationException.java | 9 + .../com/sprint/download/DownloadThread.java | 36 ++ .../com/sprint/download/FileDownloader.java | 89 +++++ .../com/sprint/download/api/Connection.java | 26 ++ .../download/api/ConnectionException.java | 7 + .../download/api/ConnectionManager.java | 11 + .../sprint/download/api/DownloadListener.java | 5 + .../sprint/download/impl/ConnectionImpl.java | 68 ++++ .../download/impl/ConnectionManagerImpl.java | 14 + .../sprint/download/FileDownloaderTest.java | 41 +++ .../sprint/download/api/ConnectionTest.java | 21 ++ 16 files changed, 686 insertions(+) create mode 100644 group11/1178243325/week03/build.gradle create mode 100644 group11/1178243325/week03/readme.md create mode 100644 group11/1178243325/week03/src/main/java/com/sprint/basic/Iterator.java create mode 100644 group11/1178243325/week03/src/main/java/com/sprint/basic/LinkedList.java create mode 100644 group11/1178243325/week03/src/main/java/com/sprint/basic/List.java create mode 100644 group11/1178243325/week03/src/main/java/com/sprint/basic/exception/ConcurrentModificationException.java create mode 100644 group11/1178243325/week03/src/main/java/com/sprint/download/DownloadThread.java create mode 100644 group11/1178243325/week03/src/main/java/com/sprint/download/FileDownloader.java create mode 100644 group11/1178243325/week03/src/main/java/com/sprint/download/api/Connection.java create mode 100644 group11/1178243325/week03/src/main/java/com/sprint/download/api/ConnectionException.java create mode 100644 group11/1178243325/week03/src/main/java/com/sprint/download/api/ConnectionManager.java create mode 100644 group11/1178243325/week03/src/main/java/com/sprint/download/api/DownloadListener.java create mode 100644 group11/1178243325/week03/src/main/java/com/sprint/download/impl/ConnectionImpl.java create mode 100644 group11/1178243325/week03/src/main/java/com/sprint/download/impl/ConnectionManagerImpl.java create mode 100644 group11/1178243325/week03/src/test/java/com/sprint/download/FileDownloaderTest.java create mode 100644 group11/1178243325/week03/src/test/java/com/sprint/download/api/ConnectionTest.java diff --git a/group11/1178243325/week03/build.gradle b/group11/1178243325/week03/build.gradle new file mode 100644 index 0000000000..c4da624f95 --- /dev/null +++ b/group11/1178243325/week03/build.gradle @@ -0,0 +1,9 @@ +apply plugin: 'java' + +repositories { + mavenCentral() +} + +dependencies { + testCompile("junit:junit:4.12") +} diff --git a/group11/1178243325/week03/readme.md b/group11/1178243325/week03/readme.md new file mode 100644 index 0000000000..e418f46fd6 --- /dev/null +++ b/group11/1178243325/week03/readme.md @@ -0,0 +1,16 @@ +## 讲课内容: +- 17-03-07:答疑(YY) +- 17-03-09:TDD和第二次作业讲解 +- 17-03-12:职场15年 + +## 第二周作业(3-6 至 3-12) +- 实现第二个大作业:多线程下载文件,支持断点续传 +- 5道数据结构习题 + +## 完成情况: +- 多线程完成 +- 待重构 + +## 我的收获: +- TTD大法好 +- 面向对象的思想以及抽象化,更深刻 diff --git a/group11/1178243325/week03/src/main/java/com/sprint/basic/Iterator.java b/group11/1178243325/week03/src/main/java/com/sprint/basic/Iterator.java new file mode 100644 index 0000000000..ff93e30377 --- /dev/null +++ b/group11/1178243325/week03/src/main/java/com/sprint/basic/Iterator.java @@ -0,0 +1,6 @@ +package com.coding.basic; + +public interface Iterator { + public boolean hasNext(); + public Object next(); +} diff --git a/group11/1178243325/week03/src/main/java/com/sprint/basic/LinkedList.java b/group11/1178243325/week03/src/main/java/com/sprint/basic/LinkedList.java new file mode 100644 index 0000000000..ac4128fe80 --- /dev/null +++ b/group11/1178243325/week03/src/main/java/com/sprint/basic/LinkedList.java @@ -0,0 +1,319 @@ +package com.sprint.basic; + +import com.sprint.basic.exception.ConcurrentModificationException; +import java.util.Objects; +public class LinkedList implements List { + + private Node head; + private int size; + public LinkedList() { + head = new Node(null, null); + size = 0; + } + + public void add(Object o){ + add(size, o); + } + + public void add(int index , Object o){ + if (index > size || index < 0) { + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + } + Node frontNode = getNode(index-1); + Node newNode = new Node(o, frontNode.next); + frontNode.next = newNode; + size++; + + } + + /*getNode getPreNodeByElement getNextNodeByElement的效率低些*/ + private Node getNode(int index) { + Node node = head; + int i = 0; + while(node.next != null && i <= index) { + node = node.next; + i++; + } + return node; + } + + private Node getPreNodeByElement(Object obj) { + if (obj != null) { + for (int i = 0; i < size(); i++) { + if (getNode(i).data == obj) { + return getNode(i-1); + } + } + } + return null; + } + + private Node getNextNodeByElement(Object obj) { + if (obj != null) { + for (int i = 0; i < size(); i++) { + if (getNode(i).data == obj) { + return getNode(i+1); + } + } + } + return null; + } + public Object get(int index){ + if (index >= size || index < 0) { + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + } + + Node node = getNode(index); + return node.data; + } + + public Object remove(int index){ + if (index >= size || index < 0) { + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + } + Node frontNode = getNode(index-1); + Node oldNode = getNode(index); + frontNode.next = oldNode.next; + size--; + return oldNode.data; + } + + public int size(){ + return size; + } + + public void addFirst(Object o){ + add(0, o); + } + + public void addLast(Object o){ + add(size, o); + } + + public Object removeFirst(){ + return remove(0); + } + + public Object removeLast(){ + return remove(size-1); + } + + public Iterator iterator(){ + return new LinkedListIterator(); + } + + private class LinkedListIterator implements Iterator { + int index; + final int capacity = size; + LinkedListIterator() { + index = 0; + } + @Override + public boolean hasNext() { + if (capacity != size) + throw new ConcurrentModificationException("此对象没有修改同步"); + return index < capacity; + } + + @Override + public Object next() { + if (capacity != size) + throw new ConcurrentModificationException("此对象没有修改同步"); + if (index >= capacity) + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + return get(index++); + } + } + + private String outOfBoundsMsg(int index) { + return "index:" + index + ", size:" + size; + } + + private static class Node { + Object data; + Node next; + + Node(Object data, Node next) { + this.data = data; + this.next = next; + } + + void setData(Object data) { + this.data = data; + } + + Object getData() { + return data; + } + + void setNext(Node next) { + this.next = next; + } + + Object getNext() { + return next; + } + } + + + /** + * 把该链表逆置 + * 例如链表为 3->7->10 , 逆置后变为 10->7->3 + */ + public void reverse(){ + Object[] oldData = new Object[size]; + Node temp = head; + int index = 1; + while(temp.next != null) { + temp = temp.next; + oldData[size - index] = temp.data; + index++; + } + + index = 0; + temp = head; + while(temp.next != null) { + temp = temp.next; + temp.data = oldData[index]; + index++; + } + } + + /** + * 删除一个单链表的前半部分 + * 例如:list = 2->5->7->8 , 删除以后的值为 7->8 + * 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10 + */ + + public void removeFirstHalf(){ + int count = size; + if (count % 2 != 0) { + for (int i = 0; i <= count/2; i++) { + removeFirst(); + } + } else { + for (int i = 0; i < count/2; i++) { + removeFirst(); + } + } + } + + /** + * 从第i个元素开始, 删除length 个元素 , 注意i从0开始 + * @param i + * @param length + */ + + public void remove(int i, int length){ + if (i < 0 || length < 0) { + return; + } + if (i == 0) { + for (int k = 0; k < length; k++) + removeFirst(); + } else { + while (length > 0) { + remove(i-1); + length--; + } + } + } + + /** + * 假定当前链表和list均包含已升序排列的整数 + * 从当前链表中取出那些list所指定的元素 + * 例如当前链表 = 11->101->201->301->401->501->601->701 + * listB = 1->3->4->6 + * 返回的结果应该是[101,301,401,601] + * @param list + */ + + public int[] getElements(LinkedList list){ + if (list.size() == 0) { + return new int[0]; + } + int[] array = new int[list.size()]; + int index = 0; + for (int i = 0; i < list.size(); i++) { + array[i] = (int)get((int)list.get(i)); + } + return array; + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 从当前链表中中删除在list中出现的元素 + * @param list + */ + public void subtract(LinkedList list){ + if (list.size() == 0) { + return; + } + for (int i = 0; i < list.size(); i++) { + removeElement(list.get(i)); + } + } + + private Object removeElement(Object obj) { + if (obj == null) { + return null; + } + Node preNode = getPreNodeByElement(obj); + Node nextNode = getNextNodeByElement(obj); + if (preNode == null && nextNode == null) + return null; + preNode.next = nextNode; + return obj; + } + + + /** + * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) + */ + + public void removeDuplicateValues(){ + if (size == 0 || size == 1) { + return; + } + + Node p1 = head; + Node p2 = head.next; + + while (p1 != null && p2 != null) { + if (Objects.equals(p1.data, p2.data)) { + p2 = p2.next; + p1.next = p2; + size--; + } else { + p1 = p2; + p2 = p2.next; + } + } + } + + + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 试写一高效的算法,删除表中所有值大于min且小于max的元素(若表中存在这样的元素) + * @param min + * @param max + */ + + public void removeRange(int min, int max){ + } + + + /** + * 假设当前链表和参数list指定的链表均以元素依值递增有序排列(同一表中的元素值各不相同) + * 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列 + * @param list + */ + + public LinkedList intersection( LinkedList list){ + + return null; + + } +} diff --git a/group11/1178243325/week03/src/main/java/com/sprint/basic/List.java b/group11/1178243325/week03/src/main/java/com/sprint/basic/List.java new file mode 100644 index 0000000000..396b1f6416 --- /dev/null +++ b/group11/1178243325/week03/src/main/java/com/sprint/basic/List.java @@ -0,0 +1,9 @@ +package com.coding.basic; + +public interface List { + public void add(Object o); + public void add(int index, Object o); + public Object get(int index); + public Object remove(int index); + public int size(); +} diff --git a/group11/1178243325/week03/src/main/java/com/sprint/basic/exception/ConcurrentModificationException.java b/group11/1178243325/week03/src/main/java/com/sprint/basic/exception/ConcurrentModificationException.java new file mode 100644 index 0000000000..f1c5c79721 --- /dev/null +++ b/group11/1178243325/week03/src/main/java/com/sprint/basic/exception/ConcurrentModificationException.java @@ -0,0 +1,9 @@ +package com.coding.basic.exception; + +public class ConcurrentModificationException extends RuntimeException { + public ConcurrentModificationException() {} + public ConcurrentModificationException(String msg) { + super(msg); + } +} + diff --git a/group11/1178243325/week03/src/main/java/com/sprint/download/DownloadThread.java b/group11/1178243325/week03/src/main/java/com/sprint/download/DownloadThread.java new file mode 100644 index 0000000000..434b60e7be --- /dev/null +++ b/group11/1178243325/week03/src/main/java/com/sprint/download/DownloadThread.java @@ -0,0 +1,36 @@ +package com.sprint.download; + +import com.sprint.download.api.Connection; +import java.io.RandomAccessFile; +import java.util.concurrent.CyclicBarrier; +public class DownloadThread extends Thread { + Connection conn; + int startPos; + int endPos; + CyclicBarrier barrier; + String localFile; + public DownloadThread(Connection conn, int startPos, int endPos, + String localFile, CyclicBarrier barrier) { + this.conn = conn; + this.startPos = startPos; + this.endPos = endPos; + this.localFile = localFile; + this.barrier = barrier; + } + + @Override + public void run() { + try { + System.out.println("Begin to read [" + startPos + "-" + endPos + "]"); + byte[] data = conn.read(startPos, endPos); + RandomAccessFile file = new RandomAccessFile(localFile, "rw"); + file.seek(startPos); + file.write(data); + file.close(); + conn.close(); + barrier.await(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/group11/1178243325/week03/src/main/java/com/sprint/download/FileDownloader.java b/group11/1178243325/week03/src/main/java/com/sprint/download/FileDownloader.java new file mode 100644 index 0000000000..9a817aefaf --- /dev/null +++ b/group11/1178243325/week03/src/main/java/com/sprint/download/FileDownloader.java @@ -0,0 +1,89 @@ +package com.sprint.download; + +import com.sprint.download.api.Connection; +import com.sprint.download.api.ConnectionManager; +import com.sprint.download.api.DownloadListener; +import java.util.concurrent.CyclicBarrier; +import java.io.RandomAccessFile; +import java.io.IOException; +public class FileDownloader { + private String url; + private String localFile; + + DownloadListener listener; + ConnectionManager cm; + + private static final int DOWNLOAD_THREAD_NUM = 3; + + public FileDownloader(String _url, String localFile) { + this.url = _url; + this.localFile = localFile; + } + + public void execute() { + CyclicBarrier barrier = new CyclicBarrier(DOWNLOAD_THREAD_NUM, new Runnable() { + public void run() { + listener.notifyFinished(); + } + }); + + Connection conn = null; + + try { + conn = cm.open(this.url); + int length = conn.getContentLength(); + createPlaceHolderFile(this.localFile, length); + int[][] ranges = allocateDownloadRange(DOWNLOAD_THREAD_NUM, length); + for (int i = 0; i < DOWNLOAD_THREAD_NUM; i++) { + DownloadThread thread = new DownloadThread( + cm.open(url), + ranges[i][0], + ranges[i][1], + localFile, + barrier); + thread.start(); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (conn != null) { + conn.close(); + } + } + } + + private void createPlaceHolderFile(String fileName, int contentLen) throws IOException { + RandomAccessFile file = new RandomAccessFile(fileName, "rw"); + for (int i = 0; i < contentLen; i++) { + file.write(0); + } + file.close(); + } + + private int[][] allocateDownloadRange(int threadNum, int contentLen) { + int[][] ranges = new int[threadNum][2]; + int eachThreadSize = contentLen / threadNum; + int left = contentLen % threadNum; + for (int i = 0; i < threadNum; i++) { + int startPos = i*eachThreadSize; + int endPos = (i+1) * eachThreadSize - 1; + if (i == (threadNum -1)) { + endPos += left; + } + ranges[i][0] = startPos; + ranges[i][1] = endPos; + } + return ranges; + } + public void setListener(DownloadListener listener) { + this.listener = listener; + } + + public void setConnectionManager(ConnectionManager ucm) { + this.cm = ucm; + } + + public DownloadListener getListener() { + return listener; + } +} diff --git a/group11/1178243325/week03/src/main/java/com/sprint/download/api/Connection.java b/group11/1178243325/week03/src/main/java/com/sprint/download/api/Connection.java new file mode 100644 index 0000000000..958a0b1ce3 --- /dev/null +++ b/group11/1178243325/week03/src/main/java/com/sprint/download/api/Connection.java @@ -0,0 +1,26 @@ +package com.sprint.download.api; + +import java.io.IOException; +public interface Connection { + /** + * 给定开始位置和结束位置,读取数据,返回值是字节 + * @param startPos 开始位置, 从0开始 + * @param endPos 结束位置 + * @return + */ + + public byte[] read(int startPos, int endPos) throws IOException; + + /** + * 得到数据内容的长度 + * @return + */ + + public int getContentLength(); + + /** + * 关闭连接 + */ + + public void close(); +} diff --git a/group11/1178243325/week03/src/main/java/com/sprint/download/api/ConnectionException.java b/group11/1178243325/week03/src/main/java/com/sprint/download/api/ConnectionException.java new file mode 100644 index 0000000000..f9ec627440 --- /dev/null +++ b/group11/1178243325/week03/src/main/java/com/sprint/download/api/ConnectionException.java @@ -0,0 +1,7 @@ +package com.sprint.download.api; + +public class ConnectionException extends Exception { + public ConnectionException(Exception e) { + super(e); + } +} diff --git a/group11/1178243325/week03/src/main/java/com/sprint/download/api/ConnectionManager.java b/group11/1178243325/week03/src/main/java/com/sprint/download/api/ConnectionManager.java new file mode 100644 index 0000000000..f20bbacc87 --- /dev/null +++ b/group11/1178243325/week03/src/main/java/com/sprint/download/api/ConnectionManager.java @@ -0,0 +1,11 @@ +package com.sprint.download.api; + +public interface ConnectionManager { + /** + * 给定一个url, 打开一个连接 + * @param url + * @return + */ + + public Connection open(String url) throws ConnectionException; +} diff --git a/group11/1178243325/week03/src/main/java/com/sprint/download/api/DownloadListener.java b/group11/1178243325/week03/src/main/java/com/sprint/download/api/DownloadListener.java new file mode 100644 index 0000000000..fc95ba8199 --- /dev/null +++ b/group11/1178243325/week03/src/main/java/com/sprint/download/api/DownloadListener.java @@ -0,0 +1,5 @@ +package com.sprint.download.api; + +public interface DownloadListener { + public void notifyFinished(); +} diff --git a/group11/1178243325/week03/src/main/java/com/sprint/download/impl/ConnectionImpl.java b/group11/1178243325/week03/src/main/java/com/sprint/download/impl/ConnectionImpl.java new file mode 100644 index 0000000000..c6c1f32cb4 --- /dev/null +++ b/group11/1178243325/week03/src/main/java/com/sprint/download/impl/ConnectionImpl.java @@ -0,0 +1,68 @@ +package com.sprint.download.impl; + +import com.sprint.download.api.Connection; +import com.sprint.download.api.ConnectionException; +import java.util.Arrays; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.net.HttpURLConnection; + +public class ConnectionImpl implements Connection { + + URL url; + static final int BUFFER_SIZE = 1024; + + ConnectionImpl(String _url) throws ConnectionException { + try { + url = new URL(_url); + } catch (MalformedURLException e) { + throw new ConnectionException(e); + } + } + + @Override + public byte[] read(int startPos, int endPos) throws IOException { + HttpURLConnection httpConn = (HttpURLConnection)url.openConnection(); + httpConn.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos); + + InputStream is = httpConn.getInputStream(); + byte[] buff = new byte[BUFFER_SIZE]; + int totalLen = endPos - startPos + 1; + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + while (baos.size() < totalLen) { + int len = is.read(buff); + if (len < 0) { + break; + } + baos.write(buff, 0, len); + } + + if (baos.size() > totalLen) { + byte[] data = baos.toByteArray(); + return Arrays.copyOf(data, totalLen); + } + return baos.toByteArray(); + } + + @Override + public int getContentLength() { + URLConnection con; + try { + con = url.openConnection(); + return con.getContentLength(); + } catch (IOException e) { + e.printStackTrace(); + } + return -1; + } + + @Override + public void close() { + + } +} diff --git a/group11/1178243325/week03/src/main/java/com/sprint/download/impl/ConnectionManagerImpl.java b/group11/1178243325/week03/src/main/java/com/sprint/download/impl/ConnectionManagerImpl.java new file mode 100644 index 0000000000..7a012808ef --- /dev/null +++ b/group11/1178243325/week03/src/main/java/com/sprint/download/impl/ConnectionManagerImpl.java @@ -0,0 +1,14 @@ +package com.sprint.download.impl; + +import com.sprint.download.api.Connection; +import com.sprint.download.api.ConnectionException; +import com.sprint.download.api.ConnectionManager; +public class ConnectionManagerImpl implements ConnectionManager { + + @Override + public Connection open(String url) throws ConnectionException { + return new ConnectionImpl(url); + } +} + + diff --git a/group11/1178243325/week03/src/test/java/com/sprint/download/FileDownloaderTest.java b/group11/1178243325/week03/src/test/java/com/sprint/download/FileDownloaderTest.java new file mode 100644 index 0000000000..6e3bccd2dc --- /dev/null +++ b/group11/1178243325/week03/src/test/java/com/sprint/download/FileDownloaderTest.java @@ -0,0 +1,41 @@ +package com.sprint.download; + +import com.sprint.download.api.ConnectionManager; +import com.sprint.download.api.DownloadListener; +import com.sprint.download.impl.ConnectionManagerImpl; + +import org.junit.Assert; +import org.junit.Test; +public class FileDownloaderTest { + boolean downloadFinished = false; + + @Test + public void testDownload() { + String url = "http://images2015.cnblogs.com/blog/610238/201604/610238-20160421154632101-286208268.png"; + FileDownloader downloader = new FileDownloader(url, "/home/sprint/xxx/test.jpg");// 保存地址时我的本地地址 + + ConnectionManager cm = new ConnectionManagerImpl(); + downloader.setConnectionManager(cm); + + downloader.setListener(new DownloadListener() { + @Override + public void notifyFinished() { + downloadFinished = false; + } + }); + + downloader.execute(); + + //等待多线程下载 + while (!downloadFinished) { + try { + System.out.println("还没有下载完成,休眠五秒"); + //休眠5秒 + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + System.out.println("下载完成!"); + } +} diff --git a/group11/1178243325/week03/src/test/java/com/sprint/download/api/ConnectionTest.java b/group11/1178243325/week03/src/test/java/com/sprint/download/api/ConnectionTest.java new file mode 100644 index 0000000000..4322814936 --- /dev/null +++ b/group11/1178243325/week03/src/test/java/com/sprint/download/api/ConnectionTest.java @@ -0,0 +1,21 @@ +package com.sprint.download.api; + +import com.sprint.download.impl.ConnectionManagerImpl; +import org.junit.Assert; +import org.junit.Test; +public class ConnectionTest { + + @Test + public void testGetContentLength() throws Exception { + ConnectionManager connMan = new ConnectionManagerImpl(); + Connection conn = connMan.open("http://www.hinews.cn/pic/0/13/91/26/13912621_821796.jpg"); + Assert.assertEquals(35470, conn.getContentLength()); + } + + @Test + public void testRead() throws Exception { + ConnectionManager connMan = new ConnectionManagerImpl(); + Connection conn = connMan.open("http://www.hinews.cn/pic/0/13/91/26/13912621_821796.jpg"); + + } +} From 1e9c327afe8dc62739d5f3cfdec7af5122f4da6c Mon Sep 17 00:00:00 2001 From: x_zhaohu Date: Mon, 27 Mar 2017 12:08:08 +0800 Subject: [PATCH 021/203] ok --- group11/1178243325/week04/readme.md | 12 ++++++++++++ group11/1178243325/week05/readme.md | 13 +++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 group11/1178243325/week04/readme.md create mode 100644 group11/1178243325/week05/readme.md diff --git a/group11/1178243325/week04/readme.md b/group11/1178243325/week04/readme.md new file mode 100644 index 0000000000..72c186be44 --- /dev/null +++ b/group11/1178243325/week04/readme.md @@ -0,0 +1,12 @@ +####讲课内容: +- 17-03-15:第三次作业讲解 +- 17-03-19:Edison分享的职业发展 + +####第四周作业(3-13 至 3-19) +无,调整进度 + +####完成情况: +休养生息 + +####我的收获: +- 职业发展:从新人到老兵 diff --git a/group11/1178243325/week05/readme.md b/group11/1178243325/week05/readme.md new file mode 100644 index 0000000000..d4388e66d7 --- /dev/null +++ b/group11/1178243325/week05/readme.md @@ -0,0 +1,13 @@ +## 讲课内容: +- 17-03-22 :漫谈操作系统之虚拟内存 +- 17-03-26 :概要性介绍class文件结构和字节码的执行过程 + +## 第五周作业(3-20 至 3-26) +无,调整进度 + +## 完成情况: +修养生息 + +## 我的收获: +- 虚拟内存 +- 进一步理解JVM From dad02b76d62d045695eb69fe6fab4617b271a53f Mon Sep 17 00:00:00 2001 From: x_zhaohu Date: Mon, 27 Mar 2017 12:11:22 +0800 Subject: [PATCH 022/203] finished --- group11/1178243325/DataStructure/build.gradle | 20 -- group11/1178243325/DataStructure/readme.md | 1 - .../DataStructure/src/main/java/com/Main.java | 17 -- .../java/com/coderising/array/ArrayUtil.java | 229 -------------- .../coderising/litestruts/LoginAction.java | 39 --- .../com/coderising/litestruts/Struts.java | 62 ---- .../com/coderising/litestruts/StrutsTest.java | 43 --- .../java/com/coderising/litestruts/View.java | 23 -- .../com/coderising/litestruts/XmlUtil.java | 59 ---- .../java/com/coderising/litestruts/struts.xml | 11 - .../com/coding/basic/.LinkedList.java.swp | Bin 16384 -> 0 bytes .../main/java/com/coding/basic/ArrayList.java | 97 ------ .../java/com/coding/basic/BinaryTreeNode.java | 33 -- .../main/java/com/coding/basic/Iterator.java | 6 - .../java/com/coding/basic/LinkedList.java | 289 ------------------ .../src/main/java/com/coding/basic/List.java | 9 - .../src/main/java/com/coding/basic/Queue.java | 30 -- .../src/main/java/com/coding/basic/Stack.java | 38 --- .../ConcurrentModificationException.java | 9 - .../basic/exception/EmptyQueueException.java | 8 - .../basic/exception/EmptyStackException.java | 8 - .../src/main/resources/struts.xml | 11 - group11/1178243325/DataStructure/struts.xml | 11 - group11/1178243325/week01/.readme.md.swp | Bin 12288 -> 0 bytes group11/1178243325/week04/readme.md | 8 +- 25 files changed, 4 insertions(+), 1057 deletions(-) delete mode 100644 group11/1178243325/DataStructure/build.gradle delete mode 100644 group11/1178243325/DataStructure/readme.md delete mode 100644 group11/1178243325/DataStructure/src/main/java/com/Main.java delete mode 100644 group11/1178243325/DataStructure/src/main/java/com/coderising/array/ArrayUtil.java delete mode 100644 group11/1178243325/DataStructure/src/main/java/com/coderising/litestruts/LoginAction.java delete mode 100644 group11/1178243325/DataStructure/src/main/java/com/coderising/litestruts/Struts.java delete mode 100644 group11/1178243325/DataStructure/src/main/java/com/coderising/litestruts/StrutsTest.java delete mode 100644 group11/1178243325/DataStructure/src/main/java/com/coderising/litestruts/View.java delete mode 100644 group11/1178243325/DataStructure/src/main/java/com/coderising/litestruts/XmlUtil.java delete mode 100644 group11/1178243325/DataStructure/src/main/java/com/coderising/litestruts/struts.xml delete mode 100644 group11/1178243325/DataStructure/src/main/java/com/coding/basic/.LinkedList.java.swp delete mode 100644 group11/1178243325/DataStructure/src/main/java/com/coding/basic/ArrayList.java delete mode 100644 group11/1178243325/DataStructure/src/main/java/com/coding/basic/BinaryTreeNode.java delete mode 100644 group11/1178243325/DataStructure/src/main/java/com/coding/basic/Iterator.java delete mode 100644 group11/1178243325/DataStructure/src/main/java/com/coding/basic/LinkedList.java delete mode 100644 group11/1178243325/DataStructure/src/main/java/com/coding/basic/List.java delete mode 100644 group11/1178243325/DataStructure/src/main/java/com/coding/basic/Queue.java delete mode 100644 group11/1178243325/DataStructure/src/main/java/com/coding/basic/Stack.java delete mode 100644 group11/1178243325/DataStructure/src/main/java/com/coding/basic/exception/ConcurrentModificationException.java delete mode 100644 group11/1178243325/DataStructure/src/main/java/com/coding/basic/exception/EmptyQueueException.java delete mode 100644 group11/1178243325/DataStructure/src/main/java/com/coding/basic/exception/EmptyStackException.java delete mode 100644 group11/1178243325/DataStructure/src/main/resources/struts.xml delete mode 100644 group11/1178243325/DataStructure/struts.xml delete mode 100644 group11/1178243325/week01/.readme.md.swp diff --git a/group11/1178243325/DataStructure/build.gradle b/group11/1178243325/DataStructure/build.gradle deleted file mode 100644 index 9c6bc859e6..0000000000 --- a/group11/1178243325/DataStructure/build.gradle +++ /dev/null @@ -1,20 +0,0 @@ - -apply plugin: 'java' -apply plugin: 'eclipse' - -jar { - from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }} - manifest { - attributes 'Main-Class' : 'com.Main' - } -} - -repositories { - mavenCentral() -} - -dependencies { - compile 'junit:junit:4.12' - compile 'dom4j:dom4j:1.6.1' -} - diff --git a/group11/1178243325/DataStructure/readme.md b/group11/1178243325/DataStructure/readme.md deleted file mode 100644 index 29ad9d5c06..0000000000 --- a/group11/1178243325/DataStructure/readme.md +++ /dev/null @@ -1 +0,0 @@ -实现基本的数据结构ArrayList,LinkList,Stack,Queue,Tree,Iterator diff --git a/group11/1178243325/DataStructure/src/main/java/com/Main.java b/group11/1178243325/DataStructure/src/main/java/com/Main.java deleted file mode 100644 index 8d49de33c4..0000000000 --- a/group11/1178243325/DataStructure/src/main/java/com/Main.java +++ /dev/null @@ -1,17 +0,0 @@ -package com; - -import com.coding.basic.LinkedList; -import com.coding.basic.Iterator; -public class Main { - public static void main(String[] args) { - LinkedList list = new LinkedList(); - - for(int i = 0; i < 10; i++) - list.add(i); - list.remove(2, 5); - Iterator iter = list.iterator(); - while(iter.hasNext()) { - System.out.println(iter.next()); - } - } -} diff --git a/group11/1178243325/DataStructure/src/main/java/com/coderising/array/ArrayUtil.java b/group11/1178243325/DataStructure/src/main/java/com/coderising/array/ArrayUtil.java deleted file mode 100644 index f94d5d01c4..0000000000 --- a/group11/1178243325/DataStructure/src/main/java/com/coderising/array/ArrayUtil.java +++ /dev/null @@ -1,229 +0,0 @@ -package com.coderising.array; - -public class ArrayUtil { - - /** - * 给定一个整形数组a , 对该数组的值进行置换 - 例如: a = [7, 9 , 30, 3] , 置换后为 [3, 30, 9,7] - 如果 a = [7, 9, 30, 3, 4] , 置换后为 [4,3, 30 , 9,7] - * @param origin - * @return - */ - public static void reverseArray(int[] origin){ - if (origin == null) { - return; - } - - int length = origin.length; - int[] temp = new int[length]; - for (int i = 0; i < length; i++) - temp[i] = origin[i]; - for (int i = length - 1, j = 0; i >= 0 && j < length; i--, j++) - origin[j] = temp[i]; - } - - /** - * 现在有如下的一个数组: int oldArr[]={1,3,4,5,0,0,6,6,0,5,4,7,6,7,0,5} - * 要求将以上数组中值为0的项去掉,将不为0的值存入一个新的数组,生成的新数组为: - * {1,3,4,5,6,6,5,4,7,6,7,5} - * @param oldArray - * @return - */ - - public static int[] removeZero(int[] oldArray){ - if (oldArray == null) { - return null; - } - - int zeroCount = 0; - for (int i = 0; i < oldArray.length; i++) { - if (oldArray[i] == 0) - zeroCount++; - } - int[] newArray = new int[oldArray.length-zeroCount]; - for (int i = 0, j = 0; i < oldArray.length && j < newArray.length; i++) { - if (oldArray[i] != 0) { - newArray[j] = oldArray[i]; - j++; - } - } - return newArray; - } - - /** - * 给定两个已经排序好的整形数组, a1和a2 , 创建一个新的数组a3, 使得a3 包含a1和a2 的所有元素, 并且仍然是有序的 - * 例如 a1 = [3, 5, 7,8] a2 = [4, 5, 6,7] 则 a3 为[3,4,5,6,7,8] , 注意: 已经消除了重复 - * @param array1 - * @param array2 - * @return - */ - - public static int[] merge(int[] array1, int[] array2){ - if (array1 == null && array2 == null) - return null; - int index1 = 0, index2 = 0; - int[] array3 = new int[array1.length + array2.length]; - int index = 0; - while (index1 != array1.length && index2 != array2.length) { - if (array1[index1] < array2[index2]) { - array3[index++] = array1[index1++]; - } else if (array1[index1] > array2[index2]) { - array3[index++] = array2[index2++]; - } else if (array1[index1] == array2[index2]){ - array3[index++] = array1[index1++]; - index2++; - } - } - - if (index1 == array1.length && index2 != array2.length) { - for (int i = index2; i < array2.length; i++) - array3[index++] = array2[i]; - } else if (index2 == array2.length && index1 != array1.length) { - for (int i = index1; i < array1.length; i++) { - array3[index++] = array1[i]; - } - } - - int[] newArray = new int[index]; - for (int i = 0; i < newArray.length; i++) - newArray[i] = array3[i]; - return newArray; - } - /** - * 把一个已经存满数据的数组 oldArray的容量进行扩展, 扩展后的新数据大小为oldArray.length + size - * 注意,老数组的元素在新数组中需要保持 - * 例如 oldArray = [2,3,6] , size = 3,则返回的新数组为 - * [2,3,6,0,0,0] - * - * @param oldArray - * @param size - * @return - */ - public static int[] grow(int [] oldArray, int size){ - if (size <= 0) - return null; - int[] newArray = new int[oldArray.length + size]; - for (int i = 0; i < oldArray.length; i++) { - newArray[i] = oldArray[i]; - } - return newArray; - } - - /** - * 斐波那契数列为:1,1,2,3,5,8,13,21...... ,给定一个最大值, 返回小于该值的数列 - * 例如, max = 15 , 则返回的数组应该为 [1,1,2,3,5,8,13] - * max = 1, 则返回空数组 [] - * @param max - * @return - */ - public static int[] fibonacci(int max){ - if (max < 1) - return null; - if (max == 1) - return null; - int[] array = new int[max]; - int i = 0; - int value = fibonaccis(i+1); - while ( value < max) { - array[i++] = value; - value = fibonaccis(i+1); - } - int[] newArray = new int[i]; - for (int j = 0; j < newArray.length; j++) { - newArray[j] = array[j]; - } - return newArray; - } - - private static int fibonaccis(int n) { - if (n <=0) - return 0; - if (n == 1 || n ==2 ) - return 1; - return fibonaccis(n-1)+fibonaccis(n-2); - } - - /** - * 返回小于给定最大值max的所有素数数组 - * 例如max = 23, 返回的数组为[2,3,5,7,11,13,17,19] - * @param max - * @return - */ - public static int[] getPrimes(int max){ - if (max <= 1) { - return null; - } - int[] array = new int[max]; - int index = 0; - for (int i = 2; i < max; i++) { - if (i == 2 || i == 3 || i == 5 || i == 7) - array[index++] = i; - if (i%2 !=0 && i%3 != 0 && i%5 != 0 && i%7 != 0) - array[index++] = i; - } - int[] newArray = new int[index]; - for (int i = 0; i < newArray.length; i++) { - newArray[i] = array[i]; - } - - return newArray; - } - - /** - * 所谓“完数”, 是指这个数恰好等于它的因子之和,例如6=1+2+3 - * 给定一个最大值max, 返回一个数组, 数组中是小于max 的所有完数 - * @param max - * @return - */ - public static int[] getPerfectNumbers(int max){ - if (max <= 0) - return null; - int[] array = new int[max]; - int index = 0; - for (int i = 1; i < max; i++) { - if (isPerfectNumber(i)) - array[index++] = i; - } - - int[] newArray = new int[index]; - for (int i = 0; i < newArray.length; i++) - newArray[i] = array[i]; - - return newArray; - } - - private static boolean isPerfectNumber(int n) { - int sum = 0; - int i = 1; - while (i < n) { - if (n%i == 0) - sum += i; - i++; - } - if (sum == n) - return true; - return false; - } - /** - * 用seperator 把数组 array给连接起来 - * 例如array= [3,8,9], seperator = "-" - * 则返回值为"3-8-9" - * @param array - * @param s - * @return - */ - public static String join(int[] array, String seperator){ - if (array == null) - return null; - StringBuilder str = new StringBuilder(); - for (int i = 0; i < array.length; i++) { - if (i == array.length-1) - str.append(array[i]); - else - str.append(array[i] + seperator); - } - return str.toString(); - } - - -} diff --git a/group11/1178243325/DataStructure/src/main/java/com/coderising/litestruts/LoginAction.java b/group11/1178243325/DataStructure/src/main/java/com/coderising/litestruts/LoginAction.java deleted file mode 100644 index 1005f35a29..0000000000 --- a/group11/1178243325/DataStructure/src/main/java/com/coderising/litestruts/LoginAction.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.coderising.litestruts; - -/** - * 这是一个用来展示登录的业务类, 其中的用户名和密码都是硬编码的。 - * @author liuxin - * - */ -public class LoginAction{ - private String name ; - private String password; - private String message; - - public String getName() { - return name; - } - - public String getPassword() { - return password; - } - - public String execute(){ - if("test".equals(name) && "1234".equals(password)){ - this.message = "login successful"; - return "success"; - } - this.message = "login failed,please check your user/pwd"; - return "fail"; - } - - public void setName(String name){ - this.name = name; - } - public void setPassword(String password){ - this.password = password; - } - public String getMessage(){ - return this.message; - } -} diff --git a/group11/1178243325/DataStructure/src/main/java/com/coderising/litestruts/Struts.java b/group11/1178243325/DataStructure/src/main/java/com/coderising/litestruts/Struts.java deleted file mode 100644 index b3bd421435..0000000000 --- a/group11/1178243325/DataStructure/src/main/java/com/coderising/litestruts/Struts.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.coderising.litestruts; - -import java.util.Map; -import java.util.HashMap; -import java.lang.reflect.Method; -public class Struts { - - public static View runAction(String actionName, Map parameters) { - - /* - - 0. 读取配置文件struts.xml*/ - /* - 1. 根据actionName找到相对应的class , 例如LoginAction, 通过反射实例化(创建对象) - 据parameters中的数据,调用对象的setter方法, 例如parameters中的数据是 - ("name"="test" , "password"="1234") , - 那就应该调用 setName和setPassword方法 - - 2. 通过反射调用对象的exectue 方法, 并获得返回值,例如"success" - - 3. 通过反射找到对象的所有getter方法(例如 getMessage), - 通过反射来调用, 把值和属性形成一个HashMap , 例如 {"message": "登录成功"} , - 放到View对象的parameters - - 4. 根据struts.xml中的 配置,以及execute的返回值, 确定哪一个jsp, - 放到View对象的jsp字段中。 - - */ - try { - String targetClassName = XmlUtil.parseXML("struts.xml", actionName); - Class targetClass = Class.forName(targetClassName); - - Method setName = targetClass.getMethod("setName", String.class); - Method setPassword = targetClass.getMethod("setPassword", String.class); - Object object = targetClass.newInstance(); - - setName.invoke(object, parameters.get("name")); - setPassword.invoke(object, parameters.get("password")); - - Method execute = targetClass.getMethod("execute"); - String result = (String)execute.invoke(object); - - Method getMessage = targetClass.getMethod("getMessage"); - String message = (String)getMessage.invoke(object); - - Map params = new HashMap(); - params.put("message", message); - String jspUrl = XmlUtil.getJspUrl("struts.xml", actionName, result); - View view = new View(); - view.setJsp(jspUrl); - view.setParameters(params); - return view; - - } catch (Exception e) { - e.printStackTrace(); - } - - - return null; - } - -} diff --git a/group11/1178243325/DataStructure/src/main/java/com/coderising/litestruts/StrutsTest.java b/group11/1178243325/DataStructure/src/main/java/com/coderising/litestruts/StrutsTest.java deleted file mode 100644 index a44c1878ac..0000000000 --- a/group11/1178243325/DataStructure/src/main/java/com/coderising/litestruts/StrutsTest.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.coderising.litestruts; - -import java.util.HashMap; -import java.util.Map; - -import org.junit.Assert; -import org.junit.Test; - - - - - -public class StrutsTest { - - @Test - public void testLoginActionSuccess() { - - String actionName = "login"; - - Map params = new HashMap(); - params.put("name","test"); - params.put("password","1234"); - - - View view = Struts.runAction(actionName,params); - - Assert.assertEquals("/jsp/homepage.jsp", view.getJsp()); - Assert.assertEquals("login successful", view.getParameters().get("message")); - } - - @Test - public void testLoginActionFailed() { - String actionName = "login"; - Map params = new HashMap(); - params.put("name","test"); - params.put("password","123456"); //密码和预设的不一致 - - View view = Struts.runAction(actionName,params); - - Assert.assertEquals("/jsp/showLogin.jsp", view.getJsp()); - Assert.assertEquals("login failed,please check your user/pwd", view.getParameters().get("message")); - } -} diff --git a/group11/1178243325/DataStructure/src/main/java/com/coderising/litestruts/View.java b/group11/1178243325/DataStructure/src/main/java/com/coderising/litestruts/View.java deleted file mode 100644 index 0194c681f6..0000000000 --- a/group11/1178243325/DataStructure/src/main/java/com/coderising/litestruts/View.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.coderising.litestruts; - -import java.util.Map; - -public class View { - private String jsp; - private Map parameters; - - public String getJsp() { - return jsp; - } - public View setJsp(String jsp) { - this.jsp = jsp; - return this; - } - public Map getParameters() { - return parameters; - } - public View setParameters(Map parameters) { - this.parameters = parameters; - return this; - } -} diff --git a/group11/1178243325/DataStructure/src/main/java/com/coderising/litestruts/XmlUtil.java b/group11/1178243325/DataStructure/src/main/java/com/coderising/litestruts/XmlUtil.java deleted file mode 100644 index d200452cc8..0000000000 --- a/group11/1178243325/DataStructure/src/main/java/com/coderising/litestruts/XmlUtil.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.coderising.litestruts; - -import java.io.*; -import java.util.*; -import org.dom4j.Attribute; -import org.dom4j.Document; -import org.dom4j.Element; -import org.dom4j.io.SAXReader; -import org.dom4j.io.XMLWriter; -public class XmlUtil { - - public static String parseXML(String filePath, String actionName) { - try { - File file = new File(filePath); - SAXReader reader = new SAXReader(); - Document doc = reader.read(file); - Element root = doc.getRootElement(); - for (Iterator iter = root.elementIterator("action"); iter.hasNext();) { - Element element = (Element)iter.next(); - Attribute nameAttr = element.attribute("name"); - if (nameAttr.getValue().equals(actionName)) { - Attribute classAttr = element.attribute("class"); - return classAttr.getValue(); - } - } - } catch (Exception e) { - e.printStackTrace(); - System.out.println("parse error"); - } - return null; - } - - public static String getJspUrl(String filePath, String actionName, String resultName) { - try { - File file = new File(filePath); - SAXReader reader = new SAXReader(); - Document doc = reader.read(file); - Element root = doc.getRootElement(); - for (Iterator iter = root.elementIterator("action"); iter.hasNext();) { - Element element = (Element)iter.next(); - Attribute nameAttr = element.attribute("name"); - if (nameAttr.getValue().equals(actionName)) { - for (Iterator ite = element.elementIterator("result"); ite.hasNext();) { - Element ele = (Element)ite.next(); - Attribute resultAttr = ele.attribute("name"); - if (resultAttr.getValue().equals(resultName)) { - return ele.getText(); - } - } - } - } - } catch (Exception e) { - e.printStackTrace(); - } - - return null; - } - -} diff --git a/group11/1178243325/DataStructure/src/main/java/com/coderising/litestruts/struts.xml b/group11/1178243325/DataStructure/src/main/java/com/coderising/litestruts/struts.xml deleted file mode 100644 index ae0ce37fd8..0000000000 --- a/group11/1178243325/DataStructure/src/main/java/com/coderising/litestruts/struts.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - /jsp/homepage.jsp - /jsp/showLogin.jsp - - - /jsp/welcome.jsp - /jsp/error.jsp - - diff --git a/group11/1178243325/DataStructure/src/main/java/com/coding/basic/.LinkedList.java.swp b/group11/1178243325/DataStructure/src/main/java/com/coding/basic/.LinkedList.java.swp deleted file mode 100644 index 7ea2e295d458709c233e753f5a1bc442a43cead0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 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 R{)L12RT~^;Qn}7={2RR2tVI9- diff --git a/group11/1178243325/DataStructure/src/main/java/com/coding/basic/ArrayList.java b/group11/1178243325/DataStructure/src/main/java/com/coding/basic/ArrayList.java deleted file mode 100644 index f6cd4c38fc..0000000000 --- a/group11/1178243325/DataStructure/src/main/java/com/coding/basic/ArrayList.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.coding.basic; - -import com.coding.basic.exception.*; -public class ArrayList implements List { - - private int size; - private Object[] elementData; - - public ArrayList () { - size = 0; - elementData = new Object[100]; - } - - public void add(Object o){ - add(size(), o); - } - - public void add(int index, Object o){ - if (size() == elementData.length) - ensureCapacity( size() * 2 + 1); - if (index > size() || index < 0) { //index == size时相当于在尾后插入 - throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); - } - for (int i = size; i > index; i--) { - elementData[i] = elementData[i-1]; - } - elementData[index] = o; - size++; - - } - - private void ensureCapacity(int newCapacity) { - if (newCapacity < size()) - return; - Object[] old = elementData; - elementData = new Object[newCapacity]; - for (int i = 0; i < size(); i++) { - elementData[i] = old[i]; - } - } - - public Object get(int index){ - if (index >= size() || index < 0) { //获取时,index==size()越界 - throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); - } - return elementData[index]; - } - - private String outOfBoundsMsg(int index) { - return "Index:" + index + ", Size:" + size; - } - - public Object remove(int index){ - if (index >= size() || index < 0) { - throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); - } - Object old = elementData[index]; - for (int i = index; i < size(); i++) { - elementData[i] = elementData[i+1]; - } - size--; - return old; - } - - /*获取表内容量*/ - public int size(){ - return size; - } - - public Iterator iterator(){ - return new ArrayListIterator(); - } - - public class ArrayListIterator implements Iterator { - private final int ONLY_CAPACITY = size; - private int index; - public ArrayListIterator() { - index = 0; - } - - @Override - public boolean hasNext() { - if (ONLY_CAPACITY != size) - throw new ConcurrentModificationException("此对象没有进行修改同步"); - return index != size; - } - - @Override - public Object next() { - if (ONLY_CAPACITY != size) - throw new ConcurrentModificationException("此对象没有进行修改同步"); - if (index >= ONLY_CAPACITY) - throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); - return elementData[index++]; - } - } -} diff --git a/group11/1178243325/DataStructure/src/main/java/com/coding/basic/BinaryTreeNode.java b/group11/1178243325/DataStructure/src/main/java/com/coding/basic/BinaryTreeNode.java deleted file mode 100644 index 1cf38aee30..0000000000 --- a/group11/1178243325/DataStructure/src/main/java/com/coding/basic/BinaryTreeNode.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.coding.basic; - -public class BinaryTreeNode { - - private Object data; - private BinaryTreeNode left; - private BinaryTreeNode right; - - public Object getData() { - return data; - } - - public void setData(Object data) { - this.data = data; - } - - public BinaryTreeNode getLeft() { - return left; - } - - public void setLeft(BinaryTreeNode left) { - this.left = left; - } - - public BinaryTreeNode getRight() { - return right; - } - - public void setRight(BinaryTreeNode right) { - this.right = right; - } - -} diff --git a/group11/1178243325/DataStructure/src/main/java/com/coding/basic/Iterator.java b/group11/1178243325/DataStructure/src/main/java/com/coding/basic/Iterator.java deleted file mode 100644 index ff93e30377..0000000000 --- a/group11/1178243325/DataStructure/src/main/java/com/coding/basic/Iterator.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.coding.basic; - -public interface Iterator { - public boolean hasNext(); - public Object next(); -} diff --git a/group11/1178243325/DataStructure/src/main/java/com/coding/basic/LinkedList.java b/group11/1178243325/DataStructure/src/main/java/com/coding/basic/LinkedList.java deleted file mode 100644 index 5717f2226d..0000000000 --- a/group11/1178243325/DataStructure/src/main/java/com/coding/basic/LinkedList.java +++ /dev/null @@ -1,289 +0,0 @@ -package com.coding.basic; - -import com.coding.basic.exception.*; -public class LinkedList implements List { - - private Node head; - private int size; - public LinkedList() { - head = new Node(null, null); - size = 0; - } - - public void add(Object o){ - add(size, o); - } - - public void add(int index , Object o){ - if (index > size || index < 0) { - throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); - } - Node frontNode = getNode(index-1); - Node newNode = new Node(o, frontNode.next); - frontNode.next = newNode; - size++; - - } - - private Node getNode(int index) { - Node node = head; - int i = 0; - while(node.next != null && i <= index) { - node = node.next; - i++; - } - return node; - } - - public Object get(int index){ - if (index >= size || index < 0) { - throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); - } - - Node node = getNode(index); - return node.data; - } - - public Object remove(int index){ - if (index >= size || index < 0) { - throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); - } - Node frontNode = getNode(index-1); - Node oldNode = getNode(index); - frontNode.next = oldNode.next; - size--; - return oldNode.data; - } - - public int size(){ - return size; - } - - public void addFirst(Object o){ - add(0, o); - } - - public void addLast(Object o){ - add(size, o); - } - - public Object removeFirst(){ - return remove(0); - } - - public Object removeLast(){ - return remove(size-1); - } - - public Iterator iterator(){ - return new LinkedListIterator(); - } - - private class LinkedListIterator implements Iterator { - int index; - final int capacity = size; - LinkedListIterator() { - index = 0; - } - @Override - public boolean hasNext() { - if (capacity != size) - throw new ConcurrentModificationException("此对象没有修改同步"); - return index < capacity; - } - - @Override - public Object next() { - if (capacity != size) - throw new ConcurrentModificationException("此对象没有修改同步"); - if (index >= capacity) - throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); - return get(index++); - } - } - - private String outOfBoundsMsg(int index) { - return "index:" + index + ", size:" + size; - } - - private static class Node { - Object data; - Node next; - - Node(Object data, Node next) { - this.data = data; - this.next = next; - } - - void setData(Object data) { - this.data = data; - } - - Object getData() { - return data; - } - - void setNext(Node next) { - this.next = next; - } - - Object getNext() { - return next; - } - } - - - /** - * 把该链表逆置 - * 例如链表为 3->7->10 , 逆置后变为 10->7->3 - */ - public void reverse(){ - Object[] oldData = new Object[size]; - Node temp = head; - int index = 1; - while(temp.next != null) { - temp = temp.next; - oldData[size - index] = temp.data; - index++; - } - - index = 0; - temp = head; - while(temp.next != null) { - temp = temp.next; - temp.data = oldData[index]; - index++; - } - } - - /** - * 删除一个单链表的前半部分 - * 例如:list = 2->5->7->8 , 删除以后的值为 7->8 - * 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10 - */ - - public void removeFirstHalf(){ - int count = size; - if (count % 2 != 0) { - for (int i = 0; i <= count/2; i++) { - removeFirst(); - } - } else { - for (int i = 0; i < count/2; i++) { - removeFirst(); - } - } - } - - /** - * 从第i个元素开始, 删除length 个元素 , 注意i从0开始 - * @param i - * @param length - */ - - public void remove(int i, int length){ - if (i < 0 || length < 0) { - return; - } - if (i == 0) { - for (int k = 0; k < length; k++) - removeFirst(); - } else { - while (length > 0) { - remove(i-1); - length--; - } - } - } - - /** - * 假定当前链表和list均包含已升序排列的整数 - * 从当前链表中取出那些list所指定的元素 - * 例如当前链表 = 11->101->201->301->401->501->601->701 - * listB = 1->3->4->6 - * 返回的结果应该是[101,301,401,601] - * @param list - */ - - public static int[] getElements(LinkedList list){ - - return null; - - } - - - - /** - - * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 - - * 从当前链表中中删除在list中出现的元素 - - - - * @param list - - */ - - - - public void subtract(LinkedList list){ - - - - } - - - - /** - - * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 - - * 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) - - */ - - public void removeDuplicateValues(){ - - - - } - - - - /** - - * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 - - * 试写一高效的算法,删除表中所有值大于min且小于max的元素(若表中存在这样的元素) - - * @param min - - * @param max - - */ - - public void removeRange(int min, int max){ - - - - } - - - - /** - - * 假设当前链表和参数list指定的链表均以元素依值递增有序排列(同一表中的元素值各不相同) - - * 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列 - - * @param list - - */ - - public LinkedList intersection( LinkedList list){ - - return null; - - } -} diff --git a/group11/1178243325/DataStructure/src/main/java/com/coding/basic/List.java b/group11/1178243325/DataStructure/src/main/java/com/coding/basic/List.java deleted file mode 100644 index 396b1f6416..0000000000 --- a/group11/1178243325/DataStructure/src/main/java/com/coding/basic/List.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.coding.basic; - -public interface List { - public void add(Object o); - public void add(int index, Object o); - public Object get(int index); - public Object remove(int index); - public int size(); -} diff --git a/group11/1178243325/DataStructure/src/main/java/com/coding/basic/Queue.java b/group11/1178243325/DataStructure/src/main/java/com/coding/basic/Queue.java deleted file mode 100644 index a5c31f5a09..0000000000 --- a/group11/1178243325/DataStructure/src/main/java/com/coding/basic/Queue.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.coding.basic; -import com.coding.basic.exception.*; -public class Queue { - - private LinkedList elementData; - - public Queue() { - elementData = new LinkedList(); - } - - public void enQueue(Object o){ - elementData.addLast(o); - } - - public Object deQueue(){ - if (isEmpty()) { - throw new EmptyQueueException("队空"); - } - Object result = elementData.removeFirst(); - return result; - } - - public boolean isEmpty(){ - return elementData.size() == 0; - } - - public int size(){ - return elementData.size(); - } -} diff --git a/group11/1178243325/DataStructure/src/main/java/com/coding/basic/Stack.java b/group11/1178243325/DataStructure/src/main/java/com/coding/basic/Stack.java deleted file mode 100644 index e41c662792..0000000000 --- a/group11/1178243325/DataStructure/src/main/java/com/coding/basic/Stack.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.coding.basic; - -import com.coding.basic.exception.*; -public class Stack { - - private ArrayList elementData; - public Stack() { - elementData = new ArrayList(); - } - - public void push(Object o){ - elementData.add(o); - } - - public Object pop(){ - if (isEmpty()) { - throw new EmptyStackException("栈空"); - } - Object result = elementData.get(size()-1); - elementData.remove(size()-1); - return result; - } - - public Object peek(){ - if (isEmpty()) { - throw new EmptyStackException("栈空"); - } - return elementData.get(0); - } - - public boolean isEmpty(){ - return elementData.size() == 0; - } - - public int size(){ - return elementData.size(); - } -} diff --git a/group11/1178243325/DataStructure/src/main/java/com/coding/basic/exception/ConcurrentModificationException.java b/group11/1178243325/DataStructure/src/main/java/com/coding/basic/exception/ConcurrentModificationException.java deleted file mode 100644 index f1c5c79721..0000000000 --- a/group11/1178243325/DataStructure/src/main/java/com/coding/basic/exception/ConcurrentModificationException.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.coding.basic.exception; - -public class ConcurrentModificationException extends RuntimeException { - public ConcurrentModificationException() {} - public ConcurrentModificationException(String msg) { - super(msg); - } -} - diff --git a/group11/1178243325/DataStructure/src/main/java/com/coding/basic/exception/EmptyQueueException.java b/group11/1178243325/DataStructure/src/main/java/com/coding/basic/exception/EmptyQueueException.java deleted file mode 100644 index 2ee7aa4ee7..0000000000 --- a/group11/1178243325/DataStructure/src/main/java/com/coding/basic/exception/EmptyQueueException.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.coding.basic.exception; - -public class EmptyQueueException extends RuntimeException { - public EmptyQueueException() {} - public EmptyQueueException(String msg) { - super(msg); - } -} diff --git a/group11/1178243325/DataStructure/src/main/java/com/coding/basic/exception/EmptyStackException.java b/group11/1178243325/DataStructure/src/main/java/com/coding/basic/exception/EmptyStackException.java deleted file mode 100644 index 2a5ae4055d..0000000000 --- a/group11/1178243325/DataStructure/src/main/java/com/coding/basic/exception/EmptyStackException.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.coding.basic.exception; - -public class EmptyStackException extends RuntimeException { - public EmptyStackException() {} - public EmptyStackException(String msg) { - super(msg); - } -} diff --git a/group11/1178243325/DataStructure/src/main/resources/struts.xml b/group11/1178243325/DataStructure/src/main/resources/struts.xml deleted file mode 100644 index ae0ce37fd8..0000000000 --- a/group11/1178243325/DataStructure/src/main/resources/struts.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - /jsp/homepage.jsp - /jsp/showLogin.jsp - - - /jsp/welcome.jsp - /jsp/error.jsp - - diff --git a/group11/1178243325/DataStructure/struts.xml b/group11/1178243325/DataStructure/struts.xml deleted file mode 100644 index 0582b7d4ea..0000000000 --- a/group11/1178243325/DataStructure/struts.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - /jsp/homepage.jsp - /jsp/showLogin.jsp - - - /jsp/welcome.jsp - /jsp/error.jsp - - diff --git a/group11/1178243325/week01/.readme.md.swp b/group11/1178243325/week01/.readme.md.swp deleted file mode 100644 index 44d97db14f1c5235f5e0a65a0bdaee85c90f52de..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI&OHUI~6ae6h3*CqsUAQx&Y$Tzb&J=7hQA1o93?>@IkQhzIb_%7Tt;5vDjgnZ} zYRk(9k6J*qhDJ(hKm^*t4{+(iU(h>uSeP#S1D>IPMgnnXFlUl8uY2y?bHCe7JH2nY z-F%I+nd=E`#|XL7_O0zp=P5FCn2>J2;`XXW!`|E9<~^ky@HTVf&W2^e(xOs^O6hHwK zKmim$0Te(16hHwKKmim$fqf_-!CUpFYC^^#jQ9Ur-~YcKCFCo_ID`Y@BE$uVlMt&% z2vHy&K-`141aS!BAjFTYXYE4^EExq*00mG01yBG5Pyhu`00sV;fQh@K6=(EZRL@Sa z?1+}kvqDIV4$}TfHW;Qa;;cB#(lLE*R!{fbJ=>wG{_{K^3 zYM~#U%xlSv_ByBaWm(~+HW8vr^E4ZWGC57IM|M_j-3Z75xsJP~$gpo#WkphbO1b#V zD4b<7P$eBomsXRd{)yp>d< Date: Tue, 28 Mar 2017 09:26:42 +0800 Subject: [PATCH 023/203] linkedList --- .../wsc/coding/basic/list/MyLinkedList.java | 298 ++++++++++++++++++ 1 file changed, 298 insertions(+) create mode 100644 group20/592146505/592146505Learning/src/org/wsc/coding/basic/list/MyLinkedList.java diff --git a/group20/592146505/592146505Learning/src/org/wsc/coding/basic/list/MyLinkedList.java b/group20/592146505/592146505Learning/src/org/wsc/coding/basic/list/MyLinkedList.java new file mode 100644 index 0000000000..3d2b1ff83a --- /dev/null +++ b/group20/592146505/592146505Learning/src/org/wsc/coding/basic/list/MyLinkedList.java @@ -0,0 +1,298 @@ +package org.wsc.coding.basic.list; + +public class MyLinkedList implements List { + private int size; + private Node head; + + private static class Node { + E data; + Node next; + + Node(E data) { + super(); + this.data = data; + } + + Node(E data, Node next) { + super(); + this.data = data; + this.next = next; + } + + } + + public boolean add(E e) { + linkLast(e); + return true; + } + + public boolean add(int index, E e) { + checkPositionIndex(index); + if (index == 0) + linkFirst(e); + else if (index == size) + linkLast(e); + else + linkAfter(e, node(index - 1)); + return false; + } + + /** + * 向头部添加元素 + * + * @param e + */ + private void linkFirst(E e) { + Node oldHead = head; + Node newHead = new Node(e); + head = newHead; + // 将原头节点作为新头节点的下一个节点 + head.next = oldHead; + size++; + } + + /** + * 向尾部添加元素 + * + * @param e + */ + void linkLast(E e) { + Node newNode = new Node(e); + if (head == null) { + head = newNode; + } else { + Node node = head; + while (true) { + if (node.next == null) { + node.next = newNode; + break; + } + node = node.next; + } + } + size++; + } + + /** + * 在指定节点之后插入新节点 + * + * @param e + * @param node + */ + void linkAfter(E e, Node node) { + Node oldNext = head; + node.next = new Node(e, oldNext); + size++; + } + + public E get(int index) { + checkElementIndex(index); + return node(index).data; + } + + /** + * 获取指定索引处元素,调用此方法请确保索引范围正确 + * + * @param index + * @return + */ + Node node(int index) { + Node node = head; + for (int i = 0; i < index; i++) { + node = node.next; + } + return node; + } + + public E remove(int index) { + checkElementIndex(index); + Node node = null; + if(index == 0){ + node = head; + head = node.next; + node.next = null; + }else{ + node = unlinkNext(node(index-1)); + } + return node == null?null:node.data; + } + + /** + * 删除此节点的下一个节点 + * @param node + * @return + */ + Node unlinkNext(Node node){ + Node nextNode = node.next; + node.next = nextNode.next; + nextNode.next = null; + size--; + return nextNode; + } + + public int size() { + return size; + } + + public void addFirst(E e) { + linkFirst(e); + } + + public void addLast(E e) { + linkLast(e); + } + + public Object removeFirst() { + return null; + } + + public Object removeLast() { + return null; + } + + public Iterator iterator() { + return null; + } + + /** + * 现有节点索引范围 + * + * @param index + * @return + */ + private boolean isElementIndex(int index) { + return index >= 0 && index < size; + } + + /** + * 可插入索引范围 + * + * @param index + * @return + */ + private boolean isPositionIndex(int index) { + return index >= 0 && index <= size; + } + + private String outOfBoundsMsg(int index) { + return "Index: " + index + ", Size: " + size; + } + + /** + * 现有节点索引范围检查 + * + * @param index + */ + private void checkElementIndex(int index) { + if (!isElementIndex(index)) + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + } + + /** + * 可插入索引范围检查 + * + * @param index + */ + private void checkPositionIndex(int index) { + if (!isPositionIndex(index)) + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + } + + /** + * 把该链表逆置 例如链表为 3->7->10 , 逆置后变为 10->7->3 + */ + public void reverse() { + + } + + /** + * 删除一个单链表的前半部分 例如:list = 2->5->7->8 , 删除以后的值为 7->8 如果list = 2->5->7->8->10 + * ,删除以后的值为7,8,10 + * + */ + public void removeFirstHalf() { + + } + + /** + * 从第i个元素开始, 删除length 个元素 , 注意i从0开始 + * + * @param i + * @param length + */ + public void remove(int i, int length) { + + } + + /** + * 假定当前链表和list均包含已升序排列的整数 从当前链表中取出那些list所指定的元素 例如当前链表 = + * 11->101->201->301->401->501->601->701 listB = 1->3->4->6 + * 返回的结果应该是[101,301,401,601] + * + * @param list + */ + public static int[] getElements(LinkedList list) { + return null; + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 从当前链表中中删除在list中出现的元素 + * + * @param list + */ + + public void subtract(LinkedList list) { + + } + + /** + * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) + */ + public void removeDuplicateValues() { + + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 试写一高效的算法,删除表中所有值大于min且小于max的元素(若表中存在这样的元素) + * + * @param min + * @param max + */ + public void removeRange(int min, int max) { + + } + + /** + * 假设当前链表和参数list指定的链表均以元素依值递增有序排列(同一表中的元素值各不相同) + * 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列 + * + * @param list + */ + public LinkedList intersection(LinkedList list) { + return null; + } + + @Override + public boolean isEmpty() { + // TODO Auto-generated method stub + return false; + } + + @Override + public Object[] toArray() { + // TODO Auto-generated method stub + return null; + } + + @Override + public T[] toArray(T[] a) { + // TODO Auto-generated method stub + return null; + } + + @Override + public E set(int index, E e) { + // TODO Auto-generated method stub + return null; + } +} From c9495316921d30622cc4d4f731dd295b19779b55 Mon Sep 17 00:00:00 2001 From: HaoSong Date: Tue, 28 Mar 2017 18:33:38 +0800 Subject: [PATCH 024/203] 3.28 --- .../week01/data_structure/LinkedList.java | 78 +++++++++++++++++++ .../src/main/week02/practice/ArrayUtil.java | 43 ++++++---- 2 files changed, 107 insertions(+), 14 deletions(-) diff --git a/group24/330657387/src/main/week01/data_structure/LinkedList.java b/group24/330657387/src/main/week01/data_structure/LinkedList.java index b61df9f254..9a5eff1c79 100644 --- a/group24/330657387/src/main/week01/data_structure/LinkedList.java +++ b/group24/330657387/src/main/week01/data_structure/LinkedList.java @@ -147,4 +147,82 @@ public Object next() { public LinkedListIterator iterator() { return new LinkedListIterator(this); } + + + + /** + * 把该链表逆置 + * 例如链表为 3->7->10 , 逆置后变为 10->7->3 + */ + public void reverse(){ + + } + + /** + * 删除一个单链表的前半部分 + * 例如:list = 2->5->7->8 , 删除以后的值为 7->8 + * 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10 + + */ + public void removeFirstHalf(){ + + } + + /** + * 从第i个元素开始, 删除length 个元素 , 注意i从0开始 + * @param i + * @param length + */ + public void remove(int i, int length){ + + } + /** + * 假定当前链表和list均包含已升序排列的整数 + * 从当前链表中取出那些list所指定的元素 + * 例如当前链表 = 11->101->201->301->401->501->601->701 + * listB = 1->3->4->6 + * 返回的结果应该是[101,301,401,601] + * @param list + */ + public static int[] getElements(LinkedList list){ + return null; + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 从当前链表中中删除在list中出现的元素 + + * @param list + */ + + public void subtract(LinkedList list){ + + } + + /** + * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) + */ + public void removeDuplicateValues(){ + + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 试写一高效的算法,删除表中所有值大于min且小于max的元素(若表中存在这样的元素) + * @param min + * @param max + */ + public void removeRange(int min, int max){ + + } + + /** + * 假设当前链表和参数list指定的链表均以元素依值递增有序排列(同一表中的元素值各不相同) + * 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列 + * @param list + */ + public LinkedList intersection( LinkedList list){ + return null; + } } diff --git a/group24/330657387/src/main/week02/practice/ArrayUtil.java b/group24/330657387/src/main/week02/practice/ArrayUtil.java index d174fdbe27..ed0dd51a60 100644 --- a/group24/330657387/src/main/week02/practice/ArrayUtil.java +++ b/group24/330657387/src/main/week02/practice/ArrayUtil.java @@ -1,6 +1,7 @@ package main.week02.practice; import java.util.ArrayList; +import java.util.Arrays; import java.util.Iterator; import com.sun.xml.internal.ws.org.objectweb.asm.Label; @@ -19,7 +20,6 @@ public void reverseArray(int[] origin) { return; } int i = 0, j = origin.length - 1; - int temp; while (j > i) { origin[i] = origin[i] ^ origin[j]; origin[j] = origin[i] ^ origin[j]; @@ -137,21 +137,36 @@ public int[] fibonacci(int max) { if (max <= 1) { return new int[0]; } - ArrayList list = new ArrayList(); - list.add(1); - list.add(1); - int index = 1; - while (list.get(index) + list.get(index - 1) < max) { - list.add(list.get(index) + list.get(index - 1)); - index++; + if(max == 2){ + return new int[]{1,1}; } - Iterator iter = list.iterator(); - int[] res = new int[list.size()]; - int i = 0; - while (iter.hasNext()) { - res[i++] = iter.next(); + int[] arr = new int[max]; + arr[0] = arr[1] = 1; + int count = 2; + for(; count < max; count++){ + arr[count] = arr[count-1] + arr[count-2]; + if(arr[count] >= max){ + break; + } } - return res; + + return Arrays.copyOf(arr, count); + +// ArrayList list = new ArrayList(); +// list.add(1); +// list.add(1); +// int index = 1; +// while (list.get(index) + list.get(index - 1) < max) { +// list.add(list.get(index) + list.get(index - 1)); +// index++; +// } +// Iterator iter = list.iterator(); +// int[] res = new int[list.size()]; +// int i = 0; +// while (iter.hasNext()) { +// res[i++] = iter.next(); +// } +// return res; } /** From 7559af508bd785094e4df1e9ba6698e68eacfba0 Mon Sep 17 00:00:00 2001 From: sargeles <330657387@qq.com> Date: Wed, 29 Mar 2017 00:30:15 +0800 Subject: [PATCH 025/203] 3.29 --- .../week01/data_structure/LinkedList.java | 99 +++++++++++-------- .../week01/data_structure/LinkedListTest.java | 17 ++++ .../week02/litestruts/StrutsTest.java | 5 +- 3 files changed, 79 insertions(+), 42 deletions(-) rename group24/330657387/src/{main => test}/week02/litestruts/StrutsTest.java (91%) diff --git a/group24/330657387/src/main/week01/data_structure/LinkedList.java b/group24/330657387/src/main/week01/data_structure/LinkedList.java index 9a5eff1c79..1dd55fdec3 100644 --- a/group24/330657387/src/main/week01/data_structure/LinkedList.java +++ b/group24/330657387/src/main/week01/data_structure/LinkedList.java @@ -62,7 +62,7 @@ public Object remove(int index) { rangeCheck(index); if (index == 0) { return removeFirst(); - }else if(index == size){ + } else if (index == size) { return removeLast(); } Node pre = getNode(index - 1); @@ -147,82 +147,99 @@ public Object next() { public LinkedListIterator iterator() { return new LinkedListIterator(this); } - - /** - * 把该链表逆置 - * 例如链表为 3->7->10 , 逆置后变为 10->7->3 + * 把该链表逆置 例如链表为 3->7->10 , 逆置后变为 10->7->3 */ - public void reverse(){ - + public void reverse() { + if(size <= 1){ + return; + } + Node A = head,B = head.next; + head.next = null; + Node temp; + while(null != B.next){ + temp = B.next; + B.next = A; + B=temp; + } + head = B; } - - /** - * 删除一个单链表的前半部分 - * 例如:list = 2->5->7->8 , 删除以后的值为 7->8 - * 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10 + /** + * 删除一个单链表的前半部分 例如:list = 2->5->7->8 , 删除以后的值为 7->8 如果list = 2->5->7->8->10 + * ,删除以后的值为7,8,10 */ - public void removeFirstHalf(){ - + public void removeFirstHalf() { + if(size <= 1){ + return; + } + size = size%2 == 0?size/2:size/2+1; + head = getNode(size-1); } - + /** * 从第i个元素开始, 删除length 个元素 , 注意i从0开始 + * * @param i * @param length */ - public void remove(int i, int length){ - + public void remove(int i, int length) { + rangeCheck(i); + rangeCheck(i+length-1); + if(i==0){ + head = getNode(length); + size -= length; + } + Node pre = getNode(i-1); + pre.next = getNode(i+length); } + /** - * 假定当前链表和list均包含已升序排列的整数 - * 从当前链表中取出那些list所指定的元素 - * 例如当前链表 = 11->101->201->301->401->501->601->701 - * listB = 1->3->4->6 - * 返回的结果应该是[101,301,401,601] + * 假定当前链表和list均包含已升序排列的整数 从当前链表中取出那些list所指定的元素 例如当前链表 = + * 11->101->201->301->401->501->601->701 listB = 1->3->4->6 + * 返回的结果应该是[101,301,401,601] + * * @param list */ - public static int[] getElements(LinkedList list){ + public static int[] getElements(LinkedList list) { return null; } - - /** - * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 - * 从当前链表中中删除在list中出现的元素 + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 从当前链表中中删除在list中出现的元素 + * * @param list */ - - public void subtract(LinkedList list){ + + public void subtract(LinkedList list) { } - + /** - * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 - * 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) + * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) */ - public void removeDuplicateValues(){ - + public void removeDuplicateValues() { + } - + /** - * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 - * 试写一高效的算法,删除表中所有值大于min且小于max的元素(若表中存在这样的元素) + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 试写一高效的算法,删除表中所有值大于min且小于max的元素(若表中存在这样的元素) + * * @param min * @param max */ - public void removeRange(int min, int max){ - + public void removeRange(int min, int max) { + } - + /** * 假设当前链表和参数list指定的链表均以元素依值递增有序排列(同一表中的元素值各不相同) * 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列 + * * @param list */ - public LinkedList intersection( LinkedList list){ + public LinkedList intersection(LinkedList list) { return null; } } diff --git a/group24/330657387/src/test/week01/data_structure/LinkedListTest.java b/group24/330657387/src/test/week01/data_structure/LinkedListTest.java index cf374a6dcb..5285aa08ae 100644 --- a/group24/330657387/src/test/week01/data_structure/LinkedListTest.java +++ b/group24/330657387/src/test/week01/data_structure/LinkedListTest.java @@ -50,5 +50,22 @@ public void testIterator() { assertEquals("B", iter.next()); assertFalse(iter.hasNext()); } + + @Test + public void testReverse(){ + list.add("A"); + list.add("B"); + list.add("C"); + list.add("D"); + list.reverse(); + LinkedListIterator iter = list.iterator(); + StringBuilder sb = new StringBuilder(); + while(iter.hasNext()){ + sb.append(iter.next()); + sb.append("->"); + } + sb.append("null"); + assertEquals("D->C->B->A->null", sb.toString()); + } } diff --git a/group24/330657387/src/main/week02/litestruts/StrutsTest.java b/group24/330657387/src/test/week02/litestruts/StrutsTest.java similarity index 91% rename from group24/330657387/src/main/week02/litestruts/StrutsTest.java rename to group24/330657387/src/test/week02/litestruts/StrutsTest.java index 1cc90265f7..f56dad80f6 100644 --- a/group24/330657387/src/main/week02/litestruts/StrutsTest.java +++ b/group24/330657387/src/test/week02/litestruts/StrutsTest.java @@ -1,8 +1,11 @@ -package main.week02.litestruts; +package test.week02.litestruts; import java.util.HashMap; import java.util.Map; +import main.week02.litestruts.Struts; +import main.week02.litestruts.View; + import org.junit.Assert; import org.junit.Test; From 494577ecce248b518572bfdf328c48e1d0641a8c Mon Sep 17 00:00:00 2001 From: xmt <542194147@qq.com> Date: Wed, 29 Mar 2017 10:30:51 +0800 Subject: [PATCH 026/203] fileDownloader MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 多线程下载修改 --- .../coderising/download/FileDownloader.java | 1 - .../download/impl/ConnectionImpl.java | 31 ++++++++++++++----- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/group11/542194147/myDataStructure/src/com/coderising/download/FileDownloader.java b/group11/542194147/myDataStructure/src/com/coderising/download/FileDownloader.java index 75ade93046..96989a4559 100644 --- a/group11/542194147/myDataStructure/src/com/coderising/download/FileDownloader.java +++ b/group11/542194147/myDataStructure/src/com/coderising/download/FileDownloader.java @@ -44,7 +44,6 @@ public void execute(){ int length = conn.getContentLength(); int downloadBlock=length/3; int appendBlock=length%3; - RandomAccessFile rdaFile=new RandomAccessFile("downloadFile","wr"); for(int i=0;i totalLen){ + byte[] data = baos.toByteArray(); + return Arrays.copyOf(data, totalLen); + } + + return baos.toByteArray(); + } @Override From 19d33c7e787baaee70997b9ba672eeedc0fbc1df Mon Sep 17 00:00:00 2001 From: Alvin Date: Wed, 29 Mar 2017 00:22:16 -0800 Subject: [PATCH 027/203] Homework 3/26 --- .../src/com/basic/linklist/LRUPageFrame.java | 56 +++++++++++++ .../com/basic/linklist/LRUPageFrameTest.java | 31 ++++++++ .../jvm/loader/ClassFileLoader.java | 24 ++++++ .../jvm/test/ClassFileloaderTest.java | 78 +++++++++++++++++++ .../com/coderising/jvm/test/EmployeeV1.java | 30 +++++++ 5 files changed, 219 insertions(+) create mode 100644 group20/404130810/src/com/basic/linklist/LRUPageFrame.java create mode 100644 group20/404130810/src/com/basic/linklist/LRUPageFrameTest.java create mode 100644 group20/404130810/src/com/coderising/jvm/loader/ClassFileLoader.java create mode 100644 group20/404130810/src/com/coderising/jvm/test/ClassFileloaderTest.java create mode 100644 group20/404130810/src/com/coderising/jvm/test/EmployeeV1.java diff --git a/group20/404130810/src/com/basic/linklist/LRUPageFrame.java b/group20/404130810/src/com/basic/linklist/LRUPageFrame.java new file mode 100644 index 0000000000..bdeced0a78 --- /dev/null +++ b/group20/404130810/src/com/basic/linklist/LRUPageFrame.java @@ -0,0 +1,56 @@ +package com.basic.linklist; + +/** + * ��˫������ʵ��LRU�㷨 + * + * @author liuxin + * + */ +public class LRUPageFrame { + + private static class Node { + + Node prev; + Node next; + int pageNum; + + Node() { + } + } + + private int capacity; + + private Node first;// ����ͷ + private Node last;// ����β + + public LRUPageFrame(int capacity) { + + this.capacity = capacity; + + } + + /** + * ��ȡ�����ж��� + * + * @param key + * @return + */ + public void access(int pageNum) { + + } + + public String toString() { + StringBuilder buffer = new StringBuilder(); + Node node = first; + while (node != null) { + buffer.append(node.pageNum); + + node = node.next; + if (node != null) { + buffer.append(","); + } + } + return buffer.toString(); + } + +} \ No newline at end of file diff --git a/group20/404130810/src/com/basic/linklist/LRUPageFrameTest.java b/group20/404130810/src/com/basic/linklist/LRUPageFrameTest.java new file mode 100644 index 0000000000..4220724649 --- /dev/null +++ b/group20/404130810/src/com/basic/linklist/LRUPageFrameTest.java @@ -0,0 +1,31 @@ +package com.basic.linklist; + +import org.junit.Assert; + +import org.junit.Test; + + +public class LRUPageFrameTest { + + @Test + public void testAccess() { + LRUPageFrame frame = new LRUPageFrame(3); + frame.access(7); + frame.access(0); + frame.access(1); + Assert.assertEquals("1,0,7", frame.toString()); + frame.access(2); + Assert.assertEquals("2,1,0", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(3); + Assert.assertEquals("3,0,2", frame.toString()); + frame.access(0); + Assert.assertEquals("0,3,2", frame.toString()); + frame.access(4); + Assert.assertEquals("4,0,3", frame.toString()); + } + +} diff --git a/group20/404130810/src/com/coderising/jvm/loader/ClassFileLoader.java b/group20/404130810/src/com/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..ba139c9662 --- /dev/null +++ b/group20/404130810/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,24 @@ +package com.coderising.jvm.loader; + +import java.util.ArrayList; +import java.util.List; + +public class ClassFileLoader { + + private List clzPaths = new ArrayList(); + + public byte[] readBinaryCode(String className) { + + return null; + + } + + public void addClassPath(String path) { + + } + + public String getClassPath() { + return null; + } + +} \ No newline at end of file diff --git a/group20/404130810/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group20/404130810/src/com/coderising/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..038b7edf0c --- /dev/null +++ b/group20/404130810/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,78 @@ +package com.coderising.jvm.test; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.coderising.jvm.loader.ClassFileLoader; + +public class ClassFileloaderTest { + + static String path1 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\mini-jvm\\bin"; + static String path2 = "C:\temp"; + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testClassPath() { + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + loader.addClassPath(path2); + + String clzPath = loader.getClassPath(); + + Assert.assertEquals(path1 + ";" + path2, clzPath); + + } + + @Test + public void testClassFileLength() { + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + + String className = "com.coderising.jvm.test.EmployeeV1"; + + byte[] byteCodes = loader.readBinaryCode(className); + + // ע�⣺����ֽ������ܺ����JVM�汾�й�ϵ�� ����Կ�������õ��ൽ���ж�� + Assert.assertEquals(1056, byteCodes.length); + + } + + @Test + public void testMagicNumber() { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "com.coderising.jvm.test.EmployeeV1"; + byte[] byteCodes = loader.readBinaryCode(className); + byte[] codes = new byte[] { byteCodes[0], byteCodes[1], byteCodes[2], byteCodes[3] }; + + String acctualValue = this.byteToHexString(codes); + + Assert.assertEquals("cafebabe", acctualValue); + } + + private String byteToHexString(byte[] codes) { + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < codes.length; i++) { + byte b = codes[i]; + int value = b & 0xFF; + String strHex = Integer.toHexString(value); + if (strHex.length() < 2) { + strHex = "0" + strHex; + } + buffer.append(strHex); + } + return buffer.toString(); + } + +} \ No newline at end of file diff --git a/group20/404130810/src/com/coderising/jvm/test/EmployeeV1.java b/group20/404130810/src/com/coderising/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..d36b122f60 --- /dev/null +++ b/group20/404130810/src/com/coderising/jvm/test/EmployeeV1.java @@ -0,0 +1,30 @@ +package com.coderising.jvm.test; + +public class EmployeeV1 { + + private String name; + private int age; + + public EmployeeV1(String name, int age) { + this.name = name; + this.age = age; + } + + public void setName(String name) { + this.name = name; + } + + public void setAge(int age) { + this.age = age; + } + + public void sayHello() { + System.out.println("Hello , this is class Employee "); + } + + public static void main(String[] args) { + EmployeeV1 p = new EmployeeV1("Andy", 29); + p.sayHello(); + + } +} \ No newline at end of file From 5d823c7ffd9bb2abeac43e700bb82a567ad7615a Mon Sep 17 00:00:00 2001 From: HaoSong Date: Wed, 29 Mar 2017 17:11:44 +0800 Subject: [PATCH 028/203] .29 --- .../week01/data_structure/LinkedList.java | 130 ++++++++++++--- .../week01/data_structure/LinkedListTest.java | 156 ++++++++++++++++-- 2 files changed, 252 insertions(+), 34 deletions(-) diff --git a/group24/330657387/src/main/week01/data_structure/LinkedList.java b/group24/330657387/src/main/week01/data_structure/LinkedList.java index 1dd55fdec3..e4d3f489ec 100644 --- a/group24/330657387/src/main/week01/data_structure/LinkedList.java +++ b/group24/330657387/src/main/week01/data_structure/LinkedList.java @@ -49,7 +49,7 @@ public Object get(int index) { return dest.data; } - public Node getNode(int index) { + private Node getNode(int index) { rangeCheck(index); Node dest = head; for (int i = 0; i < index; i++) { @@ -132,6 +132,10 @@ private LinkedListIterator(LinkedList list) { this.list = list; } + public void reset() { + position = 0; + } + @Override public boolean hasNext() { return position + 1 <= list.size; @@ -152,18 +156,19 @@ public LinkedListIterator iterator() { * 把该链表逆置 例如链表为 3->7->10 , 逆置后变为 10->7->3 */ public void reverse() { - if(size <= 1){ + if (size <= 1) { return; } - Node A = head,B = head.next; + Node a = head, b = head.next; head.next = null; Node temp; - while(null != B.next){ - temp = B.next; - B.next = A; - B=temp; + while (null != b) { + temp = b.next; + b.next = a; + a = b; + b = temp; } - head = B; + head = a; } /** @@ -171,11 +176,11 @@ public void reverse() { * ,删除以后的值为7,8,10 */ public void removeFirstHalf() { - if(size <= 1){ + if (size <= 1) { return; } - size = size%2 == 0?size/2:size/2+1; - head = getNode(size-1); + size = size % 2 == 0 ? size / 2 : size / 2 + 1; + head = getNode(size - 1); } /** @@ -186,13 +191,14 @@ public void removeFirstHalf() { */ public void remove(int i, int length) { rangeCheck(i); - rangeCheck(i+length-1); - if(i==0){ + rangeCheck(i + length - 1); + if (i == 0) { head = getNode(length); size -= length; + } else { + Node pre = getNode(i - 1); + pre.next = getNode(i + length - 1).next; } - Node pre = getNode(i-1); - pre.next = getNode(i+length); } /** @@ -201,26 +207,62 @@ public void remove(int i, int length) { * 返回的结果应该是[101,301,401,601] * * @param list + * @throws Exception */ - public static int[] getElements(LinkedList list) { - return null; + public int[] getElements(LinkedList list) throws Exception { + if (list == null) { + throw new Exception("传入链表为空?"); + } + int[] res = new int[list.size]; + for (int i = 0; i < list.size; i++) { + res[i] = Integer.parseInt(get( + Integer.parseInt(list.get(i).toString()) - 1).toString()); + } + return res; } /** * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 从当前链表中中删除在list中出现的元素 * * @param list + * @throws Exception */ - public void subtract(LinkedList list) { - + public void subtract(LinkedList list) throws Exception { + if (list == null) { + throw new Exception("传入链表为空?"); + } + LinkedListIterator beSub = this.iterator(), sub = list.iterator(); + while (sub.hasNext()) { + Object a = sub.next(); + while (beSub.hasNext()) { + Object b = beSub.next(); + if (a.equals(b)) { + this.remove(beSub.position - 1); + } + } + beSub.reset(); + } } /** * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) */ public void removeDuplicateValues() { - + LinkedListIterator iter = this.iterator(); + if (size <= 1) { + return; + } + Object a = iter.next(); + while (iter.hasNext()) { + Object b = iter.next(); + if (b.equals(a)) { + remove(iter.position - 1); + continue; + } else { + a = b; + } + } } /** @@ -228,9 +270,42 @@ public void removeDuplicateValues() { * * @param min * @param max + * @throws Exception */ - public void removeRange(int min, int max) { - + public void removeRange(int min, int max) throws Exception { + if(min > max){ + throw new Exception("输入有问题!"); + } + if(max < Integer.parseInt(get(0).toString())){ + throw new Exception("全部太小!"); + } + if(min > Integer.parseInt(get(size-1).toString())){ + throw new Exception("全部太大!"); + } + int firstRemove = -1,lastRemove = -1; + LinkedListIterator iter = this.iterator(); + boolean hasmin = false; + while(iter.hasNext()){ + int n = Integer.parseInt(iter.next().toString()); + if(n>min && !hasmin){ + firstRemove = iter.position - 1; + hasmin = true; + } + if(n"); + } + sb.append("null"); + return sb.toString(); + } } diff --git a/group24/330657387/src/test/week01/data_structure/LinkedListTest.java b/group24/330657387/src/test/week01/data_structure/LinkedListTest.java index 5285aa08ae..4458d9ab6a 100644 --- a/group24/330657387/src/test/week01/data_structure/LinkedListTest.java +++ b/group24/330657387/src/test/week01/data_structure/LinkedListTest.java @@ -1,6 +1,9 @@ package test.week01.data_structure; import static org.junit.Assert.*; + +import java.util.Arrays; + import main.week01.data_structure.LinkedList; import main.week01.data_structure.LinkedList.LinkedListIterator; @@ -8,12 +11,26 @@ import org.junit.Test; public class LinkedListTest { - + private LinkedList list; + private LinkedList[] lists = new LinkedList[3]; @Before public void setUp() throws Exception { list = new LinkedList(); + + lists[0] = new LinkedList(); + lists[1] = new LinkedList(); + lists[2] = new LinkedList(); + + lists[1].add("A"); + + lists[2].add("A"); + lists[2].add("B"); + lists[2].add("C"); + lists[2].add("D"); + lists[2].add("E"); + } @Test @@ -32,7 +49,7 @@ public void testRemove() { list.add("D"); list.add(0, "E"); assertEquals("E", list.remove(0)); - assertEquals("D", list.remove(list.size()-1)); + assertEquals("D", list.remove(list.size() - 1)); assertEquals(3, list.size()); } @@ -50,22 +67,137 @@ public void testIterator() { assertEquals("B", iter.next()); assertFalse(iter.hasNext()); } - + @Test - public void testReverse(){ - list.add("A"); - list.add("B"); - list.add("C"); - list.add("D"); - list.reverse(); - LinkedListIterator iter = list.iterator(); + public void testReverse() { + LinkedList l = lists[2]; + l.reverse(); + LinkedListIterator iter = l.iterator(); + StringBuilder sb = new StringBuilder(); + while (iter.hasNext()) { + sb.append(iter.next()); + } + // assertEquals("", sb.toString()); + // assertEquals("A", sb.toString()); + assertEquals("EDCBA", sb.toString()); + + } + + @Test + public void testRemoveFirstHalf() { + LinkedList l = lists[0]; + l.removeFirstHalf(); + + LinkedListIterator iter = l.iterator(); StringBuilder sb = new StringBuilder(); - while(iter.hasNext()){ + while (iter.hasNext()) { sb.append(iter.next()); sb.append("->"); } sb.append("null"); - assertEquals("D->C->B->A->null", sb.toString()); + + assertEquals("null", sb.toString()); + //assertEquals("A->null", sb.toString()); + //assertEquals("C->D->E->null", sb.toString()); + } + + @Test + public void testRemoveByIndex() { + try{ + LinkedList l = lists[2]; + l.remove(0, 1); + System.out.println(l.ToString()); + }catch(Exception e){ + assertEquals(IndexOutOfBoundsException.class, e.getClass()); + } + } + + @Test + public void testGetElements() { + list.add(11); + list.add(22); + list.add(33); + list.add(44); + list.add(55); + list.add(66); + list.add(77); + list.add(88); + list.add(99); + + LinkedList l = new LinkedList(); + l.add(1); + l.add(3); + l.add(4); + l.add(6); + try{ + int[] res = list.getElements(l); + System.out.println(Arrays.toString(res)); + }catch(Exception e){ + assertEquals(e.getMessage(), "传入链表为空?"); + } + } + + @Test + public void testSubtract() { + list.add(11); + list.add(22); + list.add(33); + list.add(44); + list.add(55); + list.add(66); + list.add(77); + list.add(88); + list.add(99); + + LinkedList l = new LinkedList(); + l.add(11); + l.add(33); + l.add(44); + l.add(66); + try{ + list.subtract(l); + System.out.println(list.ToString()); + }catch(Exception e){ + assertEquals(e.getMessage(), "传入链表为空?"); + } } + @Test + public void testRemoveDuplicateValues() { + list.add(11); + list.add(11); + list.add(22); + list.add(33); + list.add(33); + + list.removeDuplicateValues(); + + System.out.println(list.ToString()); + } + + @Test + public void testRemoveRange() throws Exception { + list.add(11); + list.add(22); + list.add(33); + list.add(44); + list.add(55); + list.add(66); + list.add(77); + list.add(88); + list.add(99); + System.out.println(list.ToString()); + + try{ + list.removeRange(50, 80); + System.out.println(list.ToString()); + }catch(Exception e){ + assertEquals(e.getMessage(), "输入有问题!"); + } + } + + @Test + public void testIntersection() { + + } } From e656c7c00cc838b53f21673df5c4ae8a19560e9d Mon Sep 17 00:00:00 2001 From: sargeles <330657387@qq.com> Date: Wed, 29 Mar 2017 22:52:42 +0800 Subject: [PATCH 029/203] 3.29 --- .../main/week01/data_structure/ArrayList.java | 5 +- .../week01/data_structure/ArrayListTest.java | 3 +- .../data_structure/BinaryTreeNodeTest.java | 3 +- .../week01/data_structure/LinkedList.java | 39 +++++++++- .../week01/data_structure/LinkedListTest.java | 19 ++++- .../data_structure/{ => api}/Iterator.java | 2 +- .../week01/data_structure/{ => api}/List.java | 2 +- .../week02/litestruts/StrutsTest.java | 5 +- .../week02/practice/ArrayUtilTest.java | 8 +- .../main/week03/download/DownloadThread.java | 20 +++++ .../main/week03/download/FileDownloader.java | 73 +++++++++++++++++++ .../week03/download/FileDownloaderTest.java | 61 ++++++++++++++++ .../main/week03/download/api/Connection.java | 23 ++++++ .../download/api/ConnectionException.java | 5 ++ .../download/api/ConnectionManager.java | 10 +++ .../week03/download/api/DownloadListener.java | 5 ++ .../week03/download/impl/ConnectionImpl.java | 27 +++++++ .../download/impl/ConnectionManagerImpl.java | 17 +++++ 18 files changed, 306 insertions(+), 21 deletions(-) rename group24/330657387/src/{test => main}/week01/data_structure/ArrayListTest.java (94%) rename group24/330657387/src/{test => main}/week01/data_structure/BinaryTreeNodeTest.java (83%) rename group24/330657387/src/{test => main}/week01/data_structure/LinkedListTest.java (91%) rename group24/330657387/src/main/week01/data_structure/{ => api}/Iterator.java (67%) rename group24/330657387/src/main/week01/data_structure/{ => api}/List.java (81%) rename group24/330657387/src/{test => main}/week02/litestruts/StrutsTest.java (91%) rename group24/330657387/src/{test => main}/week02/practice/ArrayUtilTest.java (94%) create mode 100644 group24/330657387/src/main/week03/download/DownloadThread.java create mode 100644 group24/330657387/src/main/week03/download/FileDownloader.java create mode 100644 group24/330657387/src/main/week03/download/FileDownloaderTest.java create mode 100644 group24/330657387/src/main/week03/download/api/Connection.java create mode 100644 group24/330657387/src/main/week03/download/api/ConnectionException.java create mode 100644 group24/330657387/src/main/week03/download/api/ConnectionManager.java create mode 100644 group24/330657387/src/main/week03/download/api/DownloadListener.java create mode 100644 group24/330657387/src/main/week03/download/impl/ConnectionImpl.java create mode 100644 group24/330657387/src/main/week03/download/impl/ConnectionManagerImpl.java diff --git a/group24/330657387/src/main/week01/data_structure/ArrayList.java b/group24/330657387/src/main/week01/data_structure/ArrayList.java index 9a2f4d2c8b..6ffbf377ef 100644 --- a/group24/330657387/src/main/week01/data_structure/ArrayList.java +++ b/group24/330657387/src/main/week01/data_structure/ArrayList.java @@ -2,6 +2,9 @@ import java.util.Arrays; +import main.week01.data_structure.api.Iterator; +import main.week01.data_structure.api.List; + public class ArrayList implements List { private int size = 0; @@ -48,7 +51,7 @@ public Object remove(int index) { Object dest = elementData[index]; System.arraycopy(elementData, index + 1, elementData, index, size - index - 1); - elementData[size---1]=null;//��ֹ�ڴ�й© + elementData[size---1]=null;//��ֹ�ڴ�й© return dest; } diff --git a/group24/330657387/src/test/week01/data_structure/ArrayListTest.java b/group24/330657387/src/main/week01/data_structure/ArrayListTest.java similarity index 94% rename from group24/330657387/src/test/week01/data_structure/ArrayListTest.java rename to group24/330657387/src/main/week01/data_structure/ArrayListTest.java index d9d63339b2..d54bc0b73e 100644 --- a/group24/330657387/src/test/week01/data_structure/ArrayListTest.java +++ b/group24/330657387/src/main/week01/data_structure/ArrayListTest.java @@ -1,7 +1,6 @@ -package test.week01.data_structure; +package main.week01.data_structure; import static org.junit.Assert.*; -import main.week01.data_structure.ArrayList; import main.week01.data_structure.ArrayList.ArrayListIterator; import org.junit.Before; diff --git a/group24/330657387/src/test/week01/data_structure/BinaryTreeNodeTest.java b/group24/330657387/src/main/week01/data_structure/BinaryTreeNodeTest.java similarity index 83% rename from group24/330657387/src/test/week01/data_structure/BinaryTreeNodeTest.java rename to group24/330657387/src/main/week01/data_structure/BinaryTreeNodeTest.java index 515da2e7d4..68dcd18d87 100644 --- a/group24/330657387/src/test/week01/data_structure/BinaryTreeNodeTest.java +++ b/group24/330657387/src/main/week01/data_structure/BinaryTreeNodeTest.java @@ -1,7 +1,6 @@ -package test.week01.data_structure; +package main.week01.data_structure; import static org.junit.Assert.*; -import main.week01.data_structure.BinaryTreeNode; import org.junit.Before; import org.junit.Test; diff --git a/group24/330657387/src/main/week01/data_structure/LinkedList.java b/group24/330657387/src/main/week01/data_structure/LinkedList.java index e4d3f489ec..aafe3654ca 100644 --- a/group24/330657387/src/main/week01/data_structure/LinkedList.java +++ b/group24/330657387/src/main/week01/data_structure/LinkedList.java @@ -2,6 +2,9 @@ import java.util.NoSuchElementException; +import main.week01.data_structure.api.Iterator; +import main.week01.data_structure.api.List; + public class LinkedList implements List { private Node head; @@ -315,7 +318,41 @@ public void removeRange(int min, int max) throws Exception { * @param list */ public LinkedList intersection(LinkedList list) { - return null; + if(0 == list.size){ + return this; + } + if(0 == size){ + return list; + } + LinkedList res = new LinkedList(); + Node a = head, b = list.head; + while(null != a && null != b){ + if(a.equals(b)){ + res.add(a.data); + a = a.next; + b = b.next; + continue; + } + if(Integer.parseInt(a.data.toString()) > Integer.parseInt(b.data.toString())){ + res.add(b.data); + b = b.next; + continue; + } + if(Integer.parseInt(a.data.toString()) < Integer.parseInt(b.data.toString())){ + res.add(a.data); + a = a.next; + continue; + } + } + while(null != a){ + res.add(a.data); + a = a.next; + } + while(null != b){ + res.add(b.data); + b = b.next; + } + return res; } public String ToString() { diff --git a/group24/330657387/src/test/week01/data_structure/LinkedListTest.java b/group24/330657387/src/main/week01/data_structure/LinkedListTest.java similarity index 91% rename from group24/330657387/src/test/week01/data_structure/LinkedListTest.java rename to group24/330657387/src/main/week01/data_structure/LinkedListTest.java index 4458d9ab6a..671cc20cd2 100644 --- a/group24/330657387/src/test/week01/data_structure/LinkedListTest.java +++ b/group24/330657387/src/main/week01/data_structure/LinkedListTest.java @@ -1,10 +1,9 @@ -package test.week01.data_structure; +package main.week01.data_structure; import static org.junit.Assert.*; import java.util.Arrays; -import main.week01.data_structure.LinkedList; import main.week01.data_structure.LinkedList.LinkedListIterator; import org.junit.Before; @@ -198,6 +197,22 @@ public void testRemoveRange() throws Exception { @Test public void testIntersection() { + list.add(11); +// list.add(22); +// list.add(33); +// list.add(44); +// list.add(55); +// list.add(66); +// list.add(77); +// list.add(88); +// list.add(99); + LinkedList l = new LinkedList(); + l.add(10); +// l.add(30); +// l.add(40); +// l.add(60); + + System.out.println(list.intersection(l).ToString()); } } diff --git a/group24/330657387/src/main/week01/data_structure/Iterator.java b/group24/330657387/src/main/week01/data_structure/api/Iterator.java similarity index 67% rename from group24/330657387/src/main/week01/data_structure/Iterator.java rename to group24/330657387/src/main/week01/data_structure/api/Iterator.java index 194891e56a..3ef869c5c8 100644 --- a/group24/330657387/src/main/week01/data_structure/Iterator.java +++ b/group24/330657387/src/main/week01/data_structure/api/Iterator.java @@ -1,4 +1,4 @@ -package main.week01.data_structure; +package main.week01.data_structure.api; public interface Iterator { public boolean hasNext(); diff --git a/group24/330657387/src/main/week01/data_structure/List.java b/group24/330657387/src/main/week01/data_structure/api/List.java similarity index 81% rename from group24/330657387/src/main/week01/data_structure/List.java rename to group24/330657387/src/main/week01/data_structure/api/List.java index 6cbc15f8ab..138f7bd018 100644 --- a/group24/330657387/src/main/week01/data_structure/List.java +++ b/group24/330657387/src/main/week01/data_structure/api/List.java @@ -1,4 +1,4 @@ -package main.week01.data_structure; +package main.week01.data_structure.api; public interface List { diff --git a/group24/330657387/src/test/week02/litestruts/StrutsTest.java b/group24/330657387/src/main/week02/litestruts/StrutsTest.java similarity index 91% rename from group24/330657387/src/test/week02/litestruts/StrutsTest.java rename to group24/330657387/src/main/week02/litestruts/StrutsTest.java index f56dad80f6..1cc90265f7 100644 --- a/group24/330657387/src/test/week02/litestruts/StrutsTest.java +++ b/group24/330657387/src/main/week02/litestruts/StrutsTest.java @@ -1,11 +1,8 @@ -package test.week02.litestruts; +package main.week02.litestruts; import java.util.HashMap; import java.util.Map; -import main.week02.litestruts.Struts; -import main.week02.litestruts.View; - import org.junit.Assert; import org.junit.Test; diff --git a/group24/330657387/src/test/week02/practice/ArrayUtilTest.java b/group24/330657387/src/main/week02/practice/ArrayUtilTest.java similarity index 94% rename from group24/330657387/src/test/week02/practice/ArrayUtilTest.java rename to group24/330657387/src/main/week02/practice/ArrayUtilTest.java index 0e29853068..3c7ccbc4e5 100644 --- a/group24/330657387/src/test/week02/practice/ArrayUtilTest.java +++ b/group24/330657387/src/main/week02/practice/ArrayUtilTest.java @@ -1,12 +1,6 @@ -package test.week02.practice; - -import static org.junit.Assert.*; +package main.week02.practice; import java.util.Arrays; -import java.util.HashMap; - -import main.week02.practice.ArrayUtil; - import org.junit.Before; import org.junit.Test; diff --git a/group24/330657387/src/main/week03/download/DownloadThread.java b/group24/330657387/src/main/week03/download/DownloadThread.java new file mode 100644 index 0000000000..a88c38eeb4 --- /dev/null +++ b/group24/330657387/src/main/week03/download/DownloadThread.java @@ -0,0 +1,20 @@ +package main.week03.download; + +import main.week03.download.api.Connection; + +public class DownloadThread extends Thread{ + + Connection conn; + int startPos; + int endPos; + + public DownloadThread( Connection conn, int startPos, int endPos){ + + this.conn = conn; + this.startPos = startPos; + this.endPos = endPos; + } + public void run(){ + + } +} diff --git a/group24/330657387/src/main/week03/download/FileDownloader.java b/group24/330657387/src/main/week03/download/FileDownloader.java new file mode 100644 index 0000000000..a213105b50 --- /dev/null +++ b/group24/330657387/src/main/week03/download/FileDownloader.java @@ -0,0 +1,73 @@ +package main.week03.download; + +import main.week03.download.api.Connection; +import main.week03.download.api.ConnectionException; +import main.week03.download.api.ConnectionManager; +import main.week03.download.api.DownloadListener; + + +public class FileDownloader { + + String url; + + DownloadListener listener; + + ConnectionManager cm; + + + public FileDownloader(String _url) { + this.url = _url; + + } + + public void execute(){ + // 在这里实现你的代码, 注意: 需要用多线程实现下载 + // 这个类依赖于其他几个接口, 你需要写这几个接口的实现代码 + // (1) ConnectionManager , 可以打开一个连接,通过Connection可以读取其中的一段(用startPos, endPos来指定) + // (2) DownloadListener, 由于是多线程下载, 调用这个类的客户端不知道什么时候结束,所以你需要实现当所有 + // 线程都执行完以后, 调用listener的notifiedFinished方法, 这样客户端就能收到通知。 + // 具体的实现思路: + // 1. 需要调用ConnectionManager的open方法打开连接, 然后通过Connection.getContentLength方法获得文件的长度 + // 2. 至少启动3个线程下载, 注意每个线程需要先调用ConnectionManager的open方法 + // 然后调用read方法, read方法中有读取文件的开始位置和结束位置的参数, 返回值是byte[]数组 + // 3. 把byte数组写入到文件中 + // 4. 所有的线程都下载完成以后, 需要调用listener的notifiedFinished方法 + + // 下面的代码是示例代码, 也就是说只有一个线程, 你需要改造成多线程的。 + Connection conn = null; + try { + + conn = cm.open(this.url); + + int length = conn.getContentLength(); + + new DownloadThread(conn,0,length-1).start(); + + } catch (ConnectionException e) { + e.printStackTrace(); + }finally{ + if(conn != null){ + conn.close(); + } + } + + + + + } + + public void setListener(DownloadListener listener) { + this.listener = listener; + } + + + + public void setConnectionManager(ConnectionManager ucm){ + this.cm = ucm; + } + + public DownloadListener getListener(){ + return this.listener; + } + +} diff --git a/group24/330657387/src/main/week03/download/FileDownloaderTest.java b/group24/330657387/src/main/week03/download/FileDownloaderTest.java new file mode 100644 index 0000000000..b308c26527 --- /dev/null +++ b/group24/330657387/src/main/week03/download/FileDownloaderTest.java @@ -0,0 +1,61 @@ +package main.week03.download; + +import main.week03.download.api.ConnectionManager; +import main.week03.download.api.DownloadListener; +import main.week03.download.impl.ConnectionManagerImpl; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + + + +public class FileDownloaderTest { + boolean downloadFinished = false; + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testDownload() { + + String url = "http://localhost:8080/test.jpg"; + + FileDownloader downloader = new FileDownloader(url); + + + ConnectionManager cm = new ConnectionManagerImpl(); + downloader.setConnectionManager(cm); + + downloader.setListener(new DownloadListener() { + @Override + public void notifyFinished() { + downloadFinished = true; + } + + }); + + + downloader.execute(); + + // 等待多线程下载程序执行完毕 + while (!downloadFinished) { + try { + System.out.println("还没有下载完成,休眠五秒"); + //休眠5秒 + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + System.out.println("下载完成!"); + + + + } + +} diff --git a/group24/330657387/src/main/week03/download/api/Connection.java b/group24/330657387/src/main/week03/download/api/Connection.java new file mode 100644 index 0000000000..da0bece84f --- /dev/null +++ b/group24/330657387/src/main/week03/download/api/Connection.java @@ -0,0 +1,23 @@ +package main.week03.download.api; + +import java.io.IOException; + +public interface Connection { + /** + * 给定开始和结束位置, 读取数据, 返回值是字节数组 + * @param startPos 开始位置, 从0开始 + * @param endPos 结束位置 + * @return + */ + public byte[] read(int startPos,int endPos) throws IOException; + /** + * 得到数据内容的长度 + * @return + */ + public int getContentLength(); + + /** + * 关闭连接 + */ + public void close(); +} diff --git a/group24/330657387/src/main/week03/download/api/ConnectionException.java b/group24/330657387/src/main/week03/download/api/ConnectionException.java new file mode 100644 index 0000000000..30d6093a17 --- /dev/null +++ b/group24/330657387/src/main/week03/download/api/ConnectionException.java @@ -0,0 +1,5 @@ +package main.week03.download.api; + +public class ConnectionException extends Exception { + +} diff --git a/group24/330657387/src/main/week03/download/api/ConnectionManager.java b/group24/330657387/src/main/week03/download/api/ConnectionManager.java new file mode 100644 index 0000000000..6df387d42b --- /dev/null +++ b/group24/330657387/src/main/week03/download/api/ConnectionManager.java @@ -0,0 +1,10 @@ +package main.week03.download.api; + +public interface ConnectionManager { + /** + * 给定一个url , 打开一个连接 + * @param url + * @return + */ + public Connection open(String url) throws ConnectionException; +} diff --git a/group24/330657387/src/main/week03/download/api/DownloadListener.java b/group24/330657387/src/main/week03/download/api/DownloadListener.java new file mode 100644 index 0000000000..86cdd29d70 --- /dev/null +++ b/group24/330657387/src/main/week03/download/api/DownloadListener.java @@ -0,0 +1,5 @@ +package main.week03.download.api; + +public interface DownloadListener { + public void notifyFinished(); +} diff --git a/group24/330657387/src/main/week03/download/impl/ConnectionImpl.java b/group24/330657387/src/main/week03/download/impl/ConnectionImpl.java new file mode 100644 index 0000000000..9ffa4f16df --- /dev/null +++ b/group24/330657387/src/main/week03/download/impl/ConnectionImpl.java @@ -0,0 +1,27 @@ +package main.week03.download.impl; + +import java.io.IOException; + +import main.week03.download.api.Connection; + +public class ConnectionImpl implements Connection{ + + @Override + public byte[] read(int startPos, int endPos) throws IOException { + + return null; + } + + @Override + public int getContentLength() { + + return 0; + } + + @Override + public void close() { + + + } + +} diff --git a/group24/330657387/src/main/week03/download/impl/ConnectionManagerImpl.java b/group24/330657387/src/main/week03/download/impl/ConnectionManagerImpl.java new file mode 100644 index 0000000000..240371883b --- /dev/null +++ b/group24/330657387/src/main/week03/download/impl/ConnectionManagerImpl.java @@ -0,0 +1,17 @@ +package main.week03.download.impl; + +import main.week03.download.api.Connection; +import main.week03.download.api.ConnectionException; +import main.week03.download.api.ConnectionManager; + + + +public class ConnectionManagerImpl implements ConnectionManager { + + @Override + public Connection open(String url) throws ConnectionException { + + return null; + } + +} From e8a369ece137c9e74436804aefe6395c5017a9b7 Mon Sep 17 00:00:00 2001 From: Cary Date: Thu, 30 Mar 2017 08:26:04 +0800 Subject: [PATCH 030/203] [#week2_0305] homework: struts && arrayutil --- .../src/week2_0305/array/ArrayUtil.java | 246 ++++++++++++++++++ .../week2_0305/litestruts/Configuration.java | 95 +++++++ .../litestruts/ConfigurationException.java | 18 ++ .../litestruts/ConfigurationTest.java | 51 ++++ .../week2_0305/litestruts/LoginAction.java | 39 +++ .../week2_0305/litestruts/ReflectionUtil.java | 74 ++++++ .../litestruts/ReflectionUtilTest.java | 130 +++++++++ .../src/week2_0305/litestruts/Struts.java | 55 ++++ .../src/week2_0305/litestruts/StrutsTest.java | 43 +++ .../src/week2_0305/litestruts/View.java | 23 ++ 10 files changed, 774 insertions(+) create mode 100644 group01/349209948/src/week2_0305/array/ArrayUtil.java create mode 100644 group01/349209948/src/week2_0305/litestruts/Configuration.java create mode 100644 group01/349209948/src/week2_0305/litestruts/ConfigurationException.java create mode 100644 group01/349209948/src/week2_0305/litestruts/ConfigurationTest.java create mode 100644 group01/349209948/src/week2_0305/litestruts/LoginAction.java create mode 100644 group01/349209948/src/week2_0305/litestruts/ReflectionUtil.java create mode 100644 group01/349209948/src/week2_0305/litestruts/ReflectionUtilTest.java create mode 100644 group01/349209948/src/week2_0305/litestruts/Struts.java create mode 100644 group01/349209948/src/week2_0305/litestruts/StrutsTest.java create mode 100644 group01/349209948/src/week2_0305/litestruts/View.java diff --git a/group01/349209948/src/week2_0305/array/ArrayUtil.java b/group01/349209948/src/week2_0305/array/ArrayUtil.java new file mode 100644 index 0000000000..3158becf66 --- /dev/null +++ b/group01/349209948/src/week2_0305/array/ArrayUtil.java @@ -0,0 +1,246 @@ +package week2_0305.array; + +import java.util.ArrayList; + +public class ArrayUtil { + + /** + * 给定一个整形数组a , 对该数组的值进行置换 + 例如: a = [7, 9 , 30, 3] , 置换后为 [3, 30, 9,7] + 如果 a = [7, 9, 30, 3, 4] , 置换后为 [4,3, 30 , 9,7] + * @param origin + * @return + */ + public void reverseArray(int[] origin){ + if (origin == null) { + throw new IllegalArgumentException(); + } + int temp = 0; + for (int i = 0; i< origin.length/2; i++) { + temp = origin[i]; + origin[i] = origin[origin.length - i]; + origin[origin.length - i] = temp; + } + } + + /** + * 现在有如下的一个数组: int oldArr[]={1,3,4,5,0,0,6,6,0,5,4,7,6,7,0,5} + * 要求将以上数组中值为0的项去掉,将不为0的值存入一个新的数组,生成的新数组为: + * {1,3,4,5,6,6,5,4,7,6,7,5} + * @param oldArray + * @return + */ + + public int[] removeZero(int[] oldArray){ + if (oldArray == null) { + throw new IllegalArgumentException(); + } + int[] newArray = new int[oldArray.length]; + int index = 0; + for (int i =0; i < oldArray.length; i ++){ + if (oldArray[i] == 0) { + continue; + } else { + newArray[index++] = oldArray[i]; + } + } + return copyOf(newArray, index); + } + + /** + * 给定两个已经排序好的整形数组, a1和a2 , 创建一个新的数组a3, 使得a3 包含a1和a2 的所有元素, 并且仍然是有序的 + * 例如 a1 = [3, 5, 7,8] a2 = [4, 5, 6,7] 则 a3 为[3,4,5,6,7,8] , 注意: 已经消除了重复 + * @param array1 + * @param array2 + * @return + */ + + public int[] merge(int[] array1, int[] array2){ + if (array1 == null || array2 == null) { + throw new IllegalArgumentException(); + } + int[] array3 = new int[array1.length + array2.length]; + int index1 = 0; + int index2 = 0; + int actualSize = 0; + for (int i = 0; i < array3.length; i ++) { + //把array2剩余的部分拷入数据 + if (index1 >= array1.length) { + arrayCopy(array2, index2, array3, i, array2.length - index2); + actualSize = i + array2.length - index2; + return copyOf(array3, actualSize); + } + if (index2 >= array2.length) { + arrayCopy(array1, index1, array3, i, array1.length - index1); + actualSize = i + array1.length - index1; + return copyOf(array3, actualSize); + } + if (array1[index1] < array2[index2]) { + array3[i] = array1[index1]; + index1 ++; + } else if (array1[index1] == array2[index2]) { + array3[i] = array1[index1]; + index1 ++; + index2 ++; + } else { + array3[i] = array2[index2]; + index2 ++; + } + } + // array1 he array2 均为 空数组的情况 + return new int[0]; + } + + private void arrayCopy(int[] src, int srcPos, int[] dest, int destPos, int length) { + for (int i = 0; i< length; i++) { + dest[destPos++] = src[srcPos++]; + } + } + + private int[] copyOf(int[] arr, int size) { + int[] dest = new int[size]; + for (int i = 0; i< size; i++) { + dest[i] = arr[i]; + } + return dest; + } + /** + * 把一个已经存满数据的数组 oldArray的容量进行扩展, 扩展后的新数据大小为oldArray.length + size + * 注意,老数组的元素在新数组中需要保持 + * 例如 oldArray = [2,3,6] , size = 3,则返回的新数组为 + * [2,3,6,0,0,0] + * @param oldArray + * @param size + * @return + */ + public int[] grow(int [] oldArray, int size){ + if (oldArray == null || size <0) { + throw new IllegalArgumentException(); + } + int[] newArray = new int[oldArray.length + size]; + for (int i = 0; i < oldArray.length; i++) { + newArray[i] = oldArray[i]; + } + return newArray; + } + + /** + * 斐波那契数列为:1,1,2,3,5,8,13,21...... ,给定一个最大值, 返回小于该值的数列 + * 例如, max = 15 , 则返回的数组应该为 [1,1,2,3,5,8,13] + * max = 1, 则返回空数组 [] + * @param max + * @return + */ + public int[] fibonacci(int max){ + if (max < 0 ) { + throw new IllegalArgumentException(); + } else if (max == 1) { + return new int[0]; + } + ArrayList list = new ArrayList(); + list.add(1); + list.add(1); + int i = 0; + while(true) { + int num = (int)list.get(i) + (int)list.get(i+1); + if (num < max) { + list.add(num); + } else { + break; + } + } + return listToArray(list); + } + + private int[] listToArray(ArrayList list){ + int[] arr = new int[list.size()]; + for (int i = 0;i < list.size(); i++) { + arr[i] = (int)list.get(i); + } + return arr; + } + + /** + * 返回小于给定最大值max的所有素数数组 + * 例如max = 23, 返回的数组为[2,3,5,7,11,13,17,19] + * @param max + * @return + */ + public int[] getPrimes(int max){ + if (max <2) { + throw new IllegalArgumentException(); + } + ArrayList list = new ArrayList(); + for (int i = 2; i < max; i++) { + if (isPrime(i)) { + list.add(i); + } + } + return listToArray(list); + } + + public boolean isPrime(int m) { + for (int i = 1; i < m/2; i++) { + if (m % i == 0) { + return false; + } + } + return true; + } + + + /** + * 所谓“完数”, 是指这个数恰好等于它的因子之和,例如6=1+2+3 + * 给定一个最大值max, 返回一个数组, 数组中是小于max 的所有完数 + * @param max + * @return + */ + public int[] getPerfectNumbers(int max){ + if (max < 0) { + throw new IllegalArgumentException(); + } + ArrayList list = new ArrayList(); + for (int i = 0; i< max; i++) { + if (isPerfectNumber(i)) { + list.add(i); + } + } + return listToArray(list); + } + + public boolean isPerfectNumber(int num) { + int sum = 0; + for (int i = 0; i < num; i++) { + if (num % i == 0) { + sum += i; + } + } + if (sum == num) { + return true; + } else { + return false; + } + } + + /** + * 用seperator 把数组 array给连接起来 + * 例如array= [3,8,9], seperator = "-" + * 则返回值为"3-8-9" + * @param array + * @param s + * @return + */ + public String join(int[] array, String seperator){ + if (array == null) { + throw new IllegalArgumentException(); + } + + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < array.length; i++) { + builder.append(array[i]).append(seperator); + } + return builder.substring(0, builder.length() - seperator.length()); + } + + +} diff --git a/group01/349209948/src/week2_0305/litestruts/Configuration.java b/group01/349209948/src/week2_0305/litestruts/Configuration.java new file mode 100644 index 0000000000..a10ac1cef9 --- /dev/null +++ b/group01/349209948/src/week2_0305/litestruts/Configuration.java @@ -0,0 +1,95 @@ +package week2_0305.litestruts; + +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import org.jdom2.Document; +import org.jdom2.Element; +import org.jdom2.JDOMException; +import org.jdom2.input.SAXBuilder; +import week2_0305.litestruts.ConfigurationException;; + +public class Configuration { + Map actions = new HashMap<>(); + + public Configuration(String fileName) { + + String packageName = this.getClass().getPackage().getName(); + + packageName = packageName.replace('.', '/'); + + InputStream is = this.getClass().getResourceAsStream("/" + packageName + "/" + fileName); + + parseXML(is); + + try { + is.close(); + } catch (IOException e) { + throw new ConfigurationException(e); + } + } + + private void parseXML(InputStream is) { + SAXBuilder builder = new SAXBuilder(); + try { + Document doc = builder.build(is); + Element root = doc.getRootElement(); + for (Element actionElement : root.getChildren("action")) { + String actionName = actionElement.getAttributeValue("name"); + String clzName = actionElement.getAttributeValue("class"); + ActionConfig ac = new ActionConfig(actionName, clzName); + for (Element resultElement : actionElement.getChildren("result")) { + String resultName = resultElement.getAttributeValue("name"); + String viewName = resultElement.getText().trim(); + + ac.addViewResult(resultName, viewName); + } + this.actions.put(actionName, ac); + } + } catch (IOException e) { + throw new ConfigurationException(e); + } catch (JDOMException e) { + throw new ConfigurationException(e); + } + } + + public String getClassName(String action) { + ActionConfig ac = this.actions.get(action); + if (ac == null) { + return null; + } + return ac.getClassName(); + } + + public String getResultView(String actionName, String resultName) { + ActionConfig ac = this.actions.get(actionName); + if (ac == null) { + return null; + } + return ac.getViewName(resultName); + } + + private static class ActionConfig { + String name; + String clzName; + Map viewResult = new HashMap<>(); + + public ActionConfig(String actionName, String clzName) { + this.name = actionName; + this.clzName = clzName; + } + + public String getClassName() { + return this.clzName; + } + + public void addViewResult(String name, String viewName) { + viewResult.put(name, viewName); + } + + public String getViewName(String resultName) { + return viewResult.get(resultName); + } + } +} diff --git a/group01/349209948/src/week2_0305/litestruts/ConfigurationException.java b/group01/349209948/src/week2_0305/litestruts/ConfigurationException.java new file mode 100644 index 0000000000..d80baae668 --- /dev/null +++ b/group01/349209948/src/week2_0305/litestruts/ConfigurationException.java @@ -0,0 +1,18 @@ +package week2_0305.litestruts; +import java.io.IOException; +import org.jdom2.JDOMException; + +public class ConfigurationException extends RuntimeException{ + + public ConfigurationException(String msg) { + super(msg); + } + + public ConfigurationException(JDOMException e) { + super(e); + } + + public ConfigurationException(IOException e) { + super(e); + } +} diff --git a/group01/349209948/src/week2_0305/litestruts/ConfigurationTest.java b/group01/349209948/src/week2_0305/litestruts/ConfigurationTest.java new file mode 100644 index 0000000000..3c2bf82ecc --- /dev/null +++ b/group01/349209948/src/week2_0305/litestruts/ConfigurationTest.java @@ -0,0 +1,51 @@ +package week2_0305.litestruts; + +import week2_0305.litestruts.Configuration; + +import org.junit.Assert; +import org.junit.Test; + +public class ConfigurationTest { + + Configuration cfg = new Configuration("struts.xml"); + + @Test + public void testGetClassName() { + String clzName = cfg.getClassName("login"); + Assert.assertEquals("week2_0305.litestruts.LoginAction", clzName); + clzName = cfg.getClassName("logout"); + Assert.assertEquals("week2_0305.litestruts.LogoutAction", clzName); + } + @Test + public void testGetFileName() { + String packageName = this.getClass().getPackage().getName(); + packageName = packageName.replace('.', '/'); + packageName = "/" + packageName + "/" + "struts.xml"; + Assert.assertEquals("/week2_0305/litestruts/struts.xml", packageName); + } + + @Test + public void testGetResultView() { + String actionName = "login"; + String resultName = "success"; + String viewName = cfg.getResultView(actionName, resultName); + Assert.assertEquals("/jsp/homepage.jsp", viewName); + + actionName = "login"; + resultName = "fail"; + viewName = cfg.getResultView(actionName, resultName); + Assert.assertEquals("/jsp/showLogin.jsp", viewName); + + actionName = "logout"; + resultName = "success"; + viewName = cfg.getResultView(actionName, resultName); + Assert.assertEquals("/jsp/welcome.jsp", viewName); + + actionName = "logout"; + resultName = "error"; + viewName = cfg.getResultView(actionName, resultName); + Assert.assertEquals("/jsp/error.jsp", viewName); + + } + +} diff --git a/group01/349209948/src/week2_0305/litestruts/LoginAction.java b/group01/349209948/src/week2_0305/litestruts/LoginAction.java new file mode 100644 index 0000000000..ed666b6645 --- /dev/null +++ b/group01/349209948/src/week2_0305/litestruts/LoginAction.java @@ -0,0 +1,39 @@ +package week2_0305.litestruts; + +/** + * 这是一个用来展示登录的业务类, 其中的用户名和密码都是硬编码的。 + * @author liuxin + * + */ +public class LoginAction{ + private String name ; + private String password; + private String message; + + public String getName() { + return name; + } + + public String getPassword() { + return password; + } + + public String execute(){ + if("test".equals(name) && "1234".equals(password)){ + this.message = "login successful"; + return "success"; + } + this.message = "login failed,please check your user/pwd"; + return "fail"; + } + + public void setName(String name){ + this.name = name; + } + public void setPassword(String password){ + this.password = password; + } + public String getMessage(){ + return this.message; + } +} diff --git a/group01/349209948/src/week2_0305/litestruts/ReflectionUtil.java b/group01/349209948/src/week2_0305/litestruts/ReflectionUtil.java new file mode 100644 index 0000000000..a670d6df04 --- /dev/null +++ b/group01/349209948/src/week2_0305/litestruts/ReflectionUtil.java @@ -0,0 +1,74 @@ +package week2_0305.litestruts; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ReflectionUtil { + + public static List getSetterMethods(Class clz) { + List methods = new ArrayList<>(); + for (Method m : clz.getDeclaredMethods()) { + if (m.getName().startsWith("set")) { + methods.add(m); + } + } + return methods; + } + + public static List getGetterMethods(Class clz) { + List methods = new ArrayList(); + for (Method m : clz.getDeclaredMethods()) { + if (m.getName().startsWith("get")) { + methods.add(m); + } + } + return methods; + } + + public static List getMethods(Class clz, String startWithName) { + List methods = new ArrayList<>(); + for (Method m : clz.getDeclaredMethods()) { + if (m.getName().startsWith(startWithName)) { + methods.add(m); + } + } + return methods; + } + + public static void setParameters(Object o, Map params) { + List methods = getSetterMethods(o.getClass()); + for (String name : params.keySet()) { + String methodName = "set" + name; + for (Method m : methods) { + if (m.getName().equalsIgnoreCase(methodName)) { + try { + m.invoke(o, params.get(name)); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + e.printStackTrace(); + } + } + } + } + } + + public static Map getParamterMap(Object o) { + Map params = new HashMap<>(); + List methods = getGetterMethods(o.getClass()); + for (Method m : methods) { + String methodName = m.getName(); + String name = methodName.replaceFirst("get", "").toLowerCase(); + try { + Object value = m.invoke(o); + params.put(name, value); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + e.printStackTrace(); + } + } + return params; + } + +} diff --git a/group01/349209948/src/week2_0305/litestruts/ReflectionUtilTest.java b/group01/349209948/src/week2_0305/litestruts/ReflectionUtilTest.java new file mode 100644 index 0000000000..242487da60 --- /dev/null +++ b/group01/349209948/src/week2_0305/litestruts/ReflectionUtilTest.java @@ -0,0 +1,130 @@ +package week2_0305.litestruts; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.junit.Assert; +import org.junit.Test; + +public class ReflectionUtilTest { + + @Test + public void testGetSetterMethod() throws Exception{ + String name = "week2_0305.litestruts.LoginAction"; + Class clz = Class.forName(name); + List methods = ReflectionUtil.getSetterMethods(clz); + + Assert.assertEquals(2, methods.size()); + + List expectNames = new ArrayList<>(); + expectNames.add("setName"); + expectNames.add("setPassword"); + + Set actualNames = new HashSet<>(); + for(Method m : methods) { + actualNames.add(m.getName()); + } + Assert.assertTrue(actualNames.containsAll(expectNames)); + } + + @Test + public void testSetParameters() throws Exception{ + String name = "week2_0305.litestruts.LoginAction"; + Class clz = Class.forName(name); + Object o = clz.newInstance(); + + Map params = new HashMap(); + params.put("name", "test"); + params.put("password", "123456"); + + ReflectionUtil.setParameters(o, params); + + Field f = clz.getDeclaredField("name"); + f.setAccessible(true); + Assert.assertEquals("test", f.get(o)); + + f = clz.getDeclaredField("password"); + f.setAccessible(true); + Assert.assertEquals("123456", f.get(o)); + } + + @Test + public void testGetGetterMethod() throws Exception{ + String name = "week2_0305.litestruts.LoginAction"; + Class clz = Class.forName(name); + List methods = ReflectionUtil.getGetterMethods(clz); + + Assert.assertEquals(3, methods.size()); + List expectNames = new ArrayList<>(); + expectNames.add("getName"); + expectNames.add("getPassword"); + expectNames.add("getMessage"); + + Set actualNames = new HashSet<>(); + + for(Method m : methods) { + actualNames.add(m.getName()); + } + Assert.assertTrue(actualNames.containsAll(expectNames)); + + } + + @Test + public void testGetMethods() throws Exception{ + String name = "week2_0305.litestruts.LoginAction"; + Class clz = Class.forName(name); + List methods = ReflectionUtil.getMethods(clz, "get"); + + Assert.assertEquals(3, methods.size()); + List expectNames = new ArrayList<>(); + expectNames.add("getName"); + expectNames.add("getPassword"); + expectNames.add("getMessage"); + + Set actualNames = new HashSet<>(); + + for(Method m : methods) { + actualNames.add(m.getName()); + } + Assert.assertTrue(actualNames.containsAll(expectNames)); + + methods = ReflectionUtil.getMethods(clz, "set"); + + Assert.assertEquals(2, methods.size()); + + expectNames = new ArrayList<>(); + expectNames.add("setName"); + expectNames.add("setPassword"); + + actualNames = new HashSet<>(); + for(Method m : methods) { + actualNames.add(m.getName()); + } + Assert.assertTrue(actualNames.containsAll(expectNames)); + } + + @Test + public void testGetParameters() throws Exception{ + String name = "week2_0305.litestruts.LoginAction"; + Class clz = Class.forName(name); + LoginAction action = (LoginAction)clz.newInstance(); + action.setName("test"); + action.setPassword("123456"); + + Map params = ReflectionUtil.getParamterMap(action); + + Assert.assertEquals(3, params.size()); + + Assert.assertEquals(null, params.get("message")); + Assert.assertEquals("test", params.get("name")); + Assert.assertEquals("123456", params.get("password")); + + } + +} diff --git a/group01/349209948/src/week2_0305/litestruts/Struts.java b/group01/349209948/src/week2_0305/litestruts/Struts.java new file mode 100644 index 0000000000..4b97a947c1 --- /dev/null +++ b/group01/349209948/src/week2_0305/litestruts/Struts.java @@ -0,0 +1,55 @@ +package week2_0305.litestruts; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Map; + + + +public class Struts { + + private final static Configuration cfg = new Configuration("struts.xml"); + public static View runAction(String actionName, Map parameters) { + + /* + + 0. 读取配置文件struts.xml + + 1. 根据actionName找到相对应的class , 例如LoginAction, 通过反射实例化(创建对象) + 据parameters中的数据,调用对象的setter方法, 例如parameters中的数据是 + ("name"="test" , "password"="1234") , + 那就应该调用 setName和setPassword方法 + + 2. 通过反射调用对象的exectue 方法, 并获得返回值,例如"success" + + 3. 通过反射找到对象的所有getter方法(例如 getMessage), + 通过反射来调用, 把值和属性形成一个HashMap , 例如 {"message": "登录成功"} , + 放到View对象的parameters + + 4. 根据struts.xml中的 配置,以及execute的返回值, 确定哪一个jsp, + 放到View对象的jsp字段中。 + + */ + String clzName = cfg.getClassName(actionName); + + try { + Class clz = Class.forName(clzName); + Object action = clz.newInstance(); + ReflectionUtil.setParameters(action, parameters); + Method m = clz.getDeclaredMethod("execute"); + String resultName = (String) m.invoke(action); + String jsp = cfg.getResultView(actionName, resultName); + Map params = ReflectionUtil.getParamterMap(action); + View view = new View(); + view.setJsp(jsp); + view.setParameters(params); + return view; + + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return null; + } + +} diff --git a/group01/349209948/src/week2_0305/litestruts/StrutsTest.java b/group01/349209948/src/week2_0305/litestruts/StrutsTest.java new file mode 100644 index 0000000000..3b4ce1d7d1 --- /dev/null +++ b/group01/349209948/src/week2_0305/litestruts/StrutsTest.java @@ -0,0 +1,43 @@ +package week2_0305.litestruts; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; + + + + + +public class StrutsTest { + + @Test + public void testLoginActionSuccess() { + + String actionName = "login"; + + Map params = new HashMap(); + params.put("name","test"); + params.put("password","1234"); + + + View view = Struts.runAction(actionName,params); + + Assert.assertEquals("/jsp/homepage.jsp", view.getJsp()); + Assert.assertEquals("login successful", view.getParameters().get("message")); + } + + @Test + public void testLoginActionFailed() { + String actionName = "login"; + Map params = new HashMap(); + params.put("name","test"); + params.put("password","123456"); //密码和预设的不一致 + + View view = Struts.runAction(actionName,params); + + Assert.assertEquals("/jsp/showLogin.jsp", view.getJsp()); + Assert.assertEquals("login failed,please check your user/pwd", view.getParameters().get("message")); + } +} diff --git a/group01/349209948/src/week2_0305/litestruts/View.java b/group01/349209948/src/week2_0305/litestruts/View.java new file mode 100644 index 0000000000..a414cad3e5 --- /dev/null +++ b/group01/349209948/src/week2_0305/litestruts/View.java @@ -0,0 +1,23 @@ +package week2_0305.litestruts; + +import java.util.Map; + +public class View { + private String jsp; + private Map parameters; + + public String getJsp() { + return jsp; + } + public View setJsp(String jsp) { + this.jsp = jsp; + return this; + } + public Map getParameters() { + return parameters; + } + public View setParameters(Map parameters) { + this.parameters = parameters; + return this; + } +} From f60cf2a56843fc80be5eca5b2abffe6dcda599de Mon Sep 17 00:00:00 2001 From: Alvin Date: Wed, 29 Mar 2017 23:13:28 -0800 Subject: [PATCH 031/203] Homework 3/26 --- .../jvm/loader/ClassFileLoader.java | 46 +++++++++++++++++-- .../jvm/test/ClassFileloaderTest.java | 2 +- .../jvm/util/ClassFileLoaderUtil.java | 14 ++++++ 3 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 group20/404130810/src/com/coderising/jvm/util/ClassFileLoaderUtil.java diff --git a/group20/404130810/src/com/coderising/jvm/loader/ClassFileLoader.java b/group20/404130810/src/com/coderising/jvm/loader/ClassFileLoader.java index ba139c9662..db46e7312b 100644 --- a/group20/404130810/src/com/coderising/jvm/loader/ClassFileLoader.java +++ b/group20/404130810/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -1,24 +1,62 @@ package com.coderising.jvm.loader; +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; import java.util.ArrayList; import java.util.List; +import com.coderising.jvm.util.ClassFileLoaderUtil; + public class ClassFileLoader { private List clzPaths = new ArrayList(); public byte[] readBinaryCode(String className) { - - return null; + String fileFullPath = ClassFileLoaderUtil.generateClassFileFullPath(getClassPath(), className); + InputStream is = null; + ByteArrayOutputStream baos = null; + try { + is = new FileInputStream(fileFullPath); + baos = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int length = 0; + while ((length = is.read(buffer)) != -1) { + baos.write(buffer, 0, length); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + return baos.toByteArray(); } public void addClassPath(String path) { - + clzPaths.add(path); } public String getClassPath() { - return null; + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < clzPaths.size(); i++) { + if (i == clzPaths.size() - 1) { + sb.append(clzPaths.get(i)); + } else { + sb.append(clzPaths.get(i) + ";"); + } + } + return sb.toString(); } } \ No newline at end of file diff --git a/group20/404130810/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group20/404130810/src/com/coderising/jvm/test/ClassFileloaderTest.java index 038b7edf0c..886ce0f25a 100644 --- a/group20/404130810/src/com/coderising/jvm/test/ClassFileloaderTest.java +++ b/group20/404130810/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -9,7 +9,7 @@ public class ClassFileloaderTest { - static String path1 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\mini-jvm\\bin"; + static String path1 = "E:\\MyDev\\mygit\\coding2017\\group20\\404130810\\bin\\"; static String path2 = "C:\temp"; @Before diff --git a/group20/404130810/src/com/coderising/jvm/util/ClassFileLoaderUtil.java b/group20/404130810/src/com/coderising/jvm/util/ClassFileLoaderUtil.java new file mode 100644 index 0000000000..62bb72a3ec --- /dev/null +++ b/group20/404130810/src/com/coderising/jvm/util/ClassFileLoaderUtil.java @@ -0,0 +1,14 @@ +package com.coderising.jvm.util; + +public class ClassFileLoaderUtil { + + public static String generateClassFileFullPath(String classPath, String className) { + String fileType = ".class"; + StringBuilder sb = new StringBuilder(); + sb.append(classPath); + sb.append(className.replace(".", "\\")); + sb.append(fileType); + return sb.toString(); + } + +} From 270d89515329c4306c22a0a06bfff49f7287e864 Mon Sep 17 00:00:00 2001 From: BigJoyce <1091149131@qq.com> Date: Fri, 31 Mar 2017 10:49:35 +0800 Subject: [PATCH 032/203] =?UTF-8?q?=E5=AE=8C=E5=96=84=E7=AC=AC=E4=B8=89?= =?UTF-8?q?=E6=AC=A1=E4=BD=9C=E4=B8=9A=20=E5=A4=9A=E7=BA=BF=E7=A8=8B?= =?UTF-8?q?=E4=B8=8B=E8=BD=BD=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/m0312/download/DownloadThread.java | 3 +- .../com/m0312/download/FileDownloader.java | 25 +++++-- .../m0312/download/FileDownloaderTest.java | 8 +- .../com/m0312/download/LinkedListTest.java | 2 +- .../m0312/download/impl/ConnectionImpl.java | 72 +++++++++++++++++- .../download/impl/ConnectionManagerImpl.java | 2 +- .../2017JavaPro/src/com/test/TestDemo.java | 26 +++++++ .../2017JavaPro/src/com/test/TestThread.java | 37 ++++++++++ .../2017JavaPro/src/com/test/TestThread2.java | 65 +++++++++++++++++ .../src/com/test/downfile/DownThread.java | 71 ++++++++++++++++++ .../src/com/test/downfile/MutilDown.java | 73 +++++++++++++++++++ 11 files changed, 371 insertions(+), 13 deletions(-) create mode 100644 group14/1091149131/2017JavaPro/src/com/test/TestDemo.java create mode 100644 group14/1091149131/2017JavaPro/src/com/test/TestThread.java create mode 100644 group14/1091149131/2017JavaPro/src/com/test/TestThread2.java create mode 100644 group14/1091149131/2017JavaPro/src/com/test/downfile/DownThread.java create mode 100644 group14/1091149131/2017JavaPro/src/com/test/downfile/MutilDown.java diff --git a/group14/1091149131/2017JavaPro/src/com/m0312/download/DownloadThread.java b/group14/1091149131/2017JavaPro/src/com/m0312/download/DownloadThread.java index 8ab66288b0..2c39f00aec 100644 --- a/group14/1091149131/2017JavaPro/src/com/m0312/download/DownloadThread.java +++ b/group14/1091149131/2017JavaPro/src/com/m0312/download/DownloadThread.java @@ -42,6 +42,7 @@ public void run(){ os.write(bytes, startPos, endPos-startPos+1); cyclicBarrier.await();//等待其他线程 */ + System.out.println("开始读["+startPos+","+endPos+"]"); byte[] buffer = conn.read(startPos , endPos); RandomAccessFile file = new RandomAccessFile(descFilePath, "rw"); file.seek(startPos); @@ -56,7 +57,7 @@ public void run(){ } catch (BrokenBarrierException e) { e.printStackTrace(); } - System.out.println("所有线程都下载完成"); + //System.out.println("所有线程都下载完成"); //通知 FileDownloader ,自己已经做完 } diff --git a/group14/1091149131/2017JavaPro/src/com/m0312/download/FileDownloader.java b/group14/1091149131/2017JavaPro/src/com/m0312/download/FileDownloader.java index b6d9102f96..d900a910b6 100644 --- a/group14/1091149131/2017JavaPro/src/com/m0312/download/FileDownloader.java +++ b/group14/1091149131/2017JavaPro/src/com/m0312/download/FileDownloader.java @@ -33,7 +33,16 @@ public FileDownloader(String _url) { this.url = _url; } - + private void createPlaceHolderFile(String fileName, int contentLen) throws IOException{ + + RandomAccessFile file = new RandomAccessFile(fileName,"rw"); + + for(int i=0; i totalLen){ + byte[] data = baos.toByteArray(); + return Arrays.copyOf(data, totalLen); + } + return baos.toByteArray(); + */ + /** + * 开始读[0,1603] + 开始读[1604,3207] + is read length: 1024 + is read length: 1024 + baos.size: 1024 + baos.size: 1024 + 开始读[3208,4811] + is read length: 580 + baos.size: 1604 ///size会累积,等于度过的所有buffer size + is read length: 1024 + baos.size: 1024 + is read length: 580 + baos.size: 1604 + is read length: 580 + baos.size: 1604 + */ } @Override diff --git a/group14/1091149131/2017JavaPro/src/com/m0312/download/impl/ConnectionManagerImpl.java b/group14/1091149131/2017JavaPro/src/com/m0312/download/impl/ConnectionManagerImpl.java index 142b40f2ad..749ec78ca0 100644 --- a/group14/1091149131/2017JavaPro/src/com/m0312/download/impl/ConnectionManagerImpl.java +++ b/group14/1091149131/2017JavaPro/src/com/m0312/download/impl/ConnectionManagerImpl.java @@ -12,7 +12,7 @@ public class ConnectionManagerImpl implements ConnectionManager { @Override public Connection open(String url) throws ConnectionException { - Connection con=new ConnectionImpl(); + Connection con=new ConnectionImpl(url); try { URL website = new URL(url); diff --git a/group14/1091149131/2017JavaPro/src/com/test/TestDemo.java b/group14/1091149131/2017JavaPro/src/com/test/TestDemo.java new file mode 100644 index 0000000000..6bc901bc88 --- /dev/null +++ b/group14/1091149131/2017JavaPro/src/com/test/TestDemo.java @@ -0,0 +1,26 @@ +package com.test; + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; + +public class TestDemo { + + @Before + public void setUp() throws Exception { + } + + @Test + public void test() { + String str="123bbb45ddd5ccc567ddd012"; + String[] data=str.split("[0-9]+"); + System.out.println("共拆分"+data.length); + for (String s : data) { + System.out.println(s); + } + System.out.println("===="); + fail("Not yet implemented"); + } + +} diff --git a/group14/1091149131/2017JavaPro/src/com/test/TestThread.java b/group14/1091149131/2017JavaPro/src/com/test/TestThread.java new file mode 100644 index 0000000000..543d52fca0 --- /dev/null +++ b/group14/1091149131/2017JavaPro/src/com/test/TestThread.java @@ -0,0 +1,37 @@ +package com.test; + +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; +/** + * 所有线程都写完后,才能进行下面任务 + * @author Joy + */ +public class TestThread { + public static void main(String[] args) { + int N = 3; + CyclicBarrier barrier = new CyclicBarrier(N); + for(int i=0;i" + end); + this.start = start; + this.end = end; + this.is = is; + this.raf = raf; + } + + public void run() { + try { + is.skip(start); + raf.seek(start); + // 定义读取输入流内容的的缓存数组(竹筒) + byte[] buff = new byte[BUFF_LEN]; + // 本线程负责下载资源的大小 + long contentLen = end - start; + // 定义最多需要读取几次就可以完成本线程的下载 + long times = contentLen / BUFF_LEN + 4; + // 实际读取的字节数 + int hasRead = 0; + for (int i = 0; i < times; i++) { + hasRead = is.read(buff); + // 如果读取的字节数小于0,则退出循环! + if (hasRead < 0) { + break; + } + raf.write(buff, 0, hasRead); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + // 使用finally块来关闭当前线程的输入流、输出流 + finally { + try { + if (is != null) { + is.close(); + } + if (raf != null) { + raf.close(); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } +} diff --git a/group14/1091149131/2017JavaPro/src/com/test/downfile/MutilDown.java b/group14/1091149131/2017JavaPro/src/com/test/downfile/MutilDown.java new file mode 100644 index 0000000000..21aa754b8b --- /dev/null +++ b/group14/1091149131/2017JavaPro/src/com/test/downfile/MutilDown.java @@ -0,0 +1,73 @@ +package com.test.downfile; + +import java.io.InputStream; +import java.io.RandomAccessFile; +import java.net.URL; +import java.net.URLConnection; + +public class MutilDown { + + public static void main(String[] args) { + //定义几个线程去下载 + final int DOWN_THREAD_NUM = 4; + final String OUT_FILE_NAME = "e:/testfile/down.png"; + InputStream[] isArr = new InputStream[DOWN_THREAD_NUM]; + RandomAccessFile[] outArr = new RandomAccessFile[DOWN_THREAD_NUM]; + try { + // 创建一个URL对象 + URL url = new URL("http://127.0.0.3:8082/applogo.png"); + //URL url = new URL("http://hiphotos.baidu.com/240728057/pic/item/6a50e38242aad8f60cf4d2b3.jpg"); + // 以此URL对象打开第一个输入流 + isArr[0] = url.openStream(); + long fileLen = getFileLength(url); + System.out.println("网络资源的大小" + fileLen); + // 以输出文件名创建第一个RandomAccessFile输出流 + //创建从中读取和向其中写入(可选)的随机存取文件流,第一个参数:文件名,第二个参数是:参数指定用以打开文件的访问模式 + //"rw"可能是可读可写, + outArr[0] = new RandomAccessFile(OUT_FILE_NAME, "rw"); + // 创建一个与下载资源相同大小的空文件 + for (int i = 0; i < fileLen; i++) { + outArr[0].write(0); + } + // 每线程应该下载的字节数 + long numPerThred = fileLen / DOWN_THREAD_NUM; + // 整个下载资源整除后剩下的余数取模 + long left = fileLen % DOWN_THREAD_NUM; + for (int i = 0; i < DOWN_THREAD_NUM; i++) { + // 为每个线程打开一个输入流、一个RandomAccessFile对象, + // 让每个线程分别负责下载资源的不同部分。 + //isArr[0]和outArr[0]已经使用,从不为0开始 + if (i != 0) { + // 以URL打开多个输入流 + isArr[i] = url.openStream(); + // 以指定输出文件创建多个RandomAccessFile对象 + outArr[i] = new RandomAccessFile(OUT_FILE_NAME, "rw"); + } + // 分别启动多个线程来下载网络资源 + if (i == DOWN_THREAD_NUM - 1) { + // 最后一个线程下载指定numPerThred+left个字节 + new DownThread(i * numPerThred, (i + 1) * numPerThred + + left, isArr[i], outArr[i]).start(); + } else { + // 每个线程负责下载一定的numPerThred个字节 + new DownThread(i * numPerThred, (i + 1) * numPerThred, + isArr[i], outArr[i]).start(); + } + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + // 定义获取指定网络资源的长度的方法 + public static long getFileLength(URL url) throws Exception { + long length = 0; + // 打开该URL对应的URLConnection + URLConnection con = url.openConnection(); + // 获取连接URL资源的长度 + long size = con.getContentLength(); + length = size; + return length; + } + +} From 66419dab30370ce76e813d9656ffb63558715e0b Mon Sep 17 00:00:00 2001 From: Alvin Date: Fri, 31 Mar 2017 00:42:20 -0800 Subject: [PATCH 033/203] Homework 3/26 --- .../src/com/basic/linklist/LRUPageFrame.java | 77 +++++++++++++++++-- 1 file changed, 71 insertions(+), 6 deletions(-) diff --git a/group20/404130810/src/com/basic/linklist/LRUPageFrame.java b/group20/404130810/src/com/basic/linklist/LRUPageFrame.java index bdeced0a78..8c32659437 100644 --- a/group20/404130810/src/com/basic/linklist/LRUPageFrame.java +++ b/group20/404130810/src/com/basic/linklist/LRUPageFrame.java @@ -10,16 +10,19 @@ public class LRUPageFrame { private static class Node { - Node prev; - Node next; - int pageNum; + private Node prev; + private Node next; + private int pageNum; - Node() { + Node(int pageNum) { + this.pageNum = pageNum; } } private int capacity; + private int size; + private Node first;// ����ͷ private Node last;// ����β @@ -36,7 +39,23 @@ public LRUPageFrame(int capacity) { * @return */ public void access(int pageNum) { - + if (first == null && last == null) { + handleEmptyContainer(pageNum); + size++; + } else if (existingPage(pageNum) != null) { + if (size == 1) { + return; + } else if(existingPage(pageNum).pageNum == first.pageNum) { + return; + } else{ + moveToFirst(existingPage(pageNum)); + } + } else { + addFirst(pageNum); + if (!ensureCapacity()) { + removeLast(); + } + } } public String toString() { @@ -44,7 +63,6 @@ public String toString() { Node node = first; while (node != null) { buffer.append(node.pageNum); - node = node.next; if (node != null) { buffer.append(","); @@ -53,4 +71,51 @@ public String toString() { return buffer.toString(); } + private boolean ensureCapacity() { + return size <= capacity; + } + + private void handleEmptyContainer(int pageNum) { + first = new Node(pageNum); + last = first; + } + + private Node existingPage(int pageNum) { + Node node = first; + while (node != null) { + if (node.pageNum == pageNum) { + return node; + } + node = node.next; + } + return null; + } + + private void addFirst(int pageNum) { + Node newerFirstNode = new Node(pageNum); + newerFirstNode.next = first; + first.prev = newerFirstNode; + first = newerFirstNode; + size++; + } + + private void removeLast() { + Node lastPreNode = last.prev; + last.prev = null; + lastPreNode.next = null; + last = lastPreNode; + size--; + } + + private void moveToFirst(Node existingPage) { + if(existingPage.pageNum == last.pageNum){ + addFirst(existingPage.pageNum); + removeLast(); + }else{ + int tempPageNum = first.pageNum; + first.pageNum = existingPage.pageNum; + existingPage.pageNum = tempPageNum; + } + } + } \ No newline at end of file From cd09dee1223dfe3bcea55b7935abde64c7b67950 Mon Sep 17 00:00:00 2001 From: JayXu Date: Fri, 31 Mar 2017 21:24:04 +0800 Subject: [PATCH 034/203] c c --- group15/1511_714512544/.idea/workspace.xml | 244 ++++++++---------- .../coderising/download/ConnectionTest.class | Bin 0 -> 1576 bytes .../download/FileDownloader$1.class | Bin 0 -> 820 bytes .../coderising/download/FileDownloader.class | Bin 3352 -> 3351 bytes .../download/FileDownloaderTest.class | Bin 2168 -> 2143 bytes .../coding/basic/ReConstructBST$Node.class | Bin 0 -> 514 bytes .../com/coding/basic/ReConstructBST.class | Bin 0 -> 2449 bytes .../com/coding/basic/ReConstructBSTTest.class | Bin 0 -> 1152 bytes .../coderising/download/FileDownloader.java | 15 +- .../download/FileDownloaderTest.java | 4 +- .../download/impl/ConnectionImpl.java | 2 +- 11 files changed, 116 insertions(+), 149 deletions(-) create mode 100644 group15/1511_714512544/out/production/1511_714512544/com/coderising/download/ConnectionTest.class create mode 100644 group15/1511_714512544/out/production/1511_714512544/com/coderising/download/FileDownloader$1.class create mode 100644 group15/1511_714512544/out/production/1511_714512544/com/coding/basic/ReConstructBST$Node.class create mode 100644 group15/1511_714512544/out/production/1511_714512544/com/coding/basic/ReConstructBST.class create mode 100644 group15/1511_714512544/out/production/1511_714512544/com/coding/basic/ReConstructBSTTest.class diff --git a/group15/1511_714512544/.idea/workspace.xml b/group15/1511_714512544/.idea/workspace.xml index 9cd6e9b941..fec3c287e7 100644 --- a/group15/1511_714512544/.idea/workspace.xml +++ b/group15/1511_714512544/.idea/workspace.xml @@ -2,9 +2,12 @@ + + - - + + + - + @@ -87,7 +90,7 @@
- + @@ -100,6 +103,7 @@ + @@ -139,42 +143,15 @@ - - - - - - - - - - - - - - + @@ -199,7 +176,7 @@ - + @@ -226,39 +203,45 @@ - + - - - + - - + - - + - - - - - + + + + - - - - - + + + + + @@ -769,7 +752,10 @@ - + + + + 1488937445293 @@ -841,18 +827,22 @@ - - - - - - + + - - + + @@ -860,6 +850,9 @@ + + + @@ -877,7 +870,7 @@ - @@ -906,7 +899,7 @@ - + @@ -962,13 +955,6 @@ - - - - - - - @@ -1200,7 +1186,6 @@ - @@ -1215,24 +1200,6 @@ - - - - - - - - - - - - - - - - - - @@ -1241,7 +1208,6 @@ - @@ -1273,73 +1239,73 @@ - + - - + + - + - - + + - + - - + + - + + + + + + + + - - + + - - + + - + - - + + - + - - - - - + + - + - - - + + - + - - - - - + + diff --git a/group15/1511_714512544/out/production/1511_714512544/com/coderising/download/ConnectionTest.class b/group15/1511_714512544/out/production/1511_714512544/com/coderising/download/ConnectionTest.class new file mode 100644 index 0000000000000000000000000000000000000000..f1636279469017868566988ab07c7c8484e9c8ae GIT binary patch literal 1576 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 CFe5Ag literal 0 HcmV?d00001 diff --git a/group15/1511_714512544/out/production/1511_714512544/com/coding/basic/ReConstructBSTTest.class b/group15/1511_714512544/out/production/1511_714512544/com/coding/basic/ReConstructBSTTest.class new file mode 100644 index 0000000000000000000000000000000000000000..a2d024465694d8e27c2ad86b05ab36d34631159c GIT binary patch literal 1152 zcma)5U2hUW6g>mW4j|g?x2@JzODhy~UwqS;w5TZwvI(sugr{Yh)@fk3nH^AnlTSX` z7~>D{M;Y%D2K$u^rGCwj zE|uF1RxRoahPj3eMRPRl33crE29#N7M1enO`${J9Bx&i7GG^Fm1kun9qP`4I-JT!I zz-@_I6vkSO0)23Fd@N%9k|7fd{o$M;|Mqhr&b1^2$1cNKYZPiZ6m1zx65kKQNc*O2 z`l?g+Y($5255!5N1PNue@YS2>Q^+vih_34UCt4^f=YoH|33{%Cr}{!Mq`GwmF2hO4 zLXM|2annp(sE46YwSgbUf=1e%Hc~O6Q7`94|H+v7qiCc8@lGatTfM!B=V$)dFTe)p zC>5}Tashj&Fl^7TM(UW*-GNWL_IhU`&tdOY_DT;ufwxmC+kq)*bes^mlz5ShUzxqc~Z|3&|uzIsuxH#pIsn* zJ@1Oy>Kckz#~~h|iHB%m!yI_;vi)TKBJFw^D>U~ZWmd^c5junW#7N`zb~fnfDLgWE PlaxW4^iR{5Tu1INA$sm& literal 0 HcmV?d00001 diff --git a/group15/1511_714512544/src/com/coderising/download/FileDownloader.java b/group15/1511_714512544/src/com/coderising/download/FileDownloader.java index f8e78d4f7a..f4351d66f1 100644 --- a/group15/1511_714512544/src/com/coderising/download/FileDownloader.java +++ b/group15/1511_714512544/src/com/coderising/download/FileDownloader.java @@ -12,7 +12,7 @@ public class FileDownloader { private String url; - private String localFile; + private String savepath; DownloadListener listener; @@ -21,9 +21,9 @@ public class FileDownloader { private static final int DOWNLOAD_TRHEAD_NUM = 3; - public FileDownloader(String _url, String localFile) { + public FileDownloader(String _url, String savepath) { this.url = _url; - this.localFile = localFile; + this.savepath = savepath; } @@ -42,9 +42,10 @@ public void execute(){ // 下面的代码是示例代码, 也就是说只有一个线程, 你需要改造成多线程的。 + //栅栏 CyclicBarrier barrier = new CyclicBarrier(DOWNLOAD_TRHEAD_NUM , new Runnable(){ public void run(){ - listener.notifyFinished(); + listener.notifyFinished(); //所有线程到了之后执行 } }); @@ -55,7 +56,7 @@ public void run(){ int length = conn.getContentLength(); - createPlaceHolderFile(this.localFile, length); + createPlaceHolderFile(this.savepath, length); int[][] ranges = allocateDownloadRange(DOWNLOAD_TRHEAD_NUM, length); @@ -63,7 +64,7 @@ public void run(){ DownloadThread thread = new DownloadThread( - cm.open(url),ranges[i][0], ranges[i][1], localFile, barrier ); + cm.open(url),ranges[i][0], ranges[i][1], savepath, barrier ); thread.start(); } @@ -77,7 +78,7 @@ public void run(){ } } - + //占住磁盘位置 private void createPlaceHolderFile(String fileName, int contentLen) throws IOException{ RandomAccessFile file = new RandomAccessFile(fileName,"rw"); diff --git a/group15/1511_714512544/src/com/coderising/download/FileDownloaderTest.java b/group15/1511_714512544/src/com/coderising/download/FileDownloaderTest.java index f5e375e118..693249b30d 100644 --- a/group15/1511_714512544/src/com/coderising/download/FileDownloaderTest.java +++ b/group15/1511_714512544/src/com/coderising/download/FileDownloaderTest.java @@ -21,9 +21,9 @@ public void tearDown() throws Exception { @Test public void testDownload() { - String url = "https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/logo_white_fe6da1ec.png"; + String url = "http://www.hinews.cn/pic/0/13/91/26/13912621_821796.jpg"; - FileDownloader downloader = new FileDownloader(url, "d:/baidu.png"); + FileDownloader downloader = new FileDownloader(url, "d:/13912621_821796.jpg"); ConnectionManager cm = new ConnectionManagerImpl(); downloader.setConnectionManager(cm); //设置连接管理器 diff --git a/group15/1511_714512544/src/com/coderising/download/impl/ConnectionImpl.java b/group15/1511_714512544/src/com/coderising/download/impl/ConnectionImpl.java index 195fc06539..fc075366c5 100644 --- a/group15/1511_714512544/src/com/coderising/download/impl/ConnectionImpl.java +++ b/group15/1511_714512544/src/com/coderising/download/impl/ConnectionImpl.java @@ -32,7 +32,7 @@ public ConnectionImpl(String _url) { public byte[] read(int startPos, int endPos) throws IOException { HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestProperty("Range", "bytes="+startPos+"-"+endPos); + conn.setRequestProperty("Range", "bytes="+startPos+"-"+endPos); //重要 InputStream is= conn.getInputStream(); From e4d3ea11f7921aa5ba82958c275f3850bb497e94 Mon Sep 17 00:00:00 2001 From: sdnb Date: Sat, 1 Apr 2017 00:16:22 +0800 Subject: [PATCH 035/203] =?UTF-8?q?=E5=A4=9A=E7=BA=BF=E7=A8=8B=E4=B8=8B?= =?UTF-8?q?=E8=BD=BD=E7=BA=BF=E7=A8=8B=E6=B1=A0=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coding/week3/download/FileDownloader.java | 3 +- .../coding/week3/download1/DownloadTask.java | 50 +++++++ .../week3/download1/FileDownloader.java | 122 ++++++++++++++++++ .../week3/download1/api/Connection.java | 26 ++++ .../download1/api/ConnectionException.java | 10 ++ .../download1/api/ConnectionManager.java | 10 ++ .../week3/download1/api/DownloadListener.java | 5 + .../week3/download1/impl/ConnectionImpl.java | 55 ++++++++ .../download1/impl/ConnectionManagerImpl.java | 37 ++++++ .../com/coding/week3/FileDownloaderTest.java | 27 ++-- 10 files changed, 330 insertions(+), 15 deletions(-) create mode 100644 group24/494800949/src/main/java/com/coding/week3/download1/DownloadTask.java create mode 100644 group24/494800949/src/main/java/com/coding/week3/download1/FileDownloader.java create mode 100644 group24/494800949/src/main/java/com/coding/week3/download1/api/Connection.java create mode 100644 group24/494800949/src/main/java/com/coding/week3/download1/api/ConnectionException.java create mode 100644 group24/494800949/src/main/java/com/coding/week3/download1/api/ConnectionManager.java create mode 100644 group24/494800949/src/main/java/com/coding/week3/download1/api/DownloadListener.java create mode 100644 group24/494800949/src/main/java/com/coding/week3/download1/impl/ConnectionImpl.java create mode 100644 group24/494800949/src/main/java/com/coding/week3/download1/impl/ConnectionManagerImpl.java diff --git a/group24/494800949/src/main/java/com/coding/week3/download/FileDownloader.java b/group24/494800949/src/main/java/com/coding/week3/download/FileDownloader.java index 0e40bc38a8..75455935be 100644 --- a/group24/494800949/src/main/java/com/coding/week3/download/FileDownloader.java +++ b/group24/494800949/src/main/java/com/coding/week3/download/FileDownloader.java @@ -68,7 +68,6 @@ public void execute() throws IOException { lastLen = fileLength % nThread; perLenOfThread = (fileLength + (nThread - lastLen)) / nThread; } - //计算 //启动线程 for (int i = 0; i < nThread; i++) { @@ -87,7 +86,7 @@ public void execute() throws IOException { } catch (ConnectionException e) { e.printStackTrace(); - }finally{ + } finally{ if(conn != null){ conn.close(); } diff --git a/group24/494800949/src/main/java/com/coding/week3/download1/DownloadTask.java b/group24/494800949/src/main/java/com/coding/week3/download1/DownloadTask.java new file mode 100644 index 0000000000..0c09657dc4 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/week3/download1/DownloadTask.java @@ -0,0 +1,50 @@ +package com.coding.week3.download1; + +import com.coding.week3.download.api.Connection; + +import java.io.IOException; +import java.io.InputStream; +import java.io.RandomAccessFile; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Created by Administrator on 2017/3/31 0031. + */ +public class DownloadTask implements Runnable { + private static final int BUFF_SIZE = 1024; + Connection conn; + int startPos; + int endPos; + RandomAccessFile ras; + AtomicInteger downloadBytesCount; + + public DownloadTask(Connection conn, int startPos, int endPos, RandomAccessFile ras, AtomicInteger downloadBytesCount) { + this.conn = conn; + this.startPos = startPos; + this.endPos = endPos; + this.ras = ras; + this.downloadBytesCount = downloadBytesCount; + } + + @Override + public void run() { + try { + InputStream is = conn.getInputStream(); + is.skip(startPos); + ras.seek(startPos); + byte[] bytes = new byte[BUFF_SIZE]; + int hasRead = 0; + int readTimes = (endPos - startPos) / BUFF_SIZE + 4; + for (int i = 0; i < readTimes; i++) { + hasRead = is.read(bytes ); + if (hasRead == -1) { + break; + } + ras.write(bytes, 0, hasRead); + downloadBytesCount.getAndAdd(hasRead); + } + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/group24/494800949/src/main/java/com/coding/week3/download1/FileDownloader.java b/group24/494800949/src/main/java/com/coding/week3/download1/FileDownloader.java new file mode 100644 index 0000000000..81c7c87508 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/week3/download1/FileDownloader.java @@ -0,0 +1,122 @@ +package com.coding.week3.download1; + + +import com.coding.week3.download.api.Connection; +import com.coding.week3.download.api.ConnectionException; +import com.coding.week3.download.api.ConnectionManager; +import com.coding.week3.download.api.DownloadListener; + +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +public class FileDownloader { + + String url; + + DownloadListener listener; + + ConnectionManager cm; + + String savePath; + + int nThread; + + int fileLength; + + AtomicInteger downloadBytesCount; + + public FileDownloader(String _url) { + this.url = _url; + } + + public FileDownloader(int nThread, String savePath, String url) { + this.nThread = nThread; + this.savePath = savePath; + this.url = url; + downloadBytesCount = new AtomicInteger(0); + } + + public void execute() throws IOException { + // 在这里实现你的代码, 注意: 需要用多线程实现下载 + // 这个类依赖于其他几个接口, 你需要写这几个接口的实现代码 + // (1) ConnectionManager , 可以打开一个连接,通过Connection可以读取其中的一段(用startPos, endPos来指定) + // (2) DownloadListener, 由于是多线程下载, 调用这个类的客户端不知道什么时候结束,所以你需要实现当所有 + // 线程都执行完以后, 调用listener的notifiedFinished方法, 这样客户端就能收到通知。 + // 具体的实现思路: + // 1. 需要调用ConnectionManager的open方法打开连接, 然后通过Connection.getContentLength方法获得文件的长度 + // 2. 至少启动3个线程下载, 注意每个线程需要先调用ConnectionManager的open方法 + // 然后调用read方法, read方法中有读取文件的开始位置和结束位置的参数, 返回值是byte[]数组 + // 3. 把byte数组写入到文件中 + // 4. 所有的线程都下载完成以后, 需要调用listener的notifiedFinished方法 + + // 下面的代码是示例代码, 也就是说只有一个线程, 你需要改造成多线程的。 + Connection conn = null; + try { + + //根据文件长度为每个线程分配下载字节数量 + conn = cm.open(this.url); + fileLength = conn.getContentLength(); + //已读字节数量 + + ExecutorService executorService = Executors.newFixedThreadPool(nThread); + int[][] allotSize = alloctSize(nThread, fileLength); + + for (int i = 0; i < nThread; i++) { + RandomAccessFile ras = new RandomAccessFile(savePath, "rw"); + executorService.execute(new DownloadTask(cm.open(url), allotSize[0][i], + allotSize[1][i], ras , downloadBytesCount)); + } + //关闭线程池 + executorService.shutdown(); + boolean isTermination ; + do { + System.out.println("已下载:"+(downloadBytesCount.get()/1024)+"K,百分比:"+ (downloadBytesCount.get()/ (fileLength/100))+"%" ); + //循环等待,直到线程全部关闭 + isTermination = executorService.awaitTermination(500, TimeUnit.MILLISECONDS); + } while (!isTermination); + + + } catch (ConnectionException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally{ + if(conn != null){ + conn.close(); + } + } + } + + private int[][] alloctSize(int nThread, int fileLength){ + int[][] allotSize = new int[2][nThread]; + int perLenOfTask = fileLength / nThread; + int lastLen = fileLength % nThread; + for (int i = 0; i < nThread; i++) { + int start = perLenOfTask * i; + int end = perLenOfTask * (i + 1) - 1; + if (i == nThread - 1) { + end += lastLen; + } + allotSize[0][i] = start; + allotSize[1][i] = end; + } + return allotSize; + } + + public void setListener(DownloadListener listener) { + this.listener = listener; + } + + public void setConnectionManager(ConnectionManager ucm){ + this.cm = ucm; + } + + public DownloadListener getListener(){ + return this.listener; + } + +} diff --git a/group24/494800949/src/main/java/com/coding/week3/download1/api/Connection.java b/group24/494800949/src/main/java/com/coding/week3/download1/api/Connection.java new file mode 100644 index 0000000000..0811902dda --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/week3/download1/api/Connection.java @@ -0,0 +1,26 @@ +package com.coding.week3.download1.api; + +import java.io.IOException; +import java.io.InputStream; + +public interface Connection { + /** + * 给定开始和结束位置, 读取数据, 返回值是字节数组 + * @param startPos 开始位置, 从0开始 + * @param endPos 结束位置 + * @return + */ + byte[] read(int startPos, int endPos) throws IOException; + /** + * 得到数据内容的长度 + * @return + */ + int getContentLength(); + + /** + * 关闭连接 + */ + void close(); + + InputStream getInputStream() throws IOException; +} diff --git a/group24/494800949/src/main/java/com/coding/week3/download1/api/ConnectionException.java b/group24/494800949/src/main/java/com/coding/week3/download1/api/ConnectionException.java new file mode 100644 index 0000000000..14f1291198 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/week3/download1/api/ConnectionException.java @@ -0,0 +1,10 @@ +package com.coding.week3.download1.api; + +public class ConnectionException extends Exception { + public ConnectionException() { + } + + public ConnectionException(String message) { + super(message); + } +} diff --git a/group24/494800949/src/main/java/com/coding/week3/download1/api/ConnectionManager.java b/group24/494800949/src/main/java/com/coding/week3/download1/api/ConnectionManager.java new file mode 100644 index 0000000000..9674179b7a --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/week3/download1/api/ConnectionManager.java @@ -0,0 +1,10 @@ +package com.coding.week3.download1.api; + +public interface ConnectionManager { + /** + * 给定一个url , 打开一个连接 + * @param url + * @return + */ + Connection open(String url) throws ConnectionException; +} diff --git a/group24/494800949/src/main/java/com/coding/week3/download1/api/DownloadListener.java b/group24/494800949/src/main/java/com/coding/week3/download1/api/DownloadListener.java new file mode 100644 index 0000000000..2195dd9be0 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/week3/download1/api/DownloadListener.java @@ -0,0 +1,5 @@ +package com.coding.week3.download1.api; + +public interface DownloadListener { + void notifyFinished(); +} diff --git a/group24/494800949/src/main/java/com/coding/week3/download1/impl/ConnectionImpl.java b/group24/494800949/src/main/java/com/coding/week3/download1/impl/ConnectionImpl.java new file mode 100644 index 0000000000..3e8773ecca --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/week3/download1/impl/ConnectionImpl.java @@ -0,0 +1,55 @@ +package com.coding.week3.download1.impl; + +import com.coding.week3.download1.api.Connection; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; + + +public class ConnectionImpl implements Connection { + + private HttpURLConnection httpURLConnection; + + public ConnectionImpl() { + } + + public ConnectionImpl(HttpURLConnection httpURLConnection) { + this.httpURLConnection = httpURLConnection; + } + + + @Override + public byte[] read(int startPos, int endPos) throws IOException { + if (startPos < 0 || endPos < 0 || endPos > getContentLength()) { + throw new IndexOutOfBoundsException(); + } + if (startPos >= endPos) { + throw new IllegalArgumentException(); + } + byte[] bytes = new byte[endPos - startPos + 1]; + + InputStream inputStream = httpURLConnection.getInputStream(); + BufferedInputStream bis = new BufferedInputStream(inputStream); + bis.read(bytes, startPos ,bytes.length-1); + return bytes; + } + + + @Override + public int getContentLength() { + return httpURLConnection.getContentLength(); + } + + @Override + public void close() { + httpURLConnection.disconnect(); + } + + @Override + public InputStream getInputStream() throws IOException { + return httpURLConnection.getInputStream(); + } + +} diff --git a/group24/494800949/src/main/java/com/coding/week3/download1/impl/ConnectionManagerImpl.java b/group24/494800949/src/main/java/com/coding/week3/download1/impl/ConnectionManagerImpl.java new file mode 100644 index 0000000000..3e65687879 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/week3/download1/impl/ConnectionManagerImpl.java @@ -0,0 +1,37 @@ +package com.coding.week3.download1.impl; + + +import com.coding.week3.download1.api.Connection; +import com.coding.week3.download1.api.ConnectionException; +import com.coding.week3.download1.api.ConnectionManager; + +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; + +public class ConnectionManagerImpl implements ConnectionManager { + + @Override + public Connection open(String url) throws ConnectionException { + try { + // 统一资源 + URL realurl = new URL(url); + // 连接类的父类,抽象类 + URLConnection urlConnection = realurl.openConnection(); + // http的连接类 + HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection; + // 设定请求的方法,默认是GET + httpURLConnection.setRequestMethod("GET"); + httpURLConnection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); + // 设置字符编码 + httpURLConnection.setRequestProperty("Charset", "UTF-8"); + // 打开到此 URL 引用的资源的通信链接(如果尚未建立这样的连接)。 + httpURLConnection.connect(); + return new ConnectionImpl(httpURLConnection); + } catch (java.io.IOException e) { + e.printStackTrace(); + throw new ConnectionException(e.getMessage()); + } + } + +} diff --git a/group24/494800949/src/test/java/com/coding/week3/FileDownloaderTest.java b/group24/494800949/src/test/java/com/coding/week3/FileDownloaderTest.java index 5b423f145f..d0985c04d4 100644 --- a/group24/494800949/src/test/java/com/coding/week3/FileDownloaderTest.java +++ b/group24/494800949/src/test/java/com/coding/week3/FileDownloaderTest.java @@ -1,15 +1,16 @@ package com.coding.week3; -import com.coding.week3.download.FileDownloader; import com.coding.week3.download.api.ConnectionManager; import com.coding.week3.download.api.DownloadListener; import com.coding.week3.download.impl.ConnectionManagerImpl; +import com.coding.week3.download1.FileDownloader; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import java.io.*; +import java.io.File; +import java.io.IOException; public class FileDownloaderTest { @@ -49,17 +50,17 @@ public void notifyFinished() { downloader.execute(); - // 等待多线程下载程序执行完毕 - while (!downloadFinished) { - try { - System.out.println("还没有下载完成,休眠五秒"); - //休眠5秒 - Thread.sleep(5000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - System.out.println("下载完成!"); +// // 等待多线程下载程序执行完毕 +// while (!downloadFinished) { +// try { +// System.out.println("还没有下载完成,休眠五秒"); +// //休眠5秒 +// Thread.sleep(5000); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } +// } +// System.out.println("下载完成!"); From 64c524d64a4713bce3d9c41102ca6ebc52a1c8a4 Mon Sep 17 00:00:00 2001 From: Korben_CHY Date: Sat, 1 Apr 2017 11:16:54 +0800 Subject: [PATCH 036/203] rename package name and add project mini-jvm by Korben --- .../{ => data-structure}/lib/dom4j-1.6.1.jar | Bin .../lib/fastjson-1.2.7.jar | Bin .../lib/hamcrest-core-1.3.jar | Bin .../{ => data-structure}/lib/junit-4.12.jar | Bin .../src/org/korben/Main.java | 0 .../korben/coderising/array/ArrayUtil.java | 0 .../coderising/array/ArrayUtilTest.java | 0 .../coderising/download/DownloadThread.java | 0 .../coderising/download/FileDownloader.java | 0 .../download/FileDownloaderTest.java | 0 .../coderising/download/api/Connection.java | 0 .../download/api/ConnectionException.java | 0 .../download/api/ConnectionManager.java | 0 .../download/api/DownloadListener.java | 0 .../download/impl/ConnectionImpl.java | 0 .../download/impl/ConnectionManagerImpl.java | 0 .../coderising/litestruts/LoginAction.java | 0 .../korben/coderising/litestruts/Struts.java | 0 .../coderising/litestruts/StrutsTest.java | 0 .../korben/coderising/litestruts/View.java | 0 .../litestruts/dom/StrutsAction.java | 0 .../litestruts/util/StrutsParser.java | 0 .../korben/coding/basic/list/KArrayList.java | 0 .../korben/coding/basic/list/KIterator.java | 0 .../korben/coding/basic/list/KLinkedList.java | 0 .../coding/basic/list/KLinkedListTest.java | 0 .../org/korben/coding/basic/list/KList.java | 0 .../coding/basic/list/KListIteratorTest.java | 0 .../korben/coding/basic/list/KListTest.java | 0 .../coding/basic/queue/KArrayQueue.java | 0 .../org/korben/coding/basic/queue/KQueue.java | 0 .../korben/coding/basic/queue/KQueueTest.java | 0 .../org/korben/coding/basic/stack/KStack.java | 0 .../korben/coding/basic/stack/KStackTest.java | 0 .../coding/basic/tree/BinaryTreeNode.java | 0 .../coding/basic/tree/BinaryTreeNodeTest.java | 0 .../mini-jvm/lib/hamcrest-core-1.3.jar | Bin 0 -> 45024 bytes .../mini-jvm/lib/junit-4.12.jar | Bin 0 -> 314932 bytes .../jvm/loader/ClassFileLoader.java | 22 ++++++ .../jvm/test/ClassFileloaderTest.java | 74 ++++++++++++++++++ .../com/coderising/jvm/test/EmployeeV1.java | 28 +++++++ .../coderising/litestruts/util/struts.xml | 11 --- 42 files changed, 124 insertions(+), 11 deletions(-) rename group20/1107837739/1107837739Learning/{ => data-structure}/lib/dom4j-1.6.1.jar (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/lib/fastjson-1.2.7.jar (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/lib/hamcrest-core-1.3.jar (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/lib/junit-4.12.jar (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/Main.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coderising/array/ArrayUtil.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coderising/array/ArrayUtilTest.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coderising/download/DownloadThread.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coderising/download/FileDownloader.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coderising/download/FileDownloaderTest.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coderising/download/api/Connection.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coderising/download/api/ConnectionException.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coderising/download/api/ConnectionManager.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coderising/download/api/DownloadListener.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coderising/download/impl/ConnectionImpl.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coderising/download/impl/ConnectionManagerImpl.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coderising/litestruts/LoginAction.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coderising/litestruts/Struts.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coderising/litestruts/StrutsTest.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coderising/litestruts/View.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coderising/litestruts/dom/StrutsAction.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coderising/litestruts/util/StrutsParser.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coding/basic/list/KArrayList.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coding/basic/list/KIterator.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coding/basic/list/KLinkedList.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coding/basic/list/KLinkedListTest.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coding/basic/list/KList.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coding/basic/list/KListIteratorTest.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coding/basic/list/KListTest.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coding/basic/queue/KArrayQueue.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coding/basic/queue/KQueue.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coding/basic/queue/KQueueTest.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coding/basic/stack/KStack.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coding/basic/stack/KStackTest.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coding/basic/tree/BinaryTreeNode.java (100%) rename group20/1107837739/1107837739Learning/{ => data-structure}/src/org/korben/coding/basic/tree/BinaryTreeNodeTest.java (100%) create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/lib/hamcrest-core-1.3.jar create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/lib/junit-4.12.jar create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/test/EmployeeV1.java delete mode 100644 group20/1107837739/1107837739Learning/src/org/korben/coderising/litestruts/util/struts.xml diff --git a/group20/1107837739/1107837739Learning/lib/dom4j-1.6.1.jar b/group20/1107837739/1107837739Learning/data-structure/lib/dom4j-1.6.1.jar similarity index 100% rename from group20/1107837739/1107837739Learning/lib/dom4j-1.6.1.jar rename to group20/1107837739/1107837739Learning/data-structure/lib/dom4j-1.6.1.jar diff --git a/group20/1107837739/1107837739Learning/lib/fastjson-1.2.7.jar b/group20/1107837739/1107837739Learning/data-structure/lib/fastjson-1.2.7.jar similarity index 100% rename from group20/1107837739/1107837739Learning/lib/fastjson-1.2.7.jar rename to group20/1107837739/1107837739Learning/data-structure/lib/fastjson-1.2.7.jar diff --git a/group20/1107837739/1107837739Learning/lib/hamcrest-core-1.3.jar b/group20/1107837739/1107837739Learning/data-structure/lib/hamcrest-core-1.3.jar similarity index 100% rename from group20/1107837739/1107837739Learning/lib/hamcrest-core-1.3.jar rename to group20/1107837739/1107837739Learning/data-structure/lib/hamcrest-core-1.3.jar diff --git a/group20/1107837739/1107837739Learning/lib/junit-4.12.jar b/group20/1107837739/1107837739Learning/data-structure/lib/junit-4.12.jar similarity index 100% rename from group20/1107837739/1107837739Learning/lib/junit-4.12.jar rename to group20/1107837739/1107837739Learning/data-structure/lib/junit-4.12.jar diff --git a/group20/1107837739/1107837739Learning/src/org/korben/Main.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/Main.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/Main.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/Main.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coderising/array/ArrayUtil.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/array/ArrayUtil.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coderising/array/ArrayUtil.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/array/ArrayUtil.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coderising/array/ArrayUtilTest.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/array/ArrayUtilTest.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coderising/array/ArrayUtilTest.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/array/ArrayUtilTest.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coderising/download/DownloadThread.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/DownloadThread.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coderising/download/DownloadThread.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/DownloadThread.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coderising/download/FileDownloader.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/FileDownloader.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coderising/download/FileDownloader.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/FileDownloader.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coderising/download/FileDownloaderTest.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/FileDownloaderTest.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coderising/download/FileDownloaderTest.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/FileDownloaderTest.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coderising/download/api/Connection.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/api/Connection.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coderising/download/api/Connection.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/api/Connection.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coderising/download/api/ConnectionException.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/api/ConnectionException.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coderising/download/api/ConnectionException.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/api/ConnectionException.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coderising/download/api/ConnectionManager.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/api/ConnectionManager.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coderising/download/api/ConnectionManager.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/api/ConnectionManager.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coderising/download/api/DownloadListener.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/api/DownloadListener.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coderising/download/api/DownloadListener.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/api/DownloadListener.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coderising/download/impl/ConnectionImpl.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/impl/ConnectionImpl.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coderising/download/impl/ConnectionImpl.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/impl/ConnectionImpl.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coderising/download/impl/ConnectionManagerImpl.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/impl/ConnectionManagerImpl.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coderising/download/impl/ConnectionManagerImpl.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/impl/ConnectionManagerImpl.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coderising/litestruts/LoginAction.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/LoginAction.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coderising/litestruts/LoginAction.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/LoginAction.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coderising/litestruts/Struts.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/Struts.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coderising/litestruts/Struts.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/Struts.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coderising/litestruts/StrutsTest.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/StrutsTest.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coderising/litestruts/StrutsTest.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/StrutsTest.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coderising/litestruts/View.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/View.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coderising/litestruts/View.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/View.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coderising/litestruts/dom/StrutsAction.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/dom/StrutsAction.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coderising/litestruts/dom/StrutsAction.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/dom/StrutsAction.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coderising/litestruts/util/StrutsParser.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/util/StrutsParser.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coderising/litestruts/util/StrutsParser.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/util/StrutsParser.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coding/basic/list/KArrayList.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KArrayList.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coding/basic/list/KArrayList.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KArrayList.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coding/basic/list/KIterator.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KIterator.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coding/basic/list/KIterator.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KIterator.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coding/basic/list/KLinkedList.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KLinkedList.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coding/basic/list/KLinkedList.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KLinkedList.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coding/basic/list/KLinkedListTest.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KLinkedListTest.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coding/basic/list/KLinkedListTest.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KLinkedListTest.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coding/basic/list/KList.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KList.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coding/basic/list/KList.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KList.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coding/basic/list/KListIteratorTest.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KListIteratorTest.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coding/basic/list/KListIteratorTest.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KListIteratorTest.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coding/basic/list/KListTest.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KListTest.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coding/basic/list/KListTest.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KListTest.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coding/basic/queue/KArrayQueue.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/queue/KArrayQueue.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coding/basic/queue/KArrayQueue.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/queue/KArrayQueue.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coding/basic/queue/KQueue.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/queue/KQueue.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coding/basic/queue/KQueue.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/queue/KQueue.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coding/basic/queue/KQueueTest.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/queue/KQueueTest.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coding/basic/queue/KQueueTest.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/queue/KQueueTest.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coding/basic/stack/KStack.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/stack/KStack.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coding/basic/stack/KStack.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/stack/KStack.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coding/basic/stack/KStackTest.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/stack/KStackTest.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coding/basic/stack/KStackTest.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/stack/KStackTest.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coding/basic/tree/BinaryTreeNode.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/tree/BinaryTreeNode.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coding/basic/tree/BinaryTreeNode.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/tree/BinaryTreeNode.java diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coding/basic/tree/BinaryTreeNodeTest.java b/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/tree/BinaryTreeNodeTest.java similarity index 100% rename from group20/1107837739/1107837739Learning/src/org/korben/coding/basic/tree/BinaryTreeNodeTest.java rename to group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/tree/BinaryTreeNodeTest.java diff --git a/group20/1107837739/1107837739Learning/mini-jvm/lib/hamcrest-core-1.3.jar b/group20/1107837739/1107837739Learning/mini-jvm/lib/hamcrest-core-1.3.jar new file mode 100644 index 0000000000000000000000000000000000000000..9d5fe16e3dd37ebe79a36f61f5d0e1a69a653a8a GIT binary patch literal 45024 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 UgpPtD2z>DYYp}SJr5?)v0beu;=l}o! literal 0 HcmV?d00001 diff --git a/group20/1107837739/1107837739Learning/mini-jvm/lib/junit-4.12.jar b/group20/1107837739/1107837739Learning/mini-jvm/lib/junit-4.12.jar new file mode 100644 index 0000000000000000000000000000000000000000..3a7fc266c3e32283a2b21fe12166ebdcc33a1da1 GIT binary patch literal 314932 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

&R7;REBZd0NaNVcN6Eoy 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

?@Ib4$R$ZbA6MIsF(ZEk4Ii=sfRBa)&Yo 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�^9Ew!K(j87!gFtE+SC|A#I#UVt_@yA-l7(**V4qD^4ptMm z6GaRn1&jJ%az?1}^NJ_fR#63mp@PL8qZJ-fl9^Ug znbf4ZM++F6Mxu@f{WX?}8F6pD4Os@KQz4oDFW^U%p3?6mFk zDmt(c%0mC$KZ4KBC&x-%E}>7`DOI4mW9c3+GCu{r?Z@>w3uOD9KOicqZo zS^VviU_O4M>Cy3%4g(?ei7I31`xGlLPc@Sqd3htVfS2Z2?TUHGkZ9SHB{xmw<4rXD z(J4t%6TShX7IZ|EtGaa}O3f)oTfxYIMY!Y=To^4Wsi{qvhJ;rYc3VMgO>ueUJ)uK4 zF{72#z>h>DsiqF|ARu(&C^TS)e$tvm2{yZ?rk%J;>Imisiv{* zH^>ed>z=V+vS^)jMr(b#9-X7wl9Fl^D0z#2^zxB=>@Ehq#;m-CDDb+QYjIuJL2`LP zyvCfAQT237NV)k&Ad0d~5RMeaXJf~h76GFwo8acxP5)T~a*dxV$WIbH{7ICE%AHZk z{R-yc)el}7M=$I2f)YHTPVW;}A+y9Qnbu-u?woT@s-HYJ0{g4A(aK>Zx7+&Ao?V0_YJihBm1}_5v*=hW(-#R(Z z9yQEw`}{vYVEqidGX+pESkX{JcMO@Yh5|z4L+e9Dkhf>`NoU|Xz!9jRtF_~26=CW2 z!$V70yj#GzZ+Vf`Os-#vvy)Gmnf@1D?;ITKyKM`{wr$&5v2EM7R-6^vwr$(CZQIF; zlP|w>&OLkI`u44Q8})W||IyEUFvlEYOb<3c{M``82ToW%$z1T6i9=9C?pvh~>46y& zN0kA3mQD&G|E|Ck(0$IdZlZk^*cuBr9Ra7WLIny{ng!Kbr+a^gu~FqrK}Kec+AIaz z8IiUCfE%zGJ0i6Q1XP9NKmITYn{o-^yY(ssOY=qWIh88lZe@{&P@iXVre*A zX!B41h{epD>O|wDl_Vvo^m}Gm_qYRcl)-2eH&1B+mbULoAea11;*I7p!LiJ8noQ;@ zjRWmC>Z^pKN(F8!b;w*t7nWBMse9;&2*X8vgy^rIcx6E^p|}a zt}v1hhKeaK5EX2md!tDQvdfGcifvA)MYgjk)ha99>j^AoRcUX4^JPaMx=V8lutFRr zn5xCmPFG_RqX`kgg>eRJqlI4l{kOCR#Smi5TZ<21KNLqurcYl`w-@boMrz^~9DsWa zcGjq#og?={qmenv4rl@0v2RY@P!_nhhbn`2&fVZ|E*KcQAmh#Uwhch_|Hvjma4E2; z*EG+*^N%Djuy~akX;kiXWR05^Kt|29Kb*hE1jjgkz%_8;p)&?(kZm1HzrvOKb9-F_ zJ@^;t>D9pS{DQV1A;+GHmXsWX_SrE;FRiFd_gU|DNK)aoTU9zX8Ox1-Kh^Hht?0L5 zn$O@Mh`BSIyMO}R6>d{M6ezRFD_9RInRF>(#nI1dPF?aip>}1?mB|Z&4M$JqTX60avDBVS~k>R>TVgmLIqYT%P=n!T6FdK9gp z>ecKN^Ca$$Z-$nS0|>5EA+Okin5HH27$aXXP<+mioIfi(XxA31mwy=|>JI+&mX*2`JMt$DM+wEn)~u`(s)n`G)06 zk&2}$RN>D)HzAPW-(z@U&?F`UU%ls~K=b{aqr!G|2zY+e%d6>4A3d+tuOFxx{OaO{ zV#GZc(qRvySA4a2*$_X+f#;kSZ2&Y9#zF8&7+Cg(nc5t}#3Noj@PSLz5H~aWNKLm8 zVn1$1HA%eh!W31+6Rgq&`TK@J69aT^fUg zYywm7K^-4QnPN~6*eqe$okP*ZAX^t$UkC@qGXiN;pA>lf5jg2K$nV-5^KD5o3O_Lp zL%nC2wnR6tZ!}^r$rq&fzgDM;x9|LNlUwfj#r8-7dtR_+-r#umi2MGxG4IbjzTBdjBSLAVdD2jMKPKO4rG(OGE&BQM(>3qXP?=#Nzf0z+TMyVgjup>T z9bf0yUD4yk^Znj0@DhcJdC3M)e1sc+v z`#i4+gx_BhA0eORR@PH= zd^*M>cdx?uc*cYjvXm$1xhTi>cQpGAuPwMs(c!yY1co?fdgY$08LN_0a2i1%z^%nse7)b{^x=LH!WgoJVjK?|>GlU8c%`Do1OecMJ23{5aw9DpK~4}p8mbEN2J%)0 zQk;ZA)IhNZp3hN}dp75>Vw(zVR#YspLE6l%>~e!W;e zBV36f8b+WsCoO8OIW2c<$>co{w_%FxKtmL2a-NedooCfswU=c~m;SUnMnrVPWz;wK z46a_TfC=#R#=<_ zRjf#Qox9#RYGl9`Z0efog)m5}SuANfn zcLI}r)LP3%YCX0(oERw~JvV4e%rL0^hK8y)D!yACnc_CYaF*y%wRYH^TJ8kR?xI6n zU1y~#8KBejd3>9i0^{V>&gWA!xBJ92;9S2uc=)Z8z-qJY*W&7i%X{odEB;Bvet9$) z|Cgu=HymyNmT)>dFHtr;3z{k2S;x&XM>%4S9p3FUpg1e;2-&JY35eLhZr&+!8xCTx zh&i(xK+0@-Pr__w@6)h&JKro3NkG}3OkDU=m{~U4jT{!a6*g5hGk>xXNqJPr73X&) z6DOBQCHW_6_6%Fwj&pQIpd+|GB2(S(6yq9Z_j%T|>-3~fBUd02y1iemr!2Fl^Ki-Sftj^bAmW4X;)+p#Z%@UsY#TGHDkrqGK=}|)*Owkm6&HWDT+kM5U-=L| z4@Y-gr*aq-+IIeh4F6MI^r)1HcKewu;0OQ!hppEkTAe&-YD8>+&%(6`~ z%zz0BSjjLIZ6l3B8V7OmIb20kd@{U>w7J31DuPfc0u3k1(SC4ObdRtDX2f0_hFm!l z968d@WEJiqxp%cq$i~&(b7)o`$bhtiF%ht6< z@*yjnHq}~FMp@7}3n8jJ|Ke!bozqIQVq}R0)RQ_SLp_aNT?Hjg0JK2gA(1urrZsKJ zC+Z)iaL12pZYt(Xs8r#h~s9M#Eo5Be(T>Tq8vR-;sSJ)Ta<7 zX47vTxNiiTv#SJ~ zv*)y3G!$RF2i@lerblI-YV_z-y+`d;wT}(EV<@Q+o@%-th3YRz{}k!>aTu{^ zxP`jLHB!9{J!zW{ymd_`QjP;*4f)5x^^k+8^_s3|l*U%$J*mi()I|^t!=Yzq zm$v34Uj;2R4x(Uk&63l%ORGWbIv%HS6!J5XjZY-qVJ0vQB%UMkFf#2$QRJ4SwteXO z2m~<~HFM;e0RJmgPs=f4rjXO1k^!UoccpkAN0TU`7d!yTU!m7F~_2hV`Bo} zJf*9`eF?u|Wh`-(02?pJf*^Hpe=SVb}P_&1?FQ}aDXM!hP5>8h#S+iXXuxF4qqZIPP zoor~nm=mE(xkhAIo1G%Z15`qDllad08)ibO?MVsLwiFfQ0M3=T?#pZ9!>i#?vi7y7 z+Gt$?m+Goc5W|ONh-ns=4|B7{jAfme`+qu8U_<>D=)-u|85WhKOu^f27fEcugH^`SkiW6CKE@sg((dz1_ zqvgKRZS$`axPq#O^$s!A^$!tjK=b!M@Vh1qk8s^O!Bh5Mdhp3Ujj4YCCFjsO)@LxD zQ`*<_@<+;VAQ%nxu-sjOr~2Bf4Y-Tzvt|ar5o65^JDIPK7>K}8i?#dokwVEHFwv!> zencnZ=BZnSrvDDq8sMz-0B_P7%72>d@wLlpD9(BUGUe)*j`)riJ+6o_xHicB%`_PR zGlv)5Kku_XDoCkgaht>2oHj`H2gVOMO!`b ziPB->7r_%90P<_lCG?@{1MZ-?x7KjiWvKT6gtr#p_NrCr&7~xm$) z!bOs2BBc9U8Zc|MtD_wgMP8^#C}r@U0KDbrZUI=r5;SW@_%oTD%zw9Xe*DU;^}R8K zQduW5qqvW4X!Pg$CF4TBvE5=IHCam{^brW1L~Ss`m4#5;{fN3ICU zJ55r3<}W%z;~Cg|Zh+fAduvs24_En?&hdn*tN(%qY(Nyg#N)IC+TN>*k4^;NySI+G z=ubcEPm3D?1UyJc=3NlR5DAQ40)QsLB3a#JzVDO3B}URzGN_Yl4)vGl8dr#hbX6c- zMa1|?9Q^g)aekpBHx_%#3kPz4(HOL8vfFD4pi;$Mbvw@eV*m~(iN+0XMWJv5c4k0< zwXQjOWN>9wk#L^sfpb??QLFW8PM^EBd|nxm{BD-l?@WYgn(dS63on2ETZ)Is-=-S$ z_)PAo>|DWav)_RQ??L|6d1wB^L{4lmCqX1u3~7;ma4)Xn#EwuRO|5 ze5tuGoi2+9L3(N~dZ-z+Dh=IMVF&dWEppUw0AKHq$6)mj%{{~VSC&sq+S$m-#;-q6 z%M0TA)58$QHsMfcXf!lT#@B6Hmry$=Hhl~l7q_0eu5Fen7kB{>=mux|{x5e0)ZnW3Bj&YsckZM$!rSE}O@_>oeaI#GC%Msvb_sV=+xs zE6#A7j($RL*)v&k{FSFS7_JM1G;nv&d)U8*zLFIF(?+1*QyQrCS8V3h0R4SX4+}%(MF#^q!FXX z?$g|3#Hfqzc$NLzF#eOb1)$sU$Ndar*UvCg{fC+SzlO;FByT3h|7MFE6({v0ct;7E z5qDpr3Wa)E9>f?FHjJc>g1n0}52aK73mnOzzHYpJF6UT59SPk+_M>^vn%|8G(wW?B zb2{!g+3xo3>;ziv4-W$|l^J9#DR@Oei&vL63?saNByH0{A5W-ua&a8(mBk!}(;j(f zJ6LJM4dr;lHxj>;5PN%vshju6>f^B2@+VYEh~|K9hs~pNA1IctK4ycQfRsIt#%7HpitrD*w^0DOL^KxD6f4b~x@)pEdq=Su$30 z!?O!9`GOerlG1+Y{re7C&JM$TndiO-R!$jR#P*AMa{V=nrN9boTN~s59;Ng2eM1BFKH1hBwbC~_F zxSY9rY(>rkK+#tR0O>$AryZQAV2GpoYv=B2UJ5W_CBIVAXG>QaTs~JFp0%Hx#j|2t@t-c{jY-Txi zF7n{4B@!8tBi}xjYE48&_aW@a+jA$gMPnUcz$&V&i@r zLpL4%4D_6y@NLSE!oipHrUz~>15x=P2%#Hwcqj0#MezQL;fpR1ec(kFBP?VLkfZ~RG&B-a!-$VHPSa?cjpeDY2W}R?P~^N{Z6l9 z^d+SKQ;g}YF7iuDy$h%Bdzakc!w%vbz0Z}KIDs!}_lL?pt9@7k#7TjwYLck{nC2rO z+80Zeas=fb*iS{1P!Y&R6f-VqQcC5ntd=jLgQmb*t}1?h*q|$pbvQ=>lY?xK6H~h6 zR;^g2AS1X!6O&wP30u*`gc*0^BKT0x-Hj;9rluA}9#eGC);V-lhve@U zckt@WwBoc#^o@*p5skOkOzPJudO`a30jes4yakRvhe_%0=i zWZ_ud=WnQm%wSAmBX628w+n+U>Cr}-@`uf%J^s&kk(mojZONFsZmI)0Q>0Ai`&mmw z9@Y$BMT0%ydVv1Xn27fD(5T=G|jZ9{y_&_cwk8`8R zT}hBkS}#kXOi!h*^FuX}vK7o)T#b$k2P6*AE3Kkv2zlmrg&)cfKj=MmTHB06pJ5bA{g+2XM z%M~|I){Vq3;IW$WCqTyZOc4x8SsIK?;v{U=BZ|e2jOs3g5>-`_)*Q>U2;*bbU^=*L zJRwb$<3Nd`8v;Z+M1us2S2mC*oZWVi_tz(rNN9SqWXnDwySBJ>fPAjLYhhNy+Fw}U zD!Xi9YFHn*qlrRhIS9iHLc^C^-J=AE(OO1>a&{BRPfR0=!&0S?azq$AK9Qb)%y5K6 z?6%@wvm`0|Y%DUj%v}Wa_pj=aZ_dx&kc62%vl3U(bHbxyT?_y95o7Z>P@K(oc~ROv zZ(+zr2+XK#G**ubBU5w<1y?=B$#gw~GP%8n-STxe-=rP*meBHgdSvI9tr$kX7uUrr z`GrIW$r-9aDdbrTmZ>$RbUYl{r`Vo=_ zx9@sSv$DA8ceZ+sjJ58apwv5FqG9ua+PO4&tkj&2nv6$XsS_3t9-m{=s560arAQuB z4;n{3Xzbbe8Il63=+4Arv#nBFQ|015eeIJD&1Lm)DRp8t#P6!G-MzUE^(n`3g7$}M zq{H=#iYilNtct_p6|6B`rS%HkY(L{T8TzW-_%HvLI91xMWT$P=02dr$&sb#&H&gbQ z7NnD}qGqHe`szkth#zt;G@Ew5fRQ^T+FQF96RV9T*mii!+@9unX&zezEtu>9%oSEv zm|4M@w6iQV!V`EuQ z5z%ZfXQpDPZn>|rIvk0@1PA+jzy1+F<7ciaBHw?Fyox{B)jCQ42 zZXAWKnB{Uh5-*|&{$-iK<^2Zf3wRUZJG6+Vr4@@ygiCg%Tb8}O2`~A1)d~T@9;kSx z;!!4zclC1xlbj3th=7bUAG9BAQ=OHhFfLW=Mx_@Zn^SXVkrq;h+eyr0rihMqLt?P3 zg@3UubJp<{SFq2)SglL3mt?^3kW55jSjRDGb}Rj6_G4gKi*4B!0kt8@v;@ypg`%9; zy8}yLyfEbu`TDuJDvaX6#9L4w(RZl#?;((a)8$(*&vUV0$|Qugq9gN)7j=V8y=3^gx^P4osQd4wVYj7KwkY?SHs|vwWL*7sCxbuGudR<64M)?{YIE(ttoIGZ%aTC zTSzB;n%ziIORx_M?egJSCB31y;SIjGV>#d08s0uTd#a3ah8gCB47t=Va$VKx@p|@EQX|+7n)2(swd$7E>Z<&75aN0sdrEb zX$5tbNyET7+wkhj)h6Mq-k&e^^~yGWTa9j)c<2RbvYd3h8I$ADD6G)dfo`vU)A3B! zg?S=YS~IiZzWL~Y4Rt5SyTZ*8;z&X2lq~6E)8w`eocd4ainIwWi?9nIAsH8jghR-_ zurlEHRIN$&!-Fy!HbVfg3SsE+myu1_+bQemwv`KqOsfhKIS1}3|9jfR2Y5G1S2#;& zyo`})Vg?tqzV>@ifzr8~mOO47w8!88DBfS=j977FTn}JSn+g8=4{VRE-_(LUlcAdgo3x zBK4Fr;>N+v8W<>YBi24~vmrreh)x?lD4%FpV@4rXq#&bep=&H#EZ~(W-Q-3nEgGpd z#H`bl&hU7JD8zW)q2b9-6!_piJG8`uZE!l)5WC?jLmIB@0=L+1wUH&OPQN#!> zn}?v>_x^hIRNHfV0(lMM{I-rfhT;jYmNg9+b8n0q?mWwFAi<@{eTOk?$r75Ow0Bzy?YL3Pl!!2KE^`)A|S zYuO=JCdsLccW}vH2~-K+l_6&@ zJ`G%^{x2fB4Ea-EN#<>;HsEA5!nV2BDB!~Y$emd-U_%zbO;Yyu+;zkzsp=&)XQ5N$ zMZbP7{VIm`GeLR>R=}^f38T8>`-W8+=}mML0$Qwm5hwS>I6p{Wv$=t1I__c<%)_@M zmN{T9mt`Yl?>ENr+Vwk&KWWo{%TDJ{#y7>By(S^~=SGg>7KT)pdH1kx5h zG<*Hk;VpB%qVZF!pFkJXN;ej`?<*$$j5UYwrSeAaxWIp*h;=$}>9@M}~4T--9MZ2{*2l_IbfuLpi0sb=4VPAj32u1-eP6OVCT1$>>a^(YKbEv^j?RinW z5E7ZYBkJi6aCxEA3b?U|GtATz%fipK1%&GKJAIEtYgj;Rh-~x~77jlyaTrD{7V~Wo z$feL3Quzy>4Wx37Mxh&?HTC>Jfml+a9&?(H_c;BPP?{Qocyavl_8PIH`?zEo^?_eM z{1wXhXf!-9u^ODyiq*t~zJV1~x3p9`!s-Q&T_M&4)>-{aaO?CB)20NWErk#xlg~KK z2Qxg@09{LM0L)KMqq3WmO%S$I{c57+F-`SBl{y1eR6Kj-R&DA`?xNIRyeGHq%X=oF zd#n1e7oyH#cS(DDrmdSWnZLbW+|lKK;ot{nLA}T$mUzTq4^(60kAQ-IioDy=Bo_{u z^}t?|6Ufr(Ta4~0Ns+Phh`4%XnUdjY7?&pauZPC2g9zE&F;u%4ypb%l(ymSvqWwt) znKt*Wt>ApY7%r>@nGqjudqsIW^4=wB?jZd}>o|;&MC(k7u_Y&Fqd5a)skmd39&SG} zWT+$AGZm9y}QVva9j-9c{h9j@Gi`E1jqD)`BBwN)ht0lf7M)nohq( zc)`RIUyqq9qE~W<@W^sjT)hHXo~hOLo!CRaM>*0?3}>2-lVnwPWMf??ON5ds#vp(B zM9uSJ;b>yzXiS~ptIL@Q|0{E2^p2p$L7`4>>k!D6FAOZYgf~J6nxk`5po0gzsqLTZ zGp+a=>PrJWqTl1!>KFdMaI1gnZka`W=~O>%a$-Lw)s+7sFBY=1u{UtEaI&-guXq1A zhWvMi9HpwGglvZ5!v-m#zJfsHk0dOzh|pcAX#-k?!CwG4C$Cwjnrw`W_TblneFXl3 z?lG6)+L*PM-&M-&-+C2h+rQ6YR?+8P1l)F6GFx(RKd8x)?#aQ*Q5r>lVq?UvLjV$vIRc*WXt6g@eW zTk#GSui^cvVQtr5~2;^9;$yKP1=JuW11?|Wcl&r&0L}eMXVv(L^b>X3a+Fa zbz_ctI$yUO6H2qBm>D`juK1)F1;_FAvi~pu6f_Q~jcYhKfssnYOvNvr?79DOxINAZ zMiP}u`ZzOP*U)yG3F;WkX-!kWz7Mj&kZT2%1nCUk&#M$uT^T`Ki*VPh2jqO`hit;-r#O)Mz$ZSgAB>S~rw!i%A>Z^DXTZ$Usvu z*A(;vGr`llQbJCQBPbY9d&wT`6Ki_EFxW}jmI&29FYix&@XVTl|Couk;;ak8+Elv6 zI5ryXDlu#Y18b(3FN76Vc77pYU*1G%>}Optm96=U{}_pFU~TmtCJiiGY1da=93tqf zywQ?Vr@Z|!v1EO92-ONCLC6ZVB$is#ALyR%+cjG7@ zixv>M3({$)dv5wCNQdCFX@GcPa0#k7UVbyNd)!20FX-;WS+tL_Jz9|MP%R zfNt`TqLXhBagAv!ToFE^oC)7x$u(Z#sv0IiLesEuuuMaEa=RcPTgB!?uFi_l1|jv~ zi+BX+D}LkeF5>N?@S;X_iVwB@A*Tq3ULBEB0Q$;G-z{l)Azuu+v8O1uIbb-5gt0A% znl|UH?Tm7rA2t+jb}&w^;@fTQ6kv6ZH7K=>T#l+F4JnxCP^K@(7RdJo*@x*nAF-jj zz>`_Z<#ZG%(N^~aMRgECVG$4VB7?fWYY|Dl%c6i5C;!w6wHMQQ1mtp^pA;oY(eEhD zb*Q7;bb;Te2Z@tvr=J78M@G^o@U04o>l9?V&i1}UP9gB*4qTVoxt22d?ex4;7>PJz zN2nRHE_MU3NS*}XD*yY9@)gzJG3f=R+9uGyC#a?BzpB1nrVESUv!S0Nj+7DZq z%kHa{{kA24pgRXK8h1lj>XHLK4d9hW$_ISQ)@oy`Z)F4zCC?TLBOP0{|Mreur`Stm zV-lD3BH@tdaCJg)NT~|=o}FuWYZ8AmIiCL8gYPfcpK@_-A)}rqyT)RWHL34O_ktom zC!}kW_*RrD&z+6XZ;#x=j(5prV-`@Qeyca%|9io`K-^4n_*rm+VE_PV{=xLB z<&Zq5=52nMW~Z^Eiv;|D2gclh32?#NWw>98OezMmy~<5ZTJ3GPZkJ^~W{t|OOJ^Rq zg}yd6SyO)?ph-TS5Ez-vWndLMGg&pUiM}c}oJz02dT(ZP-g*YmQnsT_8kS16SxMG} zHxJOhe{Zw!`kmL=O94}o0x86IApfheo_(w`(A-yAq|y7GgxYj@hQ+hTN59E+Occe; zO?IqPw<9tWXB8KyWQTQjCK^R_a}<;?(itRI>3It-Yib&<+I1+7oPy#)jx16X3E6c+ ze<+`gC(v=?z2{=#WTBUzdgB#izLcC4sI2h&!nHCti!*a{!KPcxeS9^~3G?T)SI&Ag z9u=8tBZ#Zrb&z~Qb$mBeKr%_m)nXuj+!j@Bfv@Ox>|LZ?$-Z|W#b={b01~~?yL3|- z!5;(fQiWK*zD7H_^>I}3qlcO#dde6W7v6MS(~Oj0WH&jmKuHJ51eFO?8N6aQZGy>+%B_FK>ufsX^i~}7lb5FHb%oR+?@CvT)P9GcE=^38N zkyEa%>V6fcbl&lhD@rjYn5k(#vO$^6WEWDUHSndD@$=5dV(>%lm174sS1Y&@W?RLq z2A5=+pqvE*+-X5Fk8*mAopaCJPx#NptGOWj7&)LN+-sO zvJ^k5lHV|FPGHdQ+v;VHnf~{e-u{r6(cTd>-nmrXAv2ogsnXij#B!FJk-my+PB6IVM&kddzN*2TCboQSTCbJEiZEU4#$A4YU-1xBkY&$e)v%coK;N* zzbp5k-Vt-p0RuCGgRXJ7c;zU)SRSQWiPWYk&$>c7 zf!CwehSYYU)jqDAZ%^0_4OeMd`cd=c%{mG6q$dmW*vc)bvV)MtO#n_B4GOY>7VK!( zhk%>gw7w?nRucmIktI$_(bancpryKcckoTX59cl{?tQ;mFT39hR@gevmuQMPT{8m;N-oLa`!g#EmHJc-Y+$qV9EN zREo6@5LQb#HjVc}0=G~8asM=e@r>``ma|9Qd)4J0@Me5kzoU@_o%M8@^=z00<(f+h z;uV2MoQ9n!#n%!X&>vxPjUEc^c0lalQq5JKr^RTDygs+*g20ECaRS7;#gP-P^}wT_ zt%p%L9mZUTBAFEmgL^{{u8eg4I_(nO?9g za>-S7|H*`wzBjC1eFk0TA7au>9mv*GaQ>~crpl;nzAks-fj7uvmQeC*K=1nBNuB@H zkj__2zT1ELsVZOq0O0(GrTf2&ga1=NO0iJaK0+P&wo^B4g&B;kHTHvn9G~PLOjXYK zqoFQ}0ZBqgCKz=Lgr3SUxl5z5xSZacZrS7-!PsQkQdp7R+`qV37(rIGWV^mp{Z{q4 z=wsRQc*c3--L~1b$>=`*FzKD*dHwyF^* zdgn_wIN$AV2+)wtoEuA*NG<`wCbj%(90n^0+Oz0^sGh0is`&L>h|!|bTn5IRk>`_f z;zoG`0}rAM^K?S>L1ahfgath2^O!ep$wO73&6kGNgf+1*{T zpEDB{z8&tq0*{g?RZ+}@0h&5QVkF6a!JIP-B07Q)i#5NGilt@9lX|$u@T0kO?z{;M z+uyWdo!=&-+WH9*X;me@FS(5Iu4e|6H4et<=fmc7)%Cft=foCRBDswAMe!+pV;jUg z*kPC+UL)Ed*frwee3cG$mzS4^YWYgJ=8K_4E{^26Tw9j|d$o=54Oy1T9jhWl^E86> zfDPBCtRyE*6#B`wXjfN?C0SLI?HMX!A&uwy)c<_OKu`s?I$qhK@$@KOf!EA*VREc^ zE>-x>#CQ_lAY_xv{`P^mC;4T=nq?xw|v9Z(UGmH)G*Q*B@ZpSG39S9QIm4k zmh%W1DZkP0j*qS861Lb;60u18#F#)urwhFa*T?dOR9P(Ic4MvXU&wM|C6Qfo%8Ai2 zS9fkiRS(r<^;8+RAM91U)_tn@uDLTIbb;QdpjC}v&j-PY{f9M->q*jN@gJ1lPsE*< z16!+SLVT_sx8VRF=UG6wVPzIv>x#vKWEQt8E%)q?t)WtQAFClbyDEMa)|p{2ZGFjn zCKDU0_pEH5S#Y!N4fZs7C2Qwq)-E03e9wF6FQn|(kGpD{ZUNW>c%5TWdQL`*0Xy~w zEt?q6yT3PIc-Y}QZozFkhoUI)iv{*7TxF#^$*{0lFUK~<|enb4S*n0;}p2T(YNoVwxq^lZI#cyG6saw^v zcx$O;+pw`Mh-rDThrfQ>vvbQp8`vcOD0jvS)Ks}Y03zPZA#a9-jbhYH)S~W z$BaX^z9lOjh-7nm?VN+-;SqSw;mzEyC}Li4*sRO8g~8{N6g zL;~MqA*^jo1I?aCb-7LErh@`)B=V&-bBw?C#}fHw6XeTEm@tQ^@v23^3OLCbESG`> z+98=LqBbiVD=8PH2I0uOBz=ZO5S*)wW^X_Y(ph1wnUq?t4|&{hu2Y;7>QqC5NaZ$P z6iOv+xD|6Nz8HijG!{f^JD-F-9u{7WM%7qhH&9as!v|ZrPFcT57n({s*;)(Fu)Lp{ zg2rCKk^~%>t=uu9d^7*trG(1avI$|yrCQlpojNFk67Qp$$r-ZfM4p8sVjo&t@sbA} z$DqTn-<3GbranxSiXSa2qu1j#_*k@b6&ibq4QWmG*m;@y0VJ%!%VvSpErULeSO$I1 z$}-#U8PYN^J-vYvGh7_qQ%6Z-B2OBgsah7vM!Vl%ypYy3qKIq-A6@Ck>+>cL_bN_?gd%;v9{B$=P{GX#5=DI5a*Yc*tda6!m< zHyAtA%M7!QB^fbFII`=TkCHm0>wmENs9mO>d`sr9$aRWop{u41MR-27UHcXq*K+E@ zQZ!ynSSA4}bwvko-NRAL8$>K}lZ^{fH>fv- z`_L86Ae}k6OAw=32#3YctP)d;cP&%C1I0~qi2rl%Do%lYo~ysoiO@SteCC9dl}1r0 zF1jtg+I75Jy0C^r95!N6zVN`d(1+-$Beq+#u;zp`t5%#G#bPn3ahviTEUx>E;Jr6&6^d|`iI;4OV}~~O1wGyfzr}PG zIz+Hkiz8PTs{JzgmMHvoj2)((ZzahZ)`6Y}myEA=u>8zmyYY3L4=Lvb&Aa&XSiWrB3@7y+&V1ZfTKMX|&;0h}_~y*4x(d zVn&)InOyPw4|6Zp`IaedoG`+TeC>7@3)v~!D~mb%0`l3TU6p-Zo)uc9;pgc|9&hnU zc2QN(rUT~OfLbI=6}dTXdBCv=&m1w3s+t{r024*!#bXItmjD%e5*-@Zw+^+*5SuOZ zs(Fr`s>D)3<~20!2B!(g#ozh`3c6?G)cbsh%cm|5FYqoq9J_RWG70_ydEtPZT)}C%?zrtVqmJ-u|5sgYt*V z(FnPSkIrEfvhTPJp^;1Qw$n)NlHc!CsO@wFt8M};&gMIWrWH4or|Ex>+7e4xb$$6p_ZS0T)5PZs&#~w(FSAScmSvCTIA-5Gq&tbSA6h zZiDjb@`y)-A*+hAAN&SsDBQEFV z>8QSh7@Cyw-=2zS8ftqU2_~1#J{?^6x{2Da9aYTxgw%RDBe+XK;l_&W6Azd+Os9Be z3KUB<+!RY#Xp_}UQa0RvuC8sAE?Q8lSq6BptWFHH(VpO;x}4&iYO4B%x$0RBxQWK< z*p=c|LC^J7tUs6==%JWJ(1Sg~kr$1o`46ZhqYJf?>sF0G!?9x9QKv~I4hfGM##=WXYiiZ$G^*w%H4P7f%jlJpU@0b`NqFHT1EL$G zz;yV0kmIw=vCRqZd@2lgOi0EhTeAK7<#h5xM&n_Ae^^<$0dTFWAdJGcD7059Fi;wx zwJvMT5|j`EGC@T}-Jo(+-ZYr~6*Dv%|97@QC&ZxZdc1n=0e6GB=!QcuUFjVjGd{+8 zeZz<%nJzdv1Ln@Vg%-onWdjlXE0@$bpydrkqp}0-hP|yZzy&4Jv*r?UK-GJ4EzXNz zyZyfD^%At|hJA2!0MKHfr(TF(7Cj@+hXB9=bsg6AtZ!~5EK$|3PqW8w+- z1|C)=JZW6cg5(YcyNKBY_%ILS)tla$jBBzKRAx}v>Y zBkamq4?9;ii*?8_ApC5n9gH`p^H`3h{1x56@iz|mKz~`_NmX|3Xz7PLZ=A2wqf{@A>j+-DW0u@ftON_f1id_%&Bs#@G6HzLp zq#1crEedH!3F$x#!t$4YYi9dT#@lFJ{&(Rg(^dVU#1j37jQ1bbq_l;Tv&oN-;D6`6 zE^-~R1N;b?uw<^2LWPlu@PEk2Ezv{$m6It#=k+c@ttYb@e-D3)_JQ9jg#HqPfQ+Mc zRV_$c+nT9)h6h;TkaI}ikBmKQ??$c@RM$zivBRpt6Y06vKN7K7ea*Li%23T>le2uF zah>gmj;Np|gx_wmZP!h;cbfeS>2ir4VqX@fzDbF3pv>UXgopsvP+)b^jo7)k2j7qy zx`-7@6|1(+G#jW7XGc!{9{MncK<~-fy3wruNaRl?P>n~3jt%s)k30*dtVc9M3}Axy z_D`_;*W~<%AZm{u9w#-qFt4#K_se@c-Do{d%%n;ROQ&69U6?1(S6J zqZ0-D>!1G-zj%lw3T6sB#UKhsw-SE1=pR4%(P`)kW=p`w(bGu5xkSrMo)jlQ0FckY zNJ*|jPhCe77bn0~!9w34%vVLh$lk==L!pH)0VxkG9_J%#sN3G{tBAIWWe_MYE~?m+2`JtNqS~})||s14IbTp z80mklIsc=-`!87f|B%_E{!y>;qws7bg9$dGq8ti=($1ohpdbbkh0prS4q@_drRy(6IkB%Cs!quQmQo2p$X4_NmLDd+(!VClrgxkEm`Ax(OmL2%~v@<`k1NUu! zQRuPu2*V6Mgzb^jv*07|QiJumg#I0cJ|SqBEc4dTUpvQkT1}wn2@}UUf&f$JZxK;7 zKG$vk`?XsnIon_9a2fBnOj`{$F_SqMgE_uU1`Ex#yFbkt+ku4fDaIDB#=~YK6`ezI z0_X_s8EdCjTx0vy%dwxvVfWdp#}+e$8fWVtnZ~gE^22WQp*j{1sAI}U{%oeRq@X^A zbzxr}H<1+>20!Z-2NQia5B6N2Ufi6HZWQ_7nc-R}?ncd*F)NUnvJgTT(v;QAk?-*WLyKI4`W81ck zj?uAg+qP|WY}@vVZCf3i9ix+*-h1DDzH{$+o;822AN9^rHR~;mQ5Wh0$9ceJO(++$ zWGjKG=yvP~FvO6a!MG2~R|~Ds+N3{CjWEHqlZ$p#LjF({pdYKsjM<#ctInj(w44J+ zeGS1zBhN}&!nLY&!n{%{JC6w=koX?|)^o3LHFkq}q}8ml5QGvWS^*bvNikLVCBLF` zth_Dah}+5Q1e?9d=vZ?uA6uGv%(0R5z0J7)yJZ+=8yIz02hZA$V-(V;7&7G0euLPz zjBG;TnH~;J<^PjSM&R*A74yhLIt0cu1Gc ze4Dx!bRZ!l^<(Bu(qLP_pOYvK5$2!}{o5!tlGE~Ur8;hJIt zAxzZ6F{Lvp-%hX2=n0}JcT8$Re7=Tq$FDqBE7|RvY z1hIrR&7Ck(9_#8cqSBs5PRyP{e}=l*2uh}`?7N1&F^{9jLtPz&=bOR_Av67%bqTR^ z4dzeC@#>FD@Cl8as|$S($o%dGVak0|%$=99XMd_#>+sft&At2K-!!2#4y(BV^Czb* zE*^##Yc)EY%W+icNukjt&roQDyu}$+Ub(*72m)Yio}m@GXFRRqM(NqdQ1*udI#_7t zAVj$=Rz_l`lU(fE3-TtB-XRrZkSBr3_o*`Mg%q-%8n04wsiM@HKuyFZVW?O`lOH&% zEINv5`AUV5mh$0c3o-9N#|8VL>w%OGt|=G%l+ zcdXOucU;RP2$9?5ei1aAx`kEcRgp5)@0gH|S+$Upg{H~LDx!O%Bp+7~=)?X8 z0RLLlq^_oM_hr%Gmqlp*^``#-@P8YlY!qksJUs*i`ajmZfCSU}eY_iBf)(nY1c5-n zze6Z~VtoXaf9j(nQhpd480+sC&VHi;K7@jZ4S_AdWyZ%r$F)8}OmXC7G%!Gk@^45C z58W*UvFY5CV8+J4XltS7a65Ij)^>C+2z8qy_z5MaQ+kF|OVf_kHs};8YP+4D-d8U6 zb{RsksvgSYltW)YZ`|n=PPn)`- z#U}G-({aD}M~5!4M{6p1#FfJqn+$`u-NTffQgtmoJg@qb-t>^CRz64&+dod}ubXD3 z8+^cgx#`gVO1%DaO8;6Xbg}*4iIl(Z-+0JFCxcJ4o#4CFrKGe>l=9CZ3m~3Pc8b zfkXS8h-ik2HE%o7buP_d2bPa#g6y$8id>s2go_I_ha*!Ztuaky({A0ajT(%|XzJNq4ybC;mH98*uIsq6>vI<=+PDGEYOY)X%RXy9&bietl|wC+wpv@C zFIQ8>%vjVRdRKq&kGX$&e9W}p^#kO1g@mJCq{!LkwM?ATwo~S~$wfaY7W7W}zy0XzsKRVeBu7{%;z*qsO%My2R+6qbD(6zm zV8y8Nz~07Xbnlovbj-=WlMbqst|)Ya%_+XKPDHnFo_3OkzST}Vc8D2Ez3~nT;#wK+ zls%Sm>7Lw~kkK53k=7NzKEY)^m8?7Pgn!ezwjz6>XbkUzBUUTiTsF36X*v`EXGnQT zVD1jAWqqbjtUa=V?N+6%WoZ-HmO8AL9!;Gv59y;3X;I~D8{b(XpRSqnsP3~Nx7l^! zs%0l#10ZybFWv?%TnE+qSvE4=Mz|W@}s7;X_*a-li80;k;ey z6kXo%_WEdJ1K{3hv03eGu~IR^QOYy&yVq~x#Fv3(b>l8qH`J$68p<#xz7$58el+JX zV$t}crRds|-GI{Nno&N^o9JM8dqh`$5SQ&}=!$&|{0Ag^ZXny03lFc3`(n_)@n^(F zU!9-64(-)yxh=)I7myWqdh|!EaT5Xt^GoUwGLspYl0}&>cVY|qT9{U;>mahLnyGzl z_B#3&POHeOu^nqSZ${+Urq*JX4-=%yLOnkS`Bb?yu|a8un%KhQckWAT6{S&C@DRmV zS|*h+p1luc=UKiaX*~0knBp@>v3O;)QvHmCmTahHMAM;3qRH{F-&CcrsJPj96+LlO zr6q+Bmr#Sne+hJ`yp&tbQTo=UYnML&Z=Tr9vq= zmHlyJ4U7e{m%*ZUT?-MMUcvdf?aiX3vz^X%YtFTm?7U3I649Ntkt)mT_~B`^%~e2b z`@}VM84)B-NwkVC^P|Q4^?hP}-@%IzTW={!K>8R(M#9W6_HrCJpVz3IbD>GlVd&sY zp!D)W>hUnpBT)KkTXC!xYRuQzoOag?^|ubX?zh)dS01jUmbaE6@Jkhom6E-sn1>-k zSqNE3GGZqZe+SBB)GgIwaONP_ehI0L3+l6iu_{mvwpE0%5)4j~SrSPAICFe5=jMVS zHyQ1_YyVQ!Jl{o8L6>aK4-8as;CPb zym+a#B!B_U9+|d%nyJ!oq7(;-%PRyJurY@fmSk7 z>FuF)Kw8T?e+`=t!H4j^<3B~iGQ4-3PvB&j0rjOXbZ=5P+b&F zVMCY*!@}0=ouJ5SK~H|FJrf0OM=riTaa1CY@vRK;_;m!(z&%=&QdY|epy3g?YZTR+ zU%z$LfWt^N-$&KV&>@+7VXV@61ux+qXaHzlK|*>>{-XQD5-JF^XJn=}$<5nB?(#n`>C<(EXCGXJ4kFL>Y8< zoVzFX05AAa{KEudy=>$Oy8i0#P~9s9{Q3M~1%@7i!QM$%0$i+*n)hb+Rnxgm&r0tW z&owM5visKZ_fU@=SAnrye#3ijNny+Df99k&q2L1$xXj&|O>WIjW!&q>_GWJXp!4_U zww`?N&=J)GGXBnHaQwq_u0ZWXBaap6`x5D>`K?fc{-Ia}rcU$*YZ8p7L_(oaz+wF1 zk9=#t<$|}H9fscu**{~z=7o)yUJRlLcHh#EdJs@!$@IR-AJ$I^Q9xCT(eX`F(7qD! zTFuRzcqL-CA(ABYhpG&H6UWSMdS(g;xHFs`@0U&}Qf(On(@o^CgtG^Wk*u$-cI6_8 z)77zV+>j~J2=TI|Sx*Ac`9Qjv8OrRhl5v$)pAePm59}Z1$xyB;)NhiWv3jh{9eh`m zv3(As_0{e)f)_BYhW1W+X;?xoWv#pJ23{iA1egEQus3y>dhX z$h?%Is9luP1+EJrNB6Zzlg~_;4-+1KBKL+uvpbj*r5H;8XnQh=^aVlN1a)-Jty+zO zhuignxcn{hpo9M|=~dL$W@BR&-v}UYR({$1nmJ_=OgwG=v0D>qn zC|h#xS_~!O=0#Z*vR*v+y2WVFQ4?P3s#8>1-?tKJ)*O0s&SB>bP9*$T!u2`uByzF@n2a** z0gkRw=8E&U$vvpkw?l50E)wzpHTW>WRKB;HqYs!S-pjK_13RuKtOZ@=_zHQiTR1#& zdw%e76`IPMkMJggGX38ZLUY4vhSr|(a76~X_0k-V{?LW_=F~Bk-x{R}j*lOb`z_Dn ztYDK^YWt=D>^)E_PqB6$GKE#x^V@*Se0(RmlBIbAOVSdOgF?%WblbjXRbuM=iLoSb z1S6ryBF{qHN7^g=31pOi=ktqhEVo7?fJ44zS#If z#d(So-A=31#Cxir6V&q1HX0lW#q+clA=2oA(Q$@~hsd7N#`hMlu&ZUr=k)+!yY_Jm z-vsZFD&n|OA~}2lAKBB&b(x<(5R$2nV$4RLc<4C9K5`n1g0POhk;tczIeqcJZ|zcQ zq{Zw2RYo1f5zLtKU?`B$g+isw0*kB2sr}fV8E_{%%gD5k33oo_tT@3crZTfQD^aL` zg(xwhLY$tzH(=&Izxa)=|+b(>y5yjOYucI88+)hm+q@V!d$fwC&GSc9iO+pu^o zdth;CDXo~3PP6%u=Y@n$^BH$aWM>Ly(fBmM67FZOH%|lVq$1r<=fg*aA?jG&l-4mF zxPS?%+!8Pi%~dw(Z}tN=$CQf;_9HJY>q&kaqaQfdb}YQcLIoi^<_RdLoz7UY5Tnq4bI;x^a?tlJ24RMB#;-#3%SRgax$y1mwa%q^B49 zx$Q4}y!)vK+(t?sN;v1e`3eE)2baJ~j4b=(>Op)4Wk)d*K)omqQcEc62l_{^1Uvcz zlVtD*ea`l9OoFh|sR|d|8M62vAYKVQkkqieh%a_;y{GxL;&JK|Ua7+NqPud+YRuxw z<6qoCH4>($9r4=YZz^ruxv9=*?dLQnIQOWJY+Pc$?pOa{m||};UD4_&pm-cPtfQ1` zAe)cP&liSc8$UD{XfjAmEG1~Xl2&7uR2rKUYib~Rl!$KJ1q(oLL#C+?y1!s)qN!&W zv$-YzW<1TiN}BVcz!?^?$)|G1AGk0u-XpnrEUa61Q1(X=SV~;=gZ01XaJ++B5AX(j zOGgL01o9?23rRldx@YaALXS8^jhSP)r=wH{Ubh?AGyLHliA7fng%pk`@&3B30<$m3=o2c3 zAIo*)H}~J9=ONuxH2zWWBYCMjTcPKUMU`Ts+;YQG}X}9>*XNl)tJpk&Z|&zNPpN( z`N4rZp_Sf2k98pqy1#YX1>Sl1ug~-yvfX&#O-hp^%K*6rZ@1-nD%win@YP~2`CumSKRG@zEQ6p^# zQQ@BcdcA?(o&c#|#n8j0SgG^U^gsHR9ml8o-*ORU_O{Qog_LDJfj8r$%*vL_K)r$Q zYoVjYPr@Lv)!GJh^+9Lm;KWyOxToi?az-`Q7qCP{Vhbo%HXSH)O26z-zj*6IvtwE3cc1kSD&_AIV8Gb081U1^-7Gbj7W~QA7sueD}q2k?* zl3Gm1Zv|a-_nhOx-LvKt`^;k-Q!Ov-dBvJ4zlmCW)<5|!6Ow)Q-gxl?m$g0*kPv@B zUYX~?olKqaz}18{M^ui^H0BNARvfe|Pu-QpT9pM@onnh_jHk|n!_SfH3S@W2eRt}b zw+A`60L>-HFL*`k|4`THM25Vnm~Y0WyOB$(ae>TUIq}QW0;w35Ln^}NK^M;32Bs;~ z>*M)@Q7Ig{0(`iCqTm{;iaP;c#gu~?A(_c3%X_^XASn;2HxWd$ zv~g#sIVg3isViFP!C5`zPSSd`K2K)fjLM}@C`3i+!H@7l6*4VAA4_B%Rcg7!`Z1Ka zSd*^{0bd{-Jx?SpcYF_9CZF*W5M=yYGuQ{m)wjIp_1EV=%Hw}KN6z*{SO{O$WZ186 zHR*o~dM55)O~Jp#WT$_L`UsmC**O~gcX`YwVas+w05N3dXvEbfv5Cw^Nizc#ngbp& zppB*?IFOo1gs@rV8m|#fR!K{9qgTk`8!~D#48DJu;H0gpZFs@>yt|p}(FRN7zk5bG zyAg0O04YX?nLgwzsYbKJx87kP9_HQjle8PG3Ns3xDa>VveV*8c?Q}@`=ThOUCu8s2 zK6fmIcYlKgt*m)Yld}87r>uOwaKn%9J(!LT$gmWs8hE4zjGS=7q&|36#smdP`PClp zPQ&}Gl6%VE^zImuex!u^q?ZqB3=qcj7xI{z)2TWPE_gF98A3Lju69!;=A)B)WR1!5 zi*ue*d1bR3hwu!KC+tfL--hS!x`6NR7|mva-j=b)D7JI%tvNf(q}RE-KRP5t#Sw^F zqJO$PDKqP|opjXgwzUPZVaQl_nCnjs8ewRyny$8ch&wyone|92(Tl4Y#ZxYk%UHa0 z6uS*DA+TJ`-_`Y=6whuJlX^;kSL9dk=8AvSVKBi4+Xx7bl_UIfUCA7gnFIDGFmW3p)5aYq3T#OhHOc@ z|M^Ru)J`-?#k@TVPv_UdgNg>f-o+HETGU?3xaB{`tpCt7XO%Kr;c zKa89$T>n+J`(KP&*-A2YU!d~A0XSrEkkTnE2;^JX6S=Hs_;UnM=SND42Y|$kugRng z4>gndfqozzOTt0I+aHS&ZEK=e$P1HNdziW&O^r-P|DCzP6Cik-V5}<_*NU%ZmON3m zM^MFbtFzhZ4uAkIEq3rH#!mL5ri61 z$>X>OcxUTojhmn3ye?M3_s5^-w#AoDw=1e0!U*(wV}UYr-EVQEEULqtH@|4&nU|` z$ul#=1CT$?8U|rtkjkrB;QoS}&e|nSxKhvS8kOtap$lD;!ip#gGqCE33~pab(|TjZ=olZ4(4#+67B;t5y$}8!K(fs@xaVT)Rpb>2kd_}!#PH&$XVGSh znl%nS%9XZKCw4JEXBi;Td|mC|w@T;sFokPnuH9HATzLuGE@pQ(lLcA3`^Ut>U+~!9 zxDKCvfd}p@8WH|q;Q3qaRWfmQvHy3MD@5_%pxJM8Wg;iDp<*ox@dbJj5bm;vIx7Z) zq9PQQLL8|EfMKlQRIfDoMZt&@-hwjgn{Th8W_!2u16#3F@ z+cs9QGfAN!vB{yonD9i22gOES{s`)v8y_82-;GY6DDoI-lU!him|-C1WL0hd85Zn8 z60)s!OiRNd-yVAqwfd-q*ZOdv?2Sa^J=vIbx@C8bC;+KfQoiUFG0L32Rwc%lL8NJp za<e@>;G_RuxkQ7T38ujTonq`Z?yKfet0yy;A+cL$8f8~!$W2Hs+JF8JqPM>|(I2S{ zN&X5j7+(tNcMI`dX)m+E(Ls~KEc^shOg?Hs6<6ccs}Y%LF|IqcWpiiN zv{~L9He$cIck)hCbYVbkQ{9S!R7_wD|$esfsRR|{Iq#&TfX}WD3%<6 z8)zWMm3Oho0TrF*fIN_0=w9c~&$)EfO^Z;u0KH;)DZqMHp1((9PdXGKhO>1CbXOMm z_c@t0Wf4?|m~tC^SKfI69Pu2o2&^1WR`q`1u?&MG&BmcqV(%++^Wi+Z=hqd zgk>V@+Fth|88*;dZ|w3gm94#&!vhwt;LJ6yYc4u4L;LoAHrgfTunOGC9?HlweRd*A zw}utA<>+Tt5;OF=m)$v0$ug1QJ1>}?h*$9Kaaeno=>fJ#=oN3e410S#;htNx2oD|#B5)N)FwjB|La zY=mDfdMOWj4}O#!Mq;gox#_GPPw>*TVUi0t(Ho?t(lO(=^|c}`;CV{@bz`MLY1oe> z1um{TZt$G6Xz&$Vynfq4giO{FreF`^&F`Z_`)TNo;Oq_)qzO#8P@Yc)=w!o34*=}O zF^**GTQyV1@ci6ednezQx7xG5Z`q;ZOp&dIXHd(?Z37F;GZ-F?y`r0Bn_a4bshDhG zKVdz-qq7dR^Wdx`Ra{0ydu8xnZSJE?GJ+_oLnRF!~_B>4jKyayhyILAy8_i+#C_+=wV?zgUFe zdM^>@sC-Mg;#2ErhrM}d6XO!;Z<`q33Ai?CB<5CNwYDUBC8ktkF{wA!>h;ajyNxawdQ?5>aw%2YU&CIXTSt?eV^8Wq?Zui`p$6F$igK3E!buzQX+RLCKJXA{4!bGYq1On5F09pGDdP}Q z>=<4gRl-}bRp2X25o^{|HjCYM$i1oMGnvF_hjCYaURNhI&HHv5nCI^M4|RsW7}Y+D=GHPH_B>AR zcHQ-N!uD$N{o`$)!XJxAWj4qgHiRP*S}^TInEh(>peT?ksfZnKAUaTXGr6zo{%Eg_ z;vzyX8e1=e1_ zE=sJy64vWo$au|%DnojQ3PW?Fa(>lXj?y6mTzT_TQxTO$bpZkb*08K=O&WRa`B8$> z6ZR%D!(&A!l{r4FkYg*Oao!7ZbLcU&O_Ws>%zBfsXHfx$1ey?L>~4J|^N~ulfRT7^ z@#7@RB(~c@4Hz0bQ;i{#T)5pf6bE|QezI9VqqnWjQSM#Eaa`-{hz z_v7yf6kfNH$I11Ky3CLE?nk=I$g?T(R!i7KjJ_Nxu-_Ay#jSHfGof=r`D^hQL_G+9 zj3Fp1NTdnksAQXZ9SP=K!e>pHHw6#Wn4a+P^emWyQP)tpMqT4&1o+zdfN@DjSxuV1 zLk?l}J~gz-(iNo^W+1*eTmD$!w-o@fyH+02+iGlwc>@k1YPgT%9^h`YxPpuNjW!95g zq?4DOODr^lQ4=-um_m|B>15_rf>YB|P1nby(>xZM%F4nC2^%6L<9(nC1hw>$DbeM> z(bcqFNA7jgL>BD$U3I2QFRUch>RkgS+CSH3+7kzA`CK7;9c5@nn%n5ZE!uQP;C{H< zchT}84@z#TPp^r&c+-Xh@zHOvpRUsU!ZB&n2$ef&BMTpYpRQ&G(1{Ojlb^-lP|#F0}PXF!=C5I}DUAHnMQ{Xu^41c!mR3!6KAiyrgT z4iz(Tr}Yow!bczu!~uD(@jJ3FKthq0M(NfKCWuHweFG^dpE;wj#XX<(}=FG|a70q_3 z4sXZFkS7l|;&8d80VYe_DJ#lQy5vWL{x2+NShZK_bH*_T*Rnb&D!#I=EnwUNMgl7ESyHMC5qjsT{b48 zmpUTF4|#7dB^IVjJUm_$`lWreNO_CSY0$vORYw@i9v1z4J$f=*F; z`XFO*LjT0yklyGoYFP}Aj&^qh1VTfqu&+s)WR%!U6Bx z`T=o44rtqFjBv&_9&Lb7a+a>6WC1HLO5hEaQ`ebx$c(!Fxy_kFF&?1>so^s^ZajIJ zM3h#4VYmeMSk!P@)=W;%smF4Qvn@sw<_q`{T}d-Fg3W&;pko{j}C7GTTPk3c|k1|!vcnx@x!>Fg18Wf}dixDiibHbJ5_AYTNGuD9F{0^X zAZx+vCh-rNfZ}aW9IoKX5lJacyVi>u!Ty<~NI&QNN(T>5)NQnggZNl^H_WEx5Dk|2 z^u^5OhwHimRs@rBL-Nuo^N*qUYlW!I^|VZ$g-8>pEdkwZ_*2-mkLZD}n*73n2UDA% zx9(rK_@)$dv(FvI_KuCsnE0~6woUU`=uo$M(iI*R`taGR(-5+&*#U2fMRQZ`O5#fK z;^|B(+}UB9{rhD~?wcyI>xSCmKo4SfQHk0)(e#vk5$wUC%Z1mSwo~=~{J^TeZ!bmC zouQ`B9Jr?SB{-CF4%DYyw8ma-v|CfFR`N2OzGKDWZCV`R)35;Vg3J!fx9BNUA7UP0 zsKeqJWDTUpmkLpIEY^ZPvOpB-NPtKq5Coe^8N+TfJ(Gjbk@Px(DW_7n`Wv^vpXXDJ zI^m776(LpVyTg9iA0VBexTD=r_I+s^J7%c{V$m9c*9Qz6Tr{RX{FY_}xXUT0`633; z4bl;a*(dgTN)Bp^Fv&5@xpBSL#s88KyRbfTi$XT9G_1EtSVencDFUvCaAW~oezY$Vfv{d*c#_iSo$foXSSYiU;$GV$ejje=9g3d(+ zo{TeQ0AsuQkd8JKk{!xx)^wkx_-n4}Gw{NwV$RohHVI1=L$fNMG6 znFg>>qP zCLIpel^e6k5|7hMauPH~G)7_555is?(e~X&`i~!bfg?Gx-mFka~yd*`=KuBKrrS4D2@<+JBS@X>*Keh9YE9k)Slj= zN#j*3Kv$bf`63wMQuIkvdBhgBr?c_&VM3!$)52IVG~ubHl(V5SCz6$j?$_00X#sC%xqSX7NAtBHzj9lz(u-l#z~PBfwT#=q#S96~ z5fKU7M#9AiUTS1+u-+3Z3^!##x)2i510!Edk0n)^L4HM@>e#xR&jZ%Zw?M(>G6YF? zUVY-#X}p_}&f7AILHjz-RM>IAHG)p2_Hse3EEEX=p*hTdVYE?g!iFGw^Kh1si=2rhY&Rz>*gxQ)g z%klZ;mh<$sIm0sZ=X$L4Th#~*)MliYW*ycObUVWjN6FDYg4^^5--xcoce35(M*s(( zTMnHR-$0&D+-u+YNpY_em)=mGf%qs7gt+)F9}=k$^;Q<0yUyNT2EmTuYbeop+(img3= z4voFzqCcTLZ7bVPh^0VwN0wu=^Du`wpa9sNeI*U0F5cX+W_!=FxWASVbGdfbx(_YP z33x5>Sy);!+qW9={5GFxolFHdTH0Usq6>fE%*}R=xmx=*hMJs;f8_kZHr&{hkQ#Vb z*rlixSUK=p*->lvG!Oj zcyTW?U8u^k5HB8pQOe;o!gK55X4a_Ofp`LUjliGESy!$n(Xhx@b8dKqb(wQjup!&= zw@~WfW|=sTvG`%7a?DNVr1-_F;--QS#xwI^K5$lfM*40O>9^W+CqiA?C;xW2oRoam zu7ktXe6sN}8K;z0&$G~~W2R5aF_Ss%9GcUTZ2?xgw&>gM(%M09$58E*E<4dK;-ER% zQrga6l<~~SZ?HQ74wVLS@f+d znz$UZStMeT5@t`58d_Y#cFOk-wJ!{x3vT1mxm)kS5GzTx+gbzer3G!89jOWj$T zn8KWSddvHl`lHO3n6AuLR+jQusew)t9|+sd8cB|qwjs81`OFIPs!|hjugYP!MYg{uV<__KPiNqDJxSZ>~VFhT@&f9D*CN;jMzy z#!#E3Ao_FK^Fclkp;7GB&`WUe`lVjJ3wC>;S|)q>(damhPO8{ztY^LkY;-$pobfB1 zjYiHxKzY{rbBj{b!B%7R@}{{h-MUAz$Q1JHN77#jW^mj#aNl5pk=v|*+?`Tz-_YDf zWxD!>UZT$BUWS9`R7c!gY5;dUuc3$PS(}Eucu&EbqW5dM-7XFhHa7GhhxhefyPM8{ zUwdxYs=8zbaMA|ry$VEbgfr*7!JoVzgv=l2JKuS%cH{~!bK%~>{Mc^TdE{!k01}E8 zAbx7&rGZ7jXof=bo@I+SJEJGv_4&8c)3OTj*DzGyH+?HsTga2Cp9I%h9SQE|Ka_Dl z8E@p?CwhBs2?XJ8v5p#L2O?h+1B*3XKDQ$ZD|nrS*LW>4yeAYwuoSeM+o-oYNyxCb zf-#0Lt@MWNhZNGl6`Q-Y=s$-}N6+*W{G#P+&|)(W4=0fD`18|Rz-)3sq6@Wh zD`KBDA{`JTrgHa0D76vv`975K%|&@zeKqV@=43abK1@7z;FsVImeW!ITD zp%K!r9G_gEBziJR7O8{Gg5v!Q3)qex!>CST->akGB(@Y;BU7^9bSs5l?^cf*2~{X5X5M+t1STMBKDJ3}b$B3Gg3w;<4E5e%LZ}jFM@`Q=H0J_*!1glzWgUN}e1ou>sq-KRX zvYf&A1=Wx%f&^8mn5YC1^N35bv46?BYjj~7Nk%vr3k7VnrMkg*NzF=`$M+Z)1TR*_ zSw*c*SIr>CCi;OlULicE2YZ<^M+EzCn;=cRPzflMWLBgaT(!h; zA9S^>$o$fgQK|rT&o}eAiNRkCxtXY1vy+k5CiTj98)YZ@JCJP4i`273>O;;!wP)vpC;+GKXW9$FhO= z$aBSsPW%Rfd4zhq7gn{js;$CxGx4lICYB?T)9t5>7ZTZXM3fx6iY90*nXSy|mT5ec zqg<5WmP7Tsl$UXW9*Ao|vJi_bP1wD1StmHo_3_VLsf2i^`5eNtiAP?2(p+vSl`75x zSkMr%%9RoLj|CB6Lw$-bk#(D2`-a-q=<+{rBil^Term&MYk}3!S>t4Q+lJa>HA8Hi zd$3N2q}QA}$Ph(?BZS=irfe5U4gS3*Anc5%dA&?3S5P1g%ohpG8DPXwvwjV=i51aF z1>7!vV6-Ca%d%Y%cipcgbN~k(=9-mhbfLq>w?M7030YDPlSC97Dp98C^&4FR5Oh3e zPwAQ_WdGx}p74+?*_e7dTlGot_Kl-aR^j$-ZI7UAVQ<1wuHwz@^B<|l-|aQINm@rYs zCSOiV$k<{3K}Y|{({GUvhgS%q?+6iDQ^%EZKN}BMoL?09YSai;8s(U$PG)9KeHb%Dj zBD5*;+&@`=6;&2%S0DOh*esti$X(q*@bwZf995dMNU+Ogk`8oxyru=NZ$!Jx;IlU# z@|?Dvz-L0=j+A%G@fA%ZnVSlBrmv`Mq+OP?xjcxbXsSF?5RrZ=xy>s#@S3O7oD^-} z{Q~!7sfgQ}?nsCA9X-!ZsaW@*er~P2Q!1}iouhIztJ)}Y`>lNG9JDn&zUEZOR-GZ7 z*{Viso=i~0Yg7F(0u^QSooje1dlI3-b6K^8?b_G+>{v88)>%Eo#IluTaM68t#$fIx z4=3i%-kcB$`BRC#);8J2C`YDPlkQ1IXWp?Ko6fMl72`s_nx~?K?WJ5^h899waM(58 zjyvJ8nu5CEVg91n;!s1w5c)t2c9#`hzpl8sV^u1luwyY9o!U<3f!1N&{Zfmj^))Z@ zk8^Kwh=z$uE2F$_*62aJps@GHi~jEcx!-uFnMvhD-^)v@+)9C=LsV?K>}Kwbs>qZg zI%|BnRXDA7t=9(xYIb+Nk zw>5uPFO#~5<8jbqKP2r(eRQ6H+5AB=;1CxB>?PRy&5A?$KyM^VdUUvjkFEX6UT0Z0 z_dWeNEfT-_(`)=u0S&cRm$XI@(L4DJ=aJZy+`ph8&A*G6Q~Q!X-= zd0*-lciRg)s#i6yLoshV(N^?oD}&0HLk?cOU@5EEVfIrxI%P{Q(B>!V=uv@6gsbTBO< zzJ5=A*mSeWb!B=h5BaHBCFlaMl#r$ZNa?u7`XIz@?q5^a#@Ej8nKtNJ)-+L1{l%y8+k$ zZD7|If4>LnA#hb3`^FHpfqhxZDFK3Yfipwpz1||DtUw*r%yDB{V)@}i>Z5W-ODpJU zKbIoraCGMN79y4AtZC83L)G|?b4kz=sUviW^Dyu4K9mJqfekzG$xkx+6(2R3o9g56 zMIb#k+rgOvGJfDNrvNF*e0=V^r`vf zA8vG#M+5;3P?(u`7=ft{9E5y0%Izh)39^LW&zuGs(jspBGrim+Fj^L%?Dl(E@8vu4}e}kuzK1P1e+OP`xY9obui5-f2Cyq`5^ZsxT&~lxP7wr(V&=4eUBI~7`0}19F zMF7o(+0km_)CY1X%=m+gf%^}M_YO`ncZ~f1r?u+hjuq)Ds8~=`Y=9sl z9Yhf<5dua-f(fCBEuyICf*nQIin4Y^bQKFLxULQCy&_lu``YVwPC`N^cWwgyf1W1` zy59HnGiPSb%nb}Yk@DRAk9gaqlJ&no9XLiTc^ud${Zm`xxDjpZzj?ZC?Vf?t-LL-_ zeX!-CTW)+y(+2ukITnMzES%RYW4PV%FLgOX4|YgvTXKW*Z1(Z@_ZBCuE}E*Jm$1+) ziJQEs-sRi7qixUI#}%a|cFOKKb6ou>(~+M`3&%c=PI+6}=~eu|_lY^XTeqAzE0c3T zlsWVd`(P8ZC#|nt@8vc}(848Z-{upkyFwG{rS{!uR>1A|I%a3EUZnH+ccXedE85m> z;-ODb2Ho2Re(!MJYxmzS#}k?c*{^$hckYK}k`4)1y>A^Q#U zwvBTRn(P)dAb-$KXFey#a@I#T+Yp1juZv>i3tTeJxr$mGT^wV-dnYeDIw--cf%IU9 zVw;eEJvXjj;u!Gqa%hOm(E9w}4LiMUzH<7J1?jgvx4~;fM8#3FcAOd>8hQHU@$bjB z1P#jH5p9=ee(Gz@{i3cv=W<=T?VQ}MJd(R^x_!&C0p+Q063-l3(C}EjQQ{mIL5s83 z{u0W>&HL9f&puPUD|p59kX;@dhdkd) z%Zx79jl-NT{qC32G+@hm)8w8D_FvlJ?qgJx+|#*>VerwMAxkgaH4C`fv1e)6-yb%_ zw>BGc=9bMmy>DYh=@;F9OBuJI)VEVuOE`q^V&#m7oCL4HN6o*#5vKRK)$KrW5PyD{ zmv4f5jp^HLW(&CoQtY#8zPGwD?AAD=GGb9xBtckk$8_IXC8&+*Q8_jmI4w3#+eu=#RyZSK&=Wr2nV0v7q4nCR`| z@Y#3o6ia8Qxo0>WeP!!^IOL4&{$Bd&xto6bvO;*fr1P>fds53S&b1iFTPY}+cWvr_ zCRZLmdmGtg+yi}~;mF~AgOlw|mWPW&|(o4TToOa-7?8sPn zpUA@e+%4z6F7VjfFG$aIuV2P`W1~*iLf+eTM%tDlx?bBs}^q#luK zjz>n%Z1+rW$-BjS4_&N%&c0UW?DYAct;YU#-{gZ;IB)f|kc{?CkFT3|eZko@yWuZO z1b>8Qn>-HvC#_ZCwA*unXGXoZHLm@d`>F1=4Li;(on`o=_af21CansGe>zZe`KP`? zXPfPKIVjU2dc$95v+QcW*IPZHp#5yGqFz7kS3DdTbfJY)#@C{fBG(I({_LILI3nA8 zX8#fCt-pp0y%+WBTg}1?%g#M(F-y;`?MRQ4U!_C;NyxEjf9a-mzTNZ=-^%VaecHmg z*7v}dOFTO!96H-~`QebY7jM=W;~4zaYm?E{DTlW7>?C@B$$RmLb&bk)#~7p?OpAJ9 zXH^p5{B213>a0oTtA<$j>N2idY^_JvZycWzYx-^e_c75UlD!&!dUL<|i2hCvjXNH? z5Yqbd*hhsUju|-Jb4h&W-tk6ZuB2y=(LD|=Y_;OmB7RrPSpA;v7o*xqZZyC6qpagP zKZnovZyi}+vvzljPy42}eB#jl?6g}yGh_dp`$uHRmkqc5qzzv_GxuNgZr-V>slo)k zEf@B_`m%G)f`?_zKGqC1{Py^UVZ%2@hOb6E-DJ74cYs^`jiap>raXyW4r^=w<<~hb z9sjbl*_Up{vKse1k4cKJHJSa2e{}z~hjYiAXf@&0%lI8RWmg&*?JIk*`1rDfCgZNg z?CN>rBZ&=^|v(Nf%&7A zZw#vYdfnqgbr#(cU*D2)CZL0T=E2M-b&mBdI6m>W!L|JIEeB-fdjIS{w~gERznZx| zsBOBveM3*1*q1MZj$KU}?bW(oXzp&Yo=dH6FMgBW-uRpTrn36hcP9B>ceug-tmpqV zJ;!NjVZp?Z;n$a)8?B#q)Az-eHLrim_pDKL;@kDV^L*b0IgP(jKJ@hEiGzg4j}#pe zK06;<*z4y^>y;hDtsm$&$_p?rs%fv+D{M&CsI(oimKMX~j(n`K;b4QJ{&C4ME)O~t zopLoU4Vt{pX1&L$8@!zv-7X(}vZiy#dTxE29qHhe=y1&~ElbDQVQwe1{JbIBvgJeRjVv2Fd=x?DZD^)IXL0iV*`N3gY+|Qn+~3O>dM4vqntjED}NH)a#HTwnx^-MdrxufCAs1DNt{&J z*6cqA1N%c^gIuzV^*oBtwl$uaWcG4v6z|2$9Gg=c7Y6T;UFW9vdDg{*~t@B_Zh@LyJZGGra#H`QaF zj$XrDUHk*Odb(C3a5y(%{X_W#{)FbaiccfXcgOeeyGR_NMw7$A#v|pw!Ji5N@Hc$I z2)Z=!3HjQI*5_csrQ(Cn4I-WsO9ea$@icA`DgQnGgk7SF4?Z2K@w5=`ebN5BiSltd z*MCr-hj(OgBYCjn#GlFwBe>Dj0lYh);)C4Wp`t~K!gvA#MN_7xN)S0ujiHyZQj?L~ zXn13c4xw=IO7TH9@V3!PfQq|u)NPOVpeY}~pT?>`;Nw$hk4JKa{3xk_8x4oR2w5~W zLSpTrVF^Xi{BV9K6H8Msm0pc}l@eGnTme4}&!B1LhSY2u=pwFEjC@Z~$R$mqDGt6F zLh(TsJm>&bvQZl)kle^gbR>nbw0p2A0hFs9NOwTtc?rb_CH$csP7)1`w2?evbahyC zg4{w;yHZx&@j)6v#sbHiB83KDk}>V(JVHmBAmt0fbcLLeQfqQ^z9*1)aZ!*vP)!=% zrRm`K?s~-sb&qfEtJD(#BIZe?0u9+T!AJ*-U)?68o(coDkACr!MI9Zwk! z>WNyDIe5C_gZ@$mf2{6sYoMomCLG7OSdn-#;R~7pqpu_=_l5qdrzxX~CbQ(A6rp-l ztutR;R_&BmsvfWC45@syE(a+$i(9eqEiju5V{j`K(;QB=>;ybo=^D-gu0-MoWrm_T zS`#MhzeA-@3^|;0;9k&Nt@>ok%AiN35=Q;)Kbz}MSAy-7DdHkonYZC5QR>rOZJVk zuJ<*_?oB`r3j#6)GKVJQ5WWO2J@yt3;Z2Z6&=L3Np1l4R7!*PBvmy|;fY)mxy1*H7 zF$}lR(j$_JLs|4+ELppI6>!N1F3kzdJElxbJkc>yQ6MSL|EOycU263|XJYDu2edcP z)MPd&R+Gs9USt#;Z5PM8if{;E%8iiS>a@C*0>#Kk$YrE)YILDM!ayLBMq4;3Min}w zslyd3ys)_ya9UYGp}jBLG9mq>LiAt>6AOLEix)BVAYi=(_DDnD>%qiQsSqkWnhp{1 z&YRwTXTZ?$U>Fm^DA#&15#iohDDQY;8XBrEcdzM>jgY$DK!WH%pxw1+qPf6W8VZMZ zT;f7`QCNL4g+|aq*HiC}LFiQQMJEC@Z(tQbEf{3{m6Z;Y9;zhI-FG&YUeV}U1iitI zOnPW7=ZRcCg?R*<@$$u-LBKp#He?|6cVU9Lh{YnYvq&HSy@;q<#)}-1cD;#R4~&(; zm-MLIp-fEl0`{bMXmb4IJz)PaATWuQ?#9GY+MlktwC`ixw}YI<4Kx)u*PV%_%4~En zzl^Zy8$rO!@HK_6@{=tScxwS;^UN!?gTwa$Z~K5ZJXWLpWXn8!m~a7#z@~FH)h^eT z3+mbj{sA$f`ee)cj9@}Byw6jS)L3%{TKJUlw9{Jw7;ly}Q4zqL@q84MgeNb0q9}}R zV+^34KbkK321x6HY0{xD1~JhpWTz<-9eQm-$bwe@b_u{b60Fq=VS;In3~Z?X$O`(n zK$xUMVlyL92aaW;swXzOjgB6e{Hy>t+`||V^T#vs$gra$mK-rI8U@^Sfz)P7aCkY4 ziKya`Hqf9N#~ttA{xJyb1x^IRfa;Si<4RV8`oN#&jTCH z1p;JHuZd)WBd=aiFfy@_(a?a%-@O2*FUW4AViR4lzepVmswQcqJc|eNMX;ElHLWA? z-{WR%SqCQ4gLN@y0{F@lbzsJedn_vdM)j(5iy{2*aBwy;xAMj3>g56wY-%-$Y%l~gi}&c55KO<0SI1CR{Eh+vs+TgH<0~o-?;F<95zvML zTIE~{bt_Jwp($=rk^fg->#~&zPxhF8as^y-hW)=zqv0yv8Nswa^7!cwi_3+8wGlK& z4q($~(6D^CVwfC583W68v}i}n!q39iuONWbdW~hM(E8vrB2%z;ES(poQvB6pLYEmep;s?F}H?Ly==ippRWnLsz6` ze~}oXmI8^&Flv7D-vVIxI77ip(`b-{f_u=F5G!8R2QOE#W>g)USL?*=Nykh+|9#JV zz-$kE4kkpuw1x#!O|c^+yh`0FyaV2c1Vv6fo!YG;$FUtj0JX9OA%WipU6^#lNmizlu7ge%gHA|i+q$2INOxqmFyR#Jlk@=e7N7@m zj5vFMhOSaDu5DMkGM)A4TgFeH-(@d& zqFsFsrw>7DD!i&geV(RR<0nbUhf;p@#7dHMfi5lRGa>;f6d7?i?gW)t$8=MnTV|vV zx;U&X_OY+A43u~fe888W8+!WxhptxTUio9?T|dZ1V&^HAshFo_GKUG&@xsB3b%0#}Uzky=KH0L8 zYwR=>PUa80C1Eh#qGWz#f5^)X+zF5_QuH~Tfhu6k`~~3XOgB@o?=>5egb=7F*JL z?63;$uudp&kl}u^DFJujgoC4!{Pr$p2X+*~ehydd6BEy3If3Tg=o(S} zR?llTfhi%3Go(T?U$H~0JdUYl1ohqda7{1Zw+s|wuTlqU`DKk7tRbTUwU8T7QI1#M z8L83uU#G}s);QpQGQ~W zz@O$TK({#wTIx<{>4qUYm0@tufDc(@s(dq4KE-4Tflgx(_#qbOzLx-=9Ojdnu)}NU zhn7(gytK@xJPFo3PPf%8SX(xyfvZMYtRa~EVxAS>9GEx;_}u~gniA?LGEs-DoTgO_ z4RpBmL4J!KK@RB&tGHyPH{DzvPPG#&p9oZ}qOjD|0q*xYW7onW_`XR+o+(8`^ zJ;B0DB&5vtFg)UKX57CG4@U!xg$e}2<4s3(7_qztvUTMPpv>1gTF;wb)YuV{!yk<_ zM{9j+3ZmkSEK_gDTym{fXGQ^IA~3};g1H6VC{S{(fk|L3ILw1D#Gy{YQ{dx-n)qum zi?`wqh|NdCLG{7%>mcQm=5m8tRdbZJt)M`@0!ckXpeT)+UrF=@Jls-&+FbR?maXhf z!PFuOQ&q_Gg^|8H=L2dse9ctoXh-|O6#OAPNvN1Vq4Ld;>il8^ED;!b=7A0_!Z1zh z;3o}F-7jEEmCobyL^J>8kjBnH^+FD%bznNnrdNNcTrkJ*!dyk-NIJ4pV##a|aFqVw zC}f3LJe-CscV;FO3f|Xr<4*`6PCbAk7nUY@(xI?|W@4dHE{Q%~Yy?=F;Mx1*MhPxfXEL?v|A0OTNsE?xxbLRKt~Fm-{rr*E6d&Vh$)gAsz{xaOFu;nGG%M80rBuyPMr ztudf?C9G#OP8YJmdhDKIoU)hm4siQ0^xR~8)v#$?V+6WCc2D^abi5g+dnN?eJ`*U& z6{!-AuZQC1xOyVP#9Js{KFJ&Si~!4#QzjXof~KCx;-UD%;m%7G?JSnx!KWn-u@br4 z|LTpk!0|cwlDiO{CsSxu3>@9*j3157zf%j;&1h>o=`V8ii!padIm zF*1yYh$&cv66EC)C8MKq>)Y9f;L;6liJ20n8UO_aBco%vBn5@iERS%x-edMc!r}-4 z(u9Cp8bg8eQ}j&H(9jwoygqaLfWW6giR7}rNgM@@=<8!G=P<1L{xdOmAAp{Qxe8g$ zZcNYx3=>&!C;1LD(^Lq))K!@N8FVlYR7zIj>t|O3oTe0nZ)+E|_&vZ&8Sqc%R0p1t zeG$If$@2CHk9)x+_crsY1J9Czi_OF4U}K3XI0!kQiWXD>URk191Wbf@4)f=RQ<4UX z@pjbYu4jP8RIoBB#(U_{VfZ!SI%*cSpsdp3Bz^Vc2D3~-Lx0!ja2yCf*H6&}?;kG= zohTLwu^<9cN|ET!6xnRkR|6ol1S-$|1fh9LbrDjR12v`HZN2v$PWuX$*~l>btCiKE z)Qc$y#`4CG11`4!_-*hd4c~XQE_mEojN*kk#lr%{0!ZNecN6?BC_oDIfvUAdPa(e?Og+YB5F&G79nF_8C7t zKs^s%D?*6SY&voUAdfx;LCp2RBiG}eeh@4@I1`w=5705Gicwo8)gi>ZHeSJapYdX_ z1X*uI9H|CD#j=$ST0wSGFKh-{JsDP)9yVhxb8BlIXap^KCX znswa-EhXI4xv(P$a{#PGt|4Z?o0lucoEYV@y=|qXR1}yli_jwRpWC(p(_i6B?%^4o z)&;E=9h5>9(UUhGi&zP&nF*>PXBh_2cBh^3N_0Bs|Crh)XMj?iK`A8mYlspWwvTjz zfFD{FlTP2z=)h*s$bI;l!&mvqmOZ?nj*XdzE9Of?!iuVpR$Jk)zQ1P9mgW$ zFHT-m2OJh56w#(DsLZ6GlP#YECo;fjqvQyFX3O+1t7ACv!U01rCS7yM+lSS73J=CI znCWqa3B<&}QCD*9%$q29ei~Q+R<>22Y? zHFX3>Y$j%r29xe)*Y`3jz~BHUew-q6c#EkGu&CnoDdz(0z@J(-)NF2x zzNwDIw0q^>$bX~v;ovx*-tT-Fu19$TyJWz9y{Aq>)zj}12b}_H@M1pbgU_Wabq+Va z!6^v1%}~|#C6v120To@ft_*drC>H1Ro;-6PC4H428;9h-$J|G^p5~bLQeWgg;Z}NV)`R;S$}Y9Q6X^G5CY4B;PO_@nlvrQSBCuKC2;18iHJrk z8dUE?H0bm>xS$V#SXzsUD3&iAOKj!HJ^RQL7L@(i2j(r1zo9|?SB_y^D13zx>?%Te zxN~OsW`QiRpeC}UI9FFUbvt$9l#v-j%q;amJt57a*)`2<0tls1+PX3k3nDRnT?r8FS@fG#t8I$hlr`I9y8ccBNIsc&fk_ zn}ij+%v!1~q`{wHIkEvJw|x~zSEv+bO)UFoDBiBSdk>tX zir3w&3N$DN1jSa0haC|7P^NfDdd11~kG>F3O<-lkiO}qL%U>j|wdv%MS*OXnfF3s7 zjw9$b?(~cF)J27TTZOdVVn=~QR1xyD(_bjO>{_E?cR}wXz^#T8%s6!UMP}sP4?6uh zDYkPM5}pWz$vir%+bN_5Y|me$j>L3ikIU8r2W0`Z zCP0~7T62STlV8bFv}pyJ_42HVWjye)Cs2otAmj^x4&Yy+1g}69z?4Q9A@?ZlSp!+{ ztee{NBB<9N4D3y?(7E3)vY_r+?DoZh=3UszGHhzk0r|;Mj6Xmtabgss43Q{V+Zahd zKai?kW6hnB4X}%-MY+hcTzkw!giH^g=gbs=bAv@3t1IDhSLmMSeI8X>h%K?A4T}MB{30t6F4yM)L4*M7Niv)Ygt%t zmCsO_(8zlC+-p}4f*;ifXtMTi7OWLoqCD3ou|+E0LLEnW4)qA@f;&pq;JoBS%siwz zgy>@Y6+UImeK7ELn39qcu@lfeq{RYkVlc^|A!>iiDz5|M^&|*@UPSbLm{e6V;7Ia0 zHf19Z4RWW2)9JrKN0-56$+Ex;ns2Hm36N0OoI(S|xcans;cSTGE)Z^{(I<$jN<(qf zOv@rZ3KMo)SWo~)j|5_5%iMsNsuCI|j1f(SI+EU)hg529+MK!rD6D~@-;uD&cv#l1 zn#xEYX00@k+zx)k*?~ar2565Q+$T-@HFC~efdJP6u)>hviox_gB-|`B?@%nb#szQ< za+=b3mR7=yG(($7U=DT<{?ytH#2RO)8Kk#oYo(wtkCuTNCwY0{Q3E5uM*grQM|Q+U zC2K`zPV(pq`rUc+QxRCEF^JHaaD}MlJ~#rD;W0 zANiO}qt3HRx2A*moR$o$3N~tmu2Rn@GQYwjvHmKafbhX5XqRN%eJ(;|t zMGrS?o46AcT?=BI%!jSEYei;SlvZ;g^C?Mn%pU$1u2aNDI88q2G@ej>o6r#pB8tW-1EFoZoskJrg820s{xR^3`ci z709@7LnmUH!@l#2M7HhXtXc)KyarhY5$-&4xCIw1X>LRzZr6z0+;2$8Uh$5wOWZr0x;z z*w{LTl^`2By6b`NqP!$Pt_2HOWR4CwMn$jIQC3`nYjP5IWU^*&78^?zgmdT}0cw${@)ASPTXhNvC=Xd5eNJL3#6(VuLG85fxf` zZTHMxvwSJ=s|Wm&(d>6sI|W5;p|xQ0ws3LdK$_?TF+om`x?k50Ua_wVQy8{OPcY{8 zrO(gF0p_ECc`~A9ceLYIsD~9DmA`WGRnIn{{MMj+QZ)zb#B13?!Z*`(;=!nwzhXS0^Yp@X3Fy-SuS;S|)uOhQz6qLKr3m41-aPI{CB!3U$B+WJFtjW2J!2w{TUC0LLk| z&RNt?;?+|&)(`~KAfm}4Y(ChXg?+q9&yySH28M-0>K1U+K)%YZbK|O1Jo@|!Sa?c? zb4MMC^kG=LmJVXhtep=tcq0?G16nzJ$uv=BpbJ$g0?WAgnlHQN2CC=542|4TdSF;p zX!&}dyc2|e3=pkQN9w-{FS@{XXlp_-Gn?w7gNk9x5S{O5#Gi!>nhr9MQz--RDDBo& z;L?z>VA{E%m}3jbkKs#d#;m1QWM`375C#(iDD%RQgpMVdrdQs7C;-P#G1M%~wzbkq zr_w*^Q8k#8T+;;9vJOm3dQC3;HH&IAqlyWQx(Tq$zuFqy{4a2Gav90mf)!eIU8B5h z9&h3G=SK*+(Qs^>Nd?nF+Y-m(ui!JoK>)IIF}X2))5@sTO4v zKvLqBnNx!xzlmWbgj|4o-TfCyF=fIy;C+0OZvq~Li*TgBZt7P>LX1uQ;Uz2I^`ToDf7z-500zf)MHwA6z zs4RyU8!XW(e?f!~Ci0$@t8Vnl3sW)2!Wnd-f5jE5bnklS`KVJLkOgOtWL!=e_AAtw zR8Xeau!O@iFpoFXjLVn25UY9<-}eZBE}2hHOsNJr z7ojwgJ!sJ>-s(HP=mvT z2#zA?TK}$_E+sF*EdYwDRem21?0U%qQA_D650N%SS?<6^0&qbtqMN5yfeU5YWDgJY zpDv4s?uSiK&RnQ#TnJI~;NmToyry=CH^?B6hQW4#@>XxS5?1~<5=S8=O(V(Ldnfo&KVd$yiYpG7QO>WH2bYg$)jKgZwfQ@{1#(z^t^Y zkWtfI#jo*-9RoT!lPf|897_j*&725wL7S>cjuep1SoM#&;>Ax(U@?;{5$a@AgI>Ir zy;Agv`E}Mi)7|hmoKDy6h76y8%RF_sp|8=v>s>&T(Aud{nJ(K|6_QG8G3|r`nWg$> zgMv7wFzq2{R|c@!qgx;)I&mVJPRhRUOkEQoBWbF+-mITh4N}zGGtk4WosOJ^%Pc4^ zH$A6%_)4QFg`>+e!~934EvSwUr2#p!?s$}yp0X9!1 zJ`|>TO`!$MM8yl9QL#Kv$6{ON!;PKL&!@Y?swc-6)MiScZNEZCt5{!US^=#-b*E=a z96;$c(%dGybDasN*cL%?SJpc)qDw z=keamoggARY{;8;Ywb-U!18+WV86f zr<-@6F05g$dE(Ten2C#Gv)m+zhFQDiL^|HwITQw+PJ|Bq-!j3}_8D;vk$!RrVapre zT`>hVgH8{fKCTcYXbCXJtkFaa!nRq^8SaJ$wxnKu% z`Q^Gr?gbFL1Y(@*IS7V>`-=CYR3@@Yu`A+RZf{x~p}*f47}$3Ouz3i+`^0w{sWwofYTg)DnHq>lg%`6Xb>pUn$_GN4L~F~ zS*zg{Wz97p}}8)xo7hP_Kg^bj`Hpz zWRo>hqZ*@L$DAqyRPcO`iP8-4Gh1ffg@P)_<3&rO=sb@9cgI|q6L5^6in1cmhTBrm zG1Y9!wEqYQgRUFb{3MIaymvTD`EOQGa23xB>*)q3Y6g+6;mR}r% zxJ(AobDT?j@|VCEQV$m8p_oy9vSki%wUWXx6)z1!5NNWcdJXb+%OECf0O)RP6HROA zIcq>E#&h|;C9O!nDDytwd2}FD9Z@h0foH2e*|OQgYjZq?IlFlIyL6E=*flyX+GjX! TY(h;@!?}i$7z!3V8^-w`q)kqw literal 0 HcmV?d00001 diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..7b88a4434c --- /dev/null +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,22 @@ +package com.coderising.jvm.loader; + +import java.util.ArrayList; +import java.util.List; + +public class ClassFileLoader { + + private List clzPaths = new ArrayList(); + + public byte[] readBinaryCode(String className) { + + return null; + } + + public void addClassPath(String path) { + + } + + public String getClassPath() { + return null; + } +} diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..93c48fe8e8 --- /dev/null +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,74 @@ +package com.coderising.jvm.test; + +import com.coderising.jvm.loader.ClassFileLoader; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class ClassFileloaderTest { + + static String path1 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\mini-jvm\\bin"; + static String path2 = "C:\temp"; + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testClassPath() { + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + loader.addClassPath(path2); + + String clzPath = loader.getClassPath(); + + Assert.assertEquals(path1 + ";" + path2, clzPath); + } + + @Test + public void testClassFileLength() { + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + + String className = "com.coderising.jvm.test.EmployeeV1"; + + byte[] byteCodes = loader.readBinaryCode(className); + + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + Assert.assertEquals(1056, byteCodes.length); + } + + @Test + public void testMagicNumber() { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "com.coderising.jvm.test.EmployeeV1"; + byte[] byteCodes = loader.readBinaryCode(className); + byte[] codes = new byte[] {byteCodes[0], byteCodes[1], byteCodes[2], byteCodes[3]}; + + String acctualValue = this.byteToHexString(codes); + + Assert.assertEquals("cafebabe", acctualValue); + } + + private String byteToHexString(byte[] codes) { + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < codes.length; i++) { + byte b = codes[i]; + int value = b & 0xFF; + String strHex = Integer.toHexString(value); + if (strHex.length() < 2) { + strHex = "0" + strHex; + } + buffer.append(strHex); + } + return buffer.toString(); + } +} diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/test/EmployeeV1.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..9a36573dd3 --- /dev/null +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/test/EmployeeV1.java @@ -0,0 +1,28 @@ +package com.coderising.jvm.test; + +public class EmployeeV1 { + + + private String name; + private int age; + + public EmployeeV1(String name, int age) { + this.name = name; + this.age = age; + } + + public void setName(String name) { + this.name = name; + } + public void setAge(int age){ + this.age = age; + } + public void sayHello() { + System.out.println("Hello , this is class Employee "); + } + public static void main(String[] args){ + EmployeeV1 p = new EmployeeV1("Andy",29); + p.sayHello(); + + } +} \ No newline at end of file diff --git a/group20/1107837739/1107837739Learning/src/org/korben/coderising/litestruts/util/struts.xml b/group20/1107837739/1107837739Learning/src/org/korben/coderising/litestruts/util/struts.xml deleted file mode 100644 index 1cb3f4a5df..0000000000 --- a/group20/1107837739/1107837739Learning/src/org/korben/coderising/litestruts/util/struts.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - /jsp/homepage.jsp - /jsp/showLogin.jsp - - - /jsp/welcome.jsp - /jsp/error.jsp - - \ No newline at end of file From b4af458bbc21d59ab8ab9a7550387161aa7d2d7a Mon Sep 17 00:00:00 2001 From: Korben_CHY Date: Sat, 1 Apr 2017 15:22:07 +0800 Subject: [PATCH 037/203] submit ClassFileLoader by Korben --- .../jvm/loader/ClassFileLoader.java | 91 ++++++++++++++++++- .../jvm/test/ClassFileloaderTest.java | 2 +- 2 files changed, 91 insertions(+), 2 deletions(-) diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java index 7b88a4434c..0411392cee 100644 --- a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -1,5 +1,9 @@ package com.coderising.jvm.loader; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -8,15 +12,100 @@ public class ClassFileLoader { private List clzPaths = new ArrayList(); public byte[] readBinaryCode(String className) { + if (className == null || className.length() == 0) { + return null; + } - return null; + File classFile = getClassFileFromClassPath(className); + + if (classFile == null) { + return null; + } + + return readFileBytes(classFile); } public void addClassPath(String path) { + if (path == null || path.length() == 0) { + return; + } + clzPaths.add(path); } public String getClassPath() { + StringBuilder stringBuilder = new StringBuilder(); + for (int i = 0; i < clzPaths.size(); i++) { + stringBuilder.append(clzPaths.get(i)); + if (i < clzPaths.size() - 1) { + stringBuilder.append(";"); + } + } + + return stringBuilder.toString(); + } + + private byte[] readFileBytes(File file) { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + FileInputStream in = null; + try { + in = new FileInputStream(file); + byte[] buffer = new byte[1024]; + int len; + while ((len = in.read(buffer)) != -1) { + out.write(buffer, 0, len); + } + + return out.toByteArray(); + } catch (IOException e) { + e.printStackTrace(); + return null; + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + private File getClassFileFromClassPath(String className) { + className = className2FilePath(className); + className += ".class"; + + // 从当前路径读取 + File classFile = getFileFromDir("", className); + if (classFile != null) { + return classFile; + } + + // 从环境变量路径读取 + for (String clzPath : clzPaths) { + classFile = getFileFromDir(clzPath, className); + if (classFile != null) { + return classFile; + } + } + return null; } + + private File getFileFromDir(String dir, String fileName) { + File file = new File(dir); + File destFile; + if (file.exists() && file.isDirectory()) { + destFile = new File(file.getAbsolutePath() + File.separator + fileName); + if (destFile.isFile() && destFile.exists()) { + return destFile; + } + } + return null; + } + + private String className2FilePath(String className) { + return className.replaceAll("\\.", File.separator); + } } diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java index 93c48fe8e8..b598f7f6d1 100644 --- a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -8,7 +8,7 @@ public class ClassFileloaderTest { - static String path1 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\mini-jvm\\bin"; + static String path1 = "/Users/Korben/wks/hom/01.coding2017/group20/1107837739/1107837739Learning/mini-jvm/out/production/mini-jvm/"; static String path2 = "C:\temp"; @Before From f8210b63c462f3137736a5365008716539cf4bb4 Mon Sep 17 00:00:00 2001 From: Korben_CHY Date: Sat, 1 Apr 2017 15:29:21 +0800 Subject: [PATCH 038/203] rename packagename by Korben --- .../src/{org/korben => com}/Main.java | 2 +- .../coderising/array/ArrayUtil.java | 2 +- .../coderising/array/ArrayUtilTest.java | 2 +- .../coderising/download/DownloadThread.java | 10 ++-- .../coderising/download/FileDownloader.java | 8 ++-- .../download/FileDownloaderTest.java | 8 ++-- .../coderising/download/api/Connection.java | 2 +- .../download/api/ConnectionException.java | 2 +- .../download/api/ConnectionManager.java | 2 +- .../download/api/DownloadListener.java | 2 +- .../download/impl/ConnectionImpl.java | 4 +- .../download/impl/ConnectionManagerImpl.java | 8 ++-- .../coderising/litestruts/LoginAction.java | 2 +- .../coderising/litestruts/Struts.java | 6 +-- .../coderising/litestruts/StrutsTest.java | 2 +- .../coderising/litestruts/View.java | 2 +- .../litestruts/dom/StrutsAction.java | 2 +- .../litestruts/util/StrutsParser.java | 7 ++- .../coding/basic/linklist/LRUPageFrame.java | 48 +++++++++++++++++++ .../basic/linklist/LRUPageFrameTest.java | 28 +++++++++++ .../coding/basic/list/KArrayList.java | 2 +- .../coding/basic/list/KIterator.java | 2 +- .../coding/basic/list/KLinkedList.java | 2 +- .../coding/basic/list/KLinkedListTest.java | 2 +- .../coding/basic/list/KList.java | 2 +- .../coding/basic/list/KListIteratorTest.java | 2 +- .../coding/basic/list/KListTest.java | 2 +- .../coding/basic/queue/KArrayQueue.java | 2 +- .../coding/basic/queue/KQueue.java | 2 +- .../coding/basic/queue/KQueueTest.java | 2 +- .../coding/basic/stack/KStack.java | 2 +- .../coding/basic/stack/KStackTest.java | 2 +- .../coding/basic/tree/BinaryTreeNode.java | 2 +- .../coding/basic/tree/BinaryTreeNodeTest.java | 2 +- 34 files changed, 126 insertions(+), 51 deletions(-) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/Main.java (86%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coderising/array/ArrayUtil.java (99%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coderising/array/ArrayUtilTest.java (99%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coderising/download/DownloadThread.java (89%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coderising/download/FileDownloader.java (93%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coderising/download/FileDownloaderTest.java (86%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coderising/download/api/Connection.java (93%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coderising/download/api/ConnectionException.java (81%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coderising/download/api/ConnectionManager.java (92%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coderising/download/api/DownloadListener.java (59%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coderising/download/impl/ConnectionImpl.java (96%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coderising/download/impl/ConnectionManagerImpl.java (90%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coderising/litestruts/LoginAction.java (95%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coderising/litestruts/Struts.java (96%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coderising/litestruts/StrutsTest.java (96%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coderising/litestruts/View.java (90%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coderising/litestruts/dom/StrutsAction.java (92%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coderising/litestruts/util/StrutsParser.java (91%) create mode 100644 group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/linklist/LRUPageFrame.java create mode 100644 group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/linklist/LRUPageFrameTest.java rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coding/basic/list/KArrayList.java (98%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coding/basic/list/KIterator.java (75%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coding/basic/list/KLinkedList.java (99%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coding/basic/list/KLinkedListTest.java (99%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coding/basic/list/KList.java (91%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coding/basic/list/KListIteratorTest.java (94%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coding/basic/list/KListTest.java (99%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coding/basic/queue/KArrayQueue.java (98%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coding/basic/queue/KQueue.java (84%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coding/basic/queue/KQueueTest.java (97%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coding/basic/stack/KStack.java (97%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coding/basic/stack/KStackTest.java (97%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coding/basic/tree/BinaryTreeNode.java (98%) rename group20/1107837739/1107837739Learning/data-structure/src/{org/korben => com}/coding/basic/tree/BinaryTreeNodeTest.java (97%) diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/Main.java b/group20/1107837739/1107837739Learning/data-structure/src/com/Main.java similarity index 86% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/Main.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/Main.java index 671f67a9a7..459b35980d 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/Main.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/Main.java @@ -1,4 +1,4 @@ -package org.korben; +package com; public class Main { diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/array/ArrayUtil.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/array/ArrayUtil.java similarity index 99% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/array/ArrayUtil.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coderising/array/ArrayUtil.java index 87ea998621..fca71735ea 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/array/ArrayUtil.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/array/ArrayUtil.java @@ -1,4 +1,4 @@ -package org.korben.coderising.array; +package com.coderising.array; import java.util.ArrayList; import java.util.List; diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/array/ArrayUtilTest.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/array/ArrayUtilTest.java similarity index 99% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/array/ArrayUtilTest.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coderising/array/ArrayUtilTest.java index 9f23e2c341..a2933fc48b 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/array/ArrayUtilTest.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/array/ArrayUtilTest.java @@ -1,4 +1,4 @@ -package org.korben.coderising.array; +package com.coderising.array; import org.junit.Assert; import org.junit.Test; diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/DownloadThread.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/DownloadThread.java similarity index 89% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/DownloadThread.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/DownloadThread.java index 52a5fd20a9..93f163a44e 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/DownloadThread.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/DownloadThread.java @@ -1,11 +1,11 @@ -package org.korben.coderising.download; +package com.coderising.download; +import com.coderising.download.api.Connection; +import com.coderising.download.api.ConnectionException; +import com.coderising.download.api.DownloadListener; import java.io.IOException; import java.io.RandomAccessFile; -import org.korben.coderising.download.api.Connection; -import org.korben.coderising.download.api.ConnectionException; -import org.korben.coderising.download.api.ConnectionManager; -import org.korben.coderising.download.api.DownloadListener; +import com.coderising.download.api.ConnectionManager; public class DownloadThread extends Thread { diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/FileDownloader.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/FileDownloader.java similarity index 93% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/FileDownloader.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/FileDownloader.java index 43fde0b69e..aeeb726f53 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/FileDownloader.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/FileDownloader.java @@ -1,9 +1,9 @@ -package org.korben.coderising.download; +package com.coderising.download; +import com.coderising.download.api.ConnectionException; +import com.coderising.download.api.ConnectionManager; +import com.coderising.download.api.DownloadListener; import java.util.concurrent.atomic.AtomicInteger; -import org.korben.coderising.download.api.ConnectionException; -import org.korben.coderising.download.api.ConnectionManager; -import org.korben.coderising.download.api.DownloadListener; public class FileDownloader { diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/FileDownloaderTest.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/FileDownloaderTest.java similarity index 86% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/FileDownloaderTest.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/FileDownloaderTest.java index 53b6b6e45e..3e0a91b573 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/FileDownloaderTest.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/FileDownloaderTest.java @@ -1,11 +1,11 @@ -package org.korben.coderising.download; +package com.coderising.download; +import com.coderising.download.api.ConnectionManager; +import com.coderising.download.api.DownloadListener; +import com.coderising.download.impl.ConnectionManagerImpl; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.korben.coderising.download.api.ConnectionManager; -import org.korben.coderising.download.api.DownloadListener; -import org.korben.coderising.download.impl.ConnectionManagerImpl; public class FileDownloaderTest { diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/api/Connection.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/api/Connection.java similarity index 93% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/api/Connection.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/api/Connection.java index 6f58852d56..46f573f5f2 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/api/Connection.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/api/Connection.java @@ -1,4 +1,4 @@ -package org.korben.coderising.download.api; +package com.coderising.download.api; import java.io.IOException; diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/api/ConnectionException.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/api/ConnectionException.java similarity index 81% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/api/ConnectionException.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/api/ConnectionException.java index d74b432783..45d5e3a83b 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/api/ConnectionException.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/api/ConnectionException.java @@ -1,4 +1,4 @@ -package org.korben.coderising.download.api; +package com.coderising.download.api; public class ConnectionException extends Exception { public ConnectionException(Exception e) { diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/api/ConnectionManager.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/api/ConnectionManager.java similarity index 92% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/api/ConnectionManager.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/api/ConnectionManager.java index 5e0d4afe3f..d0a7b84fcc 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/api/ConnectionManager.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/api/ConnectionManager.java @@ -1,4 +1,4 @@ -package org.korben.coderising.download.api; +package com.coderising.download.api; public interface ConnectionManager { /** diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/api/DownloadListener.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/api/DownloadListener.java similarity index 59% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/api/DownloadListener.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/api/DownloadListener.java index e2685665b7..b7100fa723 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/api/DownloadListener.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/api/DownloadListener.java @@ -1,4 +1,4 @@ -package org.korben.coderising.download.api; +package com.coderising.download.api; public interface DownloadListener { void notifyFinished(); diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/impl/ConnectionImpl.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/impl/ConnectionImpl.java similarity index 96% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/impl/ConnectionImpl.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/impl/ConnectionImpl.java index cce16fafbe..b9efbb3794 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/impl/ConnectionImpl.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/impl/ConnectionImpl.java @@ -1,10 +1,10 @@ -package org.korben.coderising.download.impl; +package com.coderising.download.impl; +import com.coderising.download.api.Connection; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; -import org.korben.coderising.download.api.Connection; public class ConnectionImpl implements Connection { diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/impl/ConnectionManagerImpl.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/impl/ConnectionManagerImpl.java similarity index 90% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/impl/ConnectionManagerImpl.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/impl/ConnectionManagerImpl.java index 16d8df8f7c..29919834fa 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/download/impl/ConnectionManagerImpl.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/impl/ConnectionManagerImpl.java @@ -1,11 +1,11 @@ -package org.korben.coderising.download.impl; +package com.coderising.download.impl; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; -import org.korben.coderising.download.api.Connection; -import org.korben.coderising.download.api.ConnectionException; -import org.korben.coderising.download.api.ConnectionManager; +import com.coderising.download.api.Connection; +import com.coderising.download.api.ConnectionException; +import com.coderising.download.api.ConnectionManager; public class ConnectionManagerImpl implements ConnectionManager { diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/LoginAction.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/litestruts/LoginAction.java similarity index 95% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/LoginAction.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coderising/litestruts/LoginAction.java index 20fa9e766b..f187e45227 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/LoginAction.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/litestruts/LoginAction.java @@ -1,4 +1,4 @@ -package org.korben.coderising.litestruts; +package com.coderising.litestruts; /** * 这是一个用来展示登录的业务类, 其中的用户名和密码都是硬编码的。 diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/Struts.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/litestruts/Struts.java similarity index 96% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/Struts.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coderising/litestruts/Struts.java index 7ac88522bf..a282279ff4 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/Struts.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/litestruts/Struts.java @@ -1,13 +1,13 @@ -package org.korben.coderising.litestruts; +package com.coderising.litestruts; +import com.coderising.litestruts.dom.StrutsAction; +import com.coderising.litestruts.util.StrutsParser; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import java.util.Objects; -import org.korben.coderising.litestruts.dom.StrutsAction; -import org.korben.coderising.litestruts.util.StrutsParser; public class Struts { diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/StrutsTest.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/litestruts/StrutsTest.java similarity index 96% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/StrutsTest.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coderising/litestruts/StrutsTest.java index 024f678100..9d940ed44b 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/StrutsTest.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/litestruts/StrutsTest.java @@ -1,4 +1,4 @@ -package org.korben.coderising.litestruts; +package com.coderising.litestruts; import java.util.HashMap; import java.util.Map; diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/View.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/litestruts/View.java similarity index 90% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/View.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coderising/litestruts/View.java index f4af03febc..e96403d8fc 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/View.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/litestruts/View.java @@ -1,4 +1,4 @@ -package org.korben.coderising.litestruts; +package com.coderising.litestruts; import java.util.Map; diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/dom/StrutsAction.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/litestruts/dom/StrutsAction.java similarity index 92% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/dom/StrutsAction.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coderising/litestruts/dom/StrutsAction.java index c16de22c44..e08c65bbc4 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/dom/StrutsAction.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/litestruts/dom/StrutsAction.java @@ -1,4 +1,4 @@ -package org.korben.coderising.litestruts.dom; +package com.coderising.litestruts.dom; import java.util.Map; diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/util/StrutsParser.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/litestruts/util/StrutsParser.java similarity index 91% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/util/StrutsParser.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coderising/litestruts/util/StrutsParser.java index 239ac2e4cd..74a85739c4 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coderising/litestruts/util/StrutsParser.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/litestruts/util/StrutsParser.java @@ -1,8 +1,8 @@ -package org.korben.coderising.litestruts.util; +package com.coderising.litestruts.util; +import com.coderising.litestruts.dom.StrutsAction; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -10,7 +10,6 @@ import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; -import org.korben.coderising.litestruts.dom.StrutsAction; /** * 解析struts.xml @@ -72,7 +71,7 @@ public static Map doParse() { private static InputStream getStrutsInputStream() { StrutsParser.class.getPackage().getName(); InputStream in = StrutsParser.class.getClassLoader() - .getResourceAsStream("org/korben/coderising/litestruts/util/" + STRUTS_XML); + .getResourceAsStream("com/coderising/litestruts/util/" + STRUTS_XML); if (in == null) { throw new IllegalStateException(STRUTS_XML + " doesn't exist"); } diff --git a/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/linklist/LRUPageFrame.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/linklist/LRUPageFrame.java new file mode 100644 index 0000000000..ae66fbd620 --- /dev/null +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/linklist/LRUPageFrame.java @@ -0,0 +1,48 @@ +package com.coding.basic.linklist; + +/** + * 用双向链表实现LRU算法 + * + * @author liuxin + */ +public class LRUPageFrame { + + private int capacity; + private Node first;// 链表头 + private Node last;// 链表尾 + public LRUPageFrame(int capacity) { + + this.capacity = capacity; + } + + /** + * 获取缓存中对象 + */ + public void access(int pageNum) { + + } + + public String toString() { + StringBuilder buffer = new StringBuilder(); + Node node = first; + while (node != null) { + buffer.append(node.pageNum); + + node = node.next; + if (node != null) { + buffer.append(","); + } + } + return buffer.toString(); + } + + private static class Node { + + Node prev; + Node next; + int pageNum; + + Node() { + } + } +} diff --git a/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/linklist/LRUPageFrameTest.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/linklist/LRUPageFrameTest.java new file mode 100644 index 0000000000..3569190716 --- /dev/null +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/linklist/LRUPageFrameTest.java @@ -0,0 +1,28 @@ +package com.coding.basic.linklist; + +import org.junit.Assert; +import org.junit.Test; + +public class LRUPageFrameTest { + + @Test + public void testAccess() { + LRUPageFrame frame = new LRUPageFrame(3); + frame.access(7); + frame.access(0); + frame.access(1); + Assert.assertEquals("1,0,7", frame.toString()); + frame.access(2); + Assert.assertEquals("2,1,0", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(3); + Assert.assertEquals("3,0,2", frame.toString()); + frame.access(0); + Assert.assertEquals("0,3,2", frame.toString()); + frame.access(4); + Assert.assertEquals("4,0,3", frame.toString()); + } +} diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KArrayList.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/list/KArrayList.java similarity index 98% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KArrayList.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/list/KArrayList.java index 5df5408e67..dc67aa7516 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KArrayList.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/list/KArrayList.java @@ -1,4 +1,4 @@ -package org.korben.coding.basic.list; +package com.coding.basic.list; import java.util.Objects; diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KIterator.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/list/KIterator.java similarity index 75% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KIterator.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/list/KIterator.java index b5245ecca0..83be164f95 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KIterator.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/list/KIterator.java @@ -1,4 +1,4 @@ -package org.korben.coding.basic.list; +package com.coding.basic.list; /** * Created by Korben on 24/02/2017. diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KLinkedList.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/list/KLinkedList.java similarity index 99% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KLinkedList.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/list/KLinkedList.java index 5f0975d3fb..5ce4fdc916 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KLinkedList.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/list/KLinkedList.java @@ -1,4 +1,4 @@ -package org.korben.coding.basic.list; +package com.coding.basic.list; import java.util.ArrayList; import java.util.List; diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KLinkedListTest.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/list/KLinkedListTest.java similarity index 99% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KLinkedListTest.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/list/KLinkedListTest.java index f086efdbdc..e7a35a7a49 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KLinkedListTest.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/list/KLinkedListTest.java @@ -1,4 +1,4 @@ -package org.korben.coding.basic.list; +package com.coding.basic.list; import org.junit.Assert; import org.junit.Before; diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KList.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/list/KList.java similarity index 91% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KList.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/list/KList.java index e5b166094e..a70076509e 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KList.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/list/KList.java @@ -1,4 +1,4 @@ -package org.korben.coding.basic.list; +package com.coding.basic.list; /** * Korben's List diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KListIteratorTest.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/list/KListIteratorTest.java similarity index 94% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KListIteratorTest.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/list/KListIteratorTest.java index 7017e0ed2c..2cab546462 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KListIteratorTest.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/list/KListIteratorTest.java @@ -1,4 +1,4 @@ -package org.korben.coding.basic.list; +package com.coding.basic.list; import org.junit.Assert; import org.junit.Before; diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KListTest.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/list/KListTest.java similarity index 99% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KListTest.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/list/KListTest.java index d789318174..8edc8e2b31 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/list/KListTest.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/list/KListTest.java @@ -1,4 +1,4 @@ -package org.korben.coding.basic.list; +package com.coding.basic.list; import java.util.Objects; import org.junit.Assert; diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/queue/KArrayQueue.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/queue/KArrayQueue.java similarity index 98% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/queue/KArrayQueue.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/queue/KArrayQueue.java index eea57cf035..3b47fcce1b 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/queue/KArrayQueue.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/queue/KArrayQueue.java @@ -1,4 +1,4 @@ -package org.korben.coding.basic.queue; +package com.coding.basic.queue; import java.util.NoSuchElementException; diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/queue/KQueue.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/queue/KQueue.java similarity index 84% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/queue/KQueue.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/queue/KQueue.java index 9d8146d50d..d5719527aa 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/queue/KQueue.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/queue/KQueue.java @@ -1,4 +1,4 @@ -package org.korben.coding.basic.queue; +package com.coding.basic.queue; /** * Korben's Queue Interface diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/queue/KQueueTest.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/queue/KQueueTest.java similarity index 97% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/queue/KQueueTest.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/queue/KQueueTest.java index 17c3703a64..ef1f930e58 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/queue/KQueueTest.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/queue/KQueueTest.java @@ -1,4 +1,4 @@ -package org.korben.coding.basic.queue; +package com.coding.basic.queue; import java.util.NoSuchElementException; import org.junit.Assert; diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/stack/KStack.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/KStack.java similarity index 97% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/stack/KStack.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/KStack.java index eb83eb47cd..cb1fb5e5b8 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/stack/KStack.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/KStack.java @@ -1,4 +1,4 @@ -package org.korben.coding.basic.stack; +package com.coding.basic.stack; import java.util.EmptyStackException; import java.util.Objects; diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/stack/KStackTest.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/KStackTest.java similarity index 97% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/stack/KStackTest.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/KStackTest.java index 20b451a7ef..eee06600b1 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/stack/KStackTest.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/KStackTest.java @@ -1,4 +1,4 @@ -package org.korben.coding.basic.stack; +package com.coding.basic.stack; import java.util.EmptyStackException; import org.junit.Assert; diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/tree/BinaryTreeNode.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/tree/BinaryTreeNode.java similarity index 98% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/tree/BinaryTreeNode.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/tree/BinaryTreeNode.java index 3cfcacc37c..3c788266c9 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/tree/BinaryTreeNode.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/tree/BinaryTreeNode.java @@ -1,4 +1,4 @@ -package org.korben.coding.basic.tree; +package com.coding.basic.tree; /** * Korben's BinaryTreeNode diff --git a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/tree/BinaryTreeNodeTest.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/tree/BinaryTreeNodeTest.java similarity index 97% rename from group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/tree/BinaryTreeNodeTest.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/tree/BinaryTreeNodeTest.java index 05873872a7..51f9263e9a 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/org/korben/coding/basic/tree/BinaryTreeNodeTest.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/tree/BinaryTreeNodeTest.java @@ -1,4 +1,4 @@ -package org.korben.coding.basic.tree; +package com.coding.basic.tree; import org.junit.Assert; From 7941760ca42aeda17fc7d4b7ba9df7e4529c4acf Mon Sep 17 00:00:00 2001 From: xmt <542194147@qq.com> Date: Sat, 1 Apr 2017 15:36:39 +0800 Subject: [PATCH 039/203] jvm --- .../jvm/loader/ClassFileLoader.java | 75 +++++++++++++++ .../jvm/test/ClassFileloaderTest.java | 94 +++++++++++++++++++ .../com/coderising/jvm/test/EmployeeV1.java | 28 ++++++ .../src/com/coding/basic/LRUPageFrame.java | 74 +++++++++++++++ .../com/coding/basic/LRUPageFrameTest.java | 31 ++++++ 5 files changed, 302 insertions(+) create mode 100644 group11/542194147/myDataStructure/src/com/coderising/jvm/loader/ClassFileLoader.java create mode 100644 group11/542194147/myDataStructure/src/com/coderising/jvm/test/ClassFileloaderTest.java create mode 100644 group11/542194147/myDataStructure/src/com/coderising/jvm/test/EmployeeV1.java create mode 100644 group11/542194147/myDataStructure/src/com/coding/basic/LRUPageFrame.java create mode 100644 group11/542194147/myDataStructure/src/com/coding/basic/LRUPageFrameTest.java diff --git a/group11/542194147/myDataStructure/src/com/coderising/jvm/loader/ClassFileLoader.java b/group11/542194147/myDataStructure/src/com/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..7e19ae9c85 --- /dev/null +++ b/group11/542194147/myDataStructure/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,75 @@ +package com.coderising.jvm.loader; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + + + +public class ClassFileLoader { + + private List clzPaths = new ArrayList(); + private static final int BUFFER_SIZE=1024; + + public byte[] readBinaryCode(String className) { + className=className.replace(".","\\"); + StringBuffer sb=new StringBuffer(); + String absolutePath=sb.append(clzPaths.get(0)).append("\\").append(className).append(".class").toString(); + File file=new File(absolutePath); + FileInputStream fis = null; + ByteArrayOutputStream baos=new ByteArrayOutputStream(); + byte[]buffer=new byte[BUFFER_SIZE]; + try { + fis=new FileInputStream(file); + while(baos.size()file.length()){ + return Arrays.copyOf(baos.toByteArray(), (int) file.length()); + } + } catch (IOException e) { + e.printStackTrace(); + }finally{ + try { + fis.close(); + baos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return baos.toByteArray(); + } + + + public void addClassPath(String path) { + clzPaths.add(path); + } + + + + public String getClassPath(){ + StringBuffer sb=new StringBuffer(); + for(int i=0;i Date: Sat, 1 Apr 2017 17:40:44 +0800 Subject: [PATCH 040/203] submit LRUPageFrame by Korben --- .../coding/basic/linklist/LRUPageFrame.java | 66 +++++++++++++++++-- 1 file changed, 61 insertions(+), 5 deletions(-) diff --git a/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/linklist/LRUPageFrame.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/linklist/LRUPageFrame.java index ae66fbd620..63ff3851c0 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/linklist/LRUPageFrame.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/linklist/LRUPageFrame.java @@ -3,15 +3,16 @@ /** * 用双向链表实现LRU算法 * - * @author liuxin + * @author Korben */ public class LRUPageFrame { private int capacity; - private Node first;// 链表头 - private Node last;// 链表尾 - public LRUPageFrame(int capacity) { + private int size; + private Node first; // 链表头 + private Node last; // 链表尾 + public LRUPageFrame(int capacity) { this.capacity = capacity; } @@ -19,7 +20,61 @@ public LRUPageFrame(int capacity) { * 获取缓存中对象 */ public void access(int pageNum) { + if (this.first == null) { + add2First(pageNum); + return; + } + + if (this.first.pageNum == pageNum) { + return; + } + + if (reorderCache(pageNum)) { + return; + } + + add2First(pageNum); + + if (this.size > this.capacity) { + removeNode(this.last); + } + } + + private boolean reorderCache(int pageNum) { + Node node = this.first; + for (int i = 0; i < this.size - 1; i++) { + node = node.next; + if (node.pageNum == pageNum) { + removeNode(node); + add2First(node.pageNum); + return true; + } + } + + return false; + } + + private void removeNode(Node node) { + node.prev.next = node.next; + if (node.next != null) { + node.next.prev = node.prev; + } else { + this.last = node.prev; + } + this.size--; + } + + private void add2First(int pageNum) { + Node oldFirst = this.first; + this.first = new Node(pageNum); + this.first.next = oldFirst; + if (oldFirst == null) { + this.last = this.first; + } else { + oldFirst.prev = this.first; + } + this.size++; } public String toString() { @@ -42,7 +97,8 @@ private static class Node { Node next; int pageNum; - Node() { + Node(int pageNum) { + this.pageNum = pageNum; } } } From da21ca14a7de171c9be872bc8e960a91943cbdf7 Mon Sep 17 00:00:00 2001 From: RalfNick Date: Sat, 1 Apr 2017 17:44:59 +0800 Subject: [PATCH 041/203] Ralf --- .../LRU/LRUPageFrame.java" | 122 ++++++++++++++++++ .../LRU/LRUPageFrameTest.java" | 37 ++++++ .../jvm/loader/ClassFileLoader.java" | 79 ++++++++++++ .../jvm/loader/ClassFileLoaderException.java" | 25 ++++ .../jvm/test/ClassFileLoaderTest.java" | 75 +++++++++++ .../com/coderising/jvm/test/EmployeeV1.java" | 32 +++++ 6 files changed, 370 insertions(+) create mode 100644 "group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/LRU/LRUPageFrame.java" create mode 100644 "group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/LRU/LRUPageFrameTest.java" create mode 100644 "group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/loader/ClassFileLoader.java" create mode 100644 "group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/loader/ClassFileLoaderException.java" create mode 100644 "group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/test/ClassFileLoaderTest.java" create mode 100644 "group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/test/EmployeeV1.java" diff --git "a/group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/LRU/LRUPageFrame.java" "b/group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/LRU/LRUPageFrame.java" new file mode 100644 index 0000000000..47fdbbe85c --- /dev/null +++ "b/group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/LRU/LRUPageFrame.java" @@ -0,0 +1,122 @@ +package com.ralf.lru; + +/** + * ˫������ʵ��LRU�㷨 + * @author Ralf + * + */ +public class LRUPageFrame { + + private static class Node { + private Node prev; + private Node next; + int pageNum; + + public Node(int pageNum) { + this.pageNum = pageNum; + } + } + + private int capacity; + private Node head; + private Node tail; + private int size; + + private void addFirst(int PageNum) { + Node node = new Node(PageNum); + if (head == null) { + node.next = null; + node.prev = null; + head = node; + tail = node; + this.size++; + } else { + node.next = head; + node.prev = null; + head.prev = node; + head = node; + this.size++; + } + } + + public LRUPageFrame(int capacity) { + this.capacity = capacity; + this.head = null; + this.tail = null; + } + + /** + * ��ȡ������� + * @param PageNum + */ + public void access(int PageNum) { + + Node node = getNode(PageNum); + if (node == null) { + if (size < capacity) { + addFirst(PageNum); + } else { + removeLast(); + addFirst(PageNum); + } + } else if (this.head.pageNum == PageNum) { + return; + } + else { + moveToHead(node); + } + } + + private void moveToHead(Node node) { + Node current = node; + if (node.pageNum == this.tail.pageNum) { + node.prev.next = null; + tail = node.prev; + + } else { + node.prev.next = node.next; + node.next.prev = node.prev; + } + current.next = head; + current.prev = null; + this.head = current; + + } + + private void removeLast() { + + Node preNode = tail.prev; + tail.prev.next = null; + tail.prev = null; + tail = preNode; + this.size--; + } + + private Node getNode(int PageNum) { + Node current = this.head; + while (current != null) { + if (current.pageNum == PageNum) { + return current; + } + current = current.next; + } + return null; + } + + public String toString() { + if (this.head == null) { + return null; + } + StringBuilder stringBuilder = new StringBuilder(); + Node current = this.head; + while (current != null) { + stringBuilder.append(current.pageNum); + if (current.next != null) { + stringBuilder.append(","); + } + current = current.next; + + } + return stringBuilder.toString(); + } +} diff --git "a/group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/LRU/LRUPageFrameTest.java" "b/group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/LRU/LRUPageFrameTest.java" new file mode 100644 index 0000000000..b024277905 --- /dev/null +++ "b/group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/LRU/LRUPageFrameTest.java" @@ -0,0 +1,37 @@ +package com.ralf.lru; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class LRUPageFrameTest { + + @Before + public void setUp() throws Exception { + } + + @Test + public void test() { + + LRUPageFrame frame = new LRUPageFrame(3); + frame.access(7); + frame.access(0); + frame.access(1); + Assert.assertEquals("1,0,7", frame.toString()); + frame.access(2); + Assert.assertEquals("2,1,0", frame.toString()); + frame.access(0); + + Assert.assertEquals("0,2,1", frame.toString()); + + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(3); + Assert.assertEquals("3,0,2", frame.toString()); + frame.access(0); + Assert.assertEquals("0,3,2", frame.toString()); + frame.access(4); + Assert.assertEquals("4,0,3", frame.toString()); + } + +} diff --git "a/group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/loader/ClassFileLoader.java" "b/group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/loader/ClassFileLoader.java" new file mode 100644 index 0000000000..c6739db459 --- /dev/null +++ "b/group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/loader/ClassFileLoader.java" @@ -0,0 +1,79 @@ +package com.coderising.jvm.loader; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class ClassFileLoader { + + private List list = new ArrayList(); + + public ClassFileLoader() { + + } + + public void addClassPath(String path) { + list.add(path); + } + + public String getClassPath() { + if (list.size() == 0 || list == null) { + return null; + } + StringBuilder stringBuilder = new StringBuilder(); + for (int i = 0; i < list.size(); i++) { + if (i == list.size() - 1) { + stringBuilder.append(list.get(i)); + } else { + stringBuilder.append(list.get(i)).append(";"); + } + + } + return stringBuilder.toString(); + } + + public byte[] readBinaryCode(String className) throws ClassFileLoaderException { + + String fileName = getFileName(className); + BufferedInputStream bis = null; + try { + bis = new BufferedInputStream(new FileInputStream(fileName)); + byte[] bytes_code = new byte[1024]; + int len = 0; + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + while((len = bis.read(bytes_code)) != -1){ + baos.write(bytes_code, 0, len); + } + return baos.toByteArray(); + } catch (FileNotFoundException e) { + throw new ClassFileLoaderException(e); + } catch (IOException e) { + throw new ClassFileLoaderException(e); + } + finally{ + if (bis != null) { + try { + bis.close(); + } catch (IOException e) { + throw new ClassFileLoaderException(e); + } + } + } + } + + private String getFileName(String className) { + StringBuilder stringBuilder = new StringBuilder(); + String folder = getClassPath(); + String packgeName = className.replace(".", "\\"); + + stringBuilder.append(folder).append('\\').append(packgeName).append(".class"); + return stringBuilder.toString(); + } + +} diff --git "a/group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/loader/ClassFileLoaderException.java" "b/group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/loader/ClassFileLoaderException.java" new file mode 100644 index 0000000000..cb70b2d88f --- /dev/null +++ "b/group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/loader/ClassFileLoaderException.java" @@ -0,0 +1,25 @@ +package com.coderising.jvm.loader; + +import java.io.FileNotFoundException; +import java.io.IOException; + +public class ClassFileLoaderException extends Exception{ + + /** + * + */ + private static final long serialVersionUID = 1L; + + public ClassFileLoaderException(String msg){ + super(msg); + } + + public ClassFileLoaderException(FileNotFoundException e){ + super(e); + } + + public ClassFileLoaderException(IOException e){ + super(e); + } + +} diff --git "a/group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/test/ClassFileLoaderTest.java" "b/group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/test/ClassFileLoaderTest.java" new file mode 100644 index 0000000000..4585119f98 --- /dev/null +++ "b/group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/test/ClassFileLoaderTest.java" @@ -0,0 +1,75 @@ +package com.coderising.jvm.test; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.coderising.jvm.loader.ClassFileLoader; +import com.coderising.jvm.loader.ClassFileLoaderException; + +public class ClassFileLoaderTest { + + static String path1 = "D:\\MyTest\\mini-jvm\\bin"; + static String path2 = "C:\\temp"; + + @Before + public void setUp() throws Exception { + } + + @Test + public void test() { + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + loader.addClassPath(path2); + + String clzPath = loader.getClassPath(); + + Assert.assertEquals(path1 + ";" + path2, clzPath); + } + + @Test + public void ClassFileLengthTest() throws ClassFileLoaderException { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + + String className = "com.coderising.jvm.test.EmployeeV1"; + byte[] bytes = loader.readBinaryCode(className); + + Assert.assertEquals(1056, bytes.length); + } + + @Test + public void MagicNumberTest() throws ClassFileLoaderException { + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + + String className = "com.coderising.jvm.test.EmployeeV1"; + byte[] byteCodes = loader.readBinaryCode(className); + + byte[] bytes = { byteCodes[0], byteCodes[1], byteCodes[2], byteCodes[3] }; + String actualString = byteToHexString(bytes); + Assert.assertEquals("cafebabe", actualString); + } + + private String byteToHexString(byte[] bytes) { + + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < bytes.length; i++) { + byte b = bytes[i]; + int value = b & 0xFF; + String strHex = Integer.toHexString(value); + if (strHex.length() < 2) { + strHex = "0" + strHex; + } + buffer.append(strHex); + } + return buffer.toString(); + } + +} diff --git "a/group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/test/EmployeeV1.java" "b/group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/test/EmployeeV1.java" new file mode 100644 index 0000000000..39af3b3d32 --- /dev/null +++ "b/group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/test/EmployeeV1.java" @@ -0,0 +1,32 @@ +package com.coderising.jvm.test; + +public class EmployeeV1 { + + private String name; + private int age; + + public EmployeeV1(String name, int age){ + + this.name = name; + this.age = age; + } + + public void setName(String name) { + this.name = name; + } + + public void setAge(int age) { + this.age = age; + } + + public void sayHello(){ + System.out.println("Hello , this is class Employee "); + } + + public static void main(String[] args) { + + EmployeeV1 p = new EmployeeV1("Andy",29); + p.sayHello(); + } + +} From a5c157639f81ca67b5272daf562ebfa5ccbfe119 Mon Sep 17 00:00:00 2001 From: RalfNick Date: Sat, 1 Apr 2017 18:10:09 +0800 Subject: [PATCH 042/203] Ralf --- .../\346\226\207\347\253\240\351\223\276\346\216\245.txt" | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 "group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/\346\226\207\347\253\240\351\223\276\346\216\245.txt" diff --git "a/group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/\346\226\207\347\253\240\351\223\276\346\216\245.txt" "b/group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/\346\226\207\347\253\240\351\223\276\346\216\245.txt" new file mode 100644 index 0000000000..e69de29bb2 From 067d3a79f84f10bb7ae4c107eb38922ce9dc0bc9 Mon Sep 17 00:00:00 2001 From: James <1310368322@qq.com> Date: Sat, 1 Apr 2017 22:45:25 +0800 Subject: [PATCH 043/203] FourthHomework --- .../BaseDataStructure/LRUPageFrame.java | 143 ++++++++++++++++++ .../FourthHomework/jvm/ClassFileLoader.java | 51 +++++++ .../src/FourthHomework/jvm/TestJVM.java | 7 + .../BaseDataStructure/TestLRUPageFrame.java | 31 ++++ .../test/FourthHomework/JVM/EmployeeV1.java | 28 ++++ .../JVM/TestClassFileLoader.java | 67 ++++++++ 6 files changed, 327 insertions(+) create mode 100644 group11/1310368322/src/FourthHomework/BaseDataStructure/LRUPageFrame.java create mode 100644 group11/1310368322/src/FourthHomework/jvm/ClassFileLoader.java create mode 100644 group11/1310368322/src/FourthHomework/jvm/TestJVM.java create mode 100644 group11/1310368322/test/FourthHomework/BaseDataStructure/TestLRUPageFrame.java create mode 100644 group11/1310368322/test/FourthHomework/JVM/EmployeeV1.java create mode 100644 group11/1310368322/test/FourthHomework/JVM/TestClassFileLoader.java diff --git a/group11/1310368322/src/FourthHomework/BaseDataStructure/LRUPageFrame.java b/group11/1310368322/src/FourthHomework/BaseDataStructure/LRUPageFrame.java new file mode 100644 index 0000000000..5e860a31d7 --- /dev/null +++ b/group11/1310368322/src/FourthHomework/BaseDataStructure/LRUPageFrame.java @@ -0,0 +1,143 @@ +package DataStructure_4_LRU; + +import org.junit.runners.Parameterized.Parameters; + +/* + * ��˫������ʵ��LRU�㷨 + */ +public class LRUPageFrame { + private static class Node{ + Node prev; + Node next; + int pageNum = -1;// ����ҳ + + Node(){ + + } + } + + private int capacity; + + private Node first;// ����ͷ + private Node last;// ����β + boolean tag = false; + + public LRUPageFrame(int capacity){ + this.capacity = capacity; + + for(int i = 0; i < capacity; i++){ + Node curNode = new Node(); + if(null == first){ + last = first = curNode; + }else{ + last.next = curNode; + curNode.prev = last; + last = last.next; + } + last.next = null; + } + } + public void printList(){ + Node curNode = first; + while(curNode != null){ + curNode = curNode.next; + } + } + /* + * ��ȡ�����ж��� + * @param key + * @return + */ + public void access(int pageNum){ + printList(); + Node index = findLogicPage(pageNum); + modifyPhysicalPage(index,pageNum); + } + + /* + * @param pageNum ��ʾҪ��ѯ���߼�ҳ�� + * @return ��������ҳ���ҵ�Ҫ��ѯ���߼�ҳ�棬�򷵻ظ�����ҳ�ڵ�����ã����򷵻�null + */ + public Node findLogicPage(int pageNum){ + + Node index = null; + Node curNode = first; + while(curNode != null){ + if(curNode.pageNum == pageNum){ + index = curNode; + tag = true; + } + curNode = curNode.next; + } + return index; + } + /* + * @prama index ������ ���߼�ҳ������ҳ�Ľڵ������ + */ + public void modifyPhysicalPage(Node index,int pageNum){ + push(pageNum,index); + } + /* + * @param pageNum Ҫ push���߼�ҳ�棬 Ĭ��ջ���� first, bottom ջ�� ָ����ջ�Ĵ�С + */ + public void push(int pageNum,Node bottom){ + Node index = checkWhichListNodeNotUsed(); + if(index != null){ + index.pageNum = pageNum; + return; + } + + Node lastNode; + if(null == bottom){ + lastNode = last; + }else{ + lastNode = bottom; + } + Node curNode = lastNode.prev; + while(curNode != null){ + lastNode.pageNum = curNode.pageNum; + lastNode = curNode; + curNode = curNode.prev; + } + lastNode.pageNum = pageNum; + return; + } + + /* + * @return ��������ҳ�� pageNum û�б�ʹ�õĽڵ������(����ջ���������)�����ȫ������ʹ�ã��򷵻� null + */ + public Node checkWhichListNodeNotUsed(){ + Node node = first; + Node index = null; + while(node != null){ + if(node.pageNum == -1){ + index = node; + } + node = node.next; + } + return index; + } + + public String toString(){ + StringBuffer buffer = new StringBuffer(); + Node node = first; + while(node != null){ + buffer.append(node.pageNum); + + node = node.next; + if(node != null){ + buffer.append(","); + } + } + return buffer.toString(); + } + + + + + + + + + +} diff --git a/group11/1310368322/src/FourthHomework/jvm/ClassFileLoader.java b/group11/1310368322/src/FourthHomework/jvm/ClassFileLoader.java new file mode 100644 index 0000000000..6db696e5aa --- /dev/null +++ b/group11/1310368322/src/FourthHomework/jvm/ClassFileLoader.java @@ -0,0 +1,51 @@ +package com.coderising.jvm.loader; + +import java.io.BufferedInputStream; +import java.io.DataInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.junit.runners.Parameterized.Parameters; + +public class ClassFileLoader { + private List clzPaths = new ArrayList(); + int countForClassPath = 0; + int countForReadBinaryCode = 0; + byte [] a = new byte[10000]; + + /* ��ָ��·����ȡ�������ļ����������䱣�浽һ���ֽ������У������� + * @Parameters ָ��·�� + * @�ֽ����� + */ + public byte[] readBinaryCode(String className) throws IOException{ + DataInputStream dis = new DataInputStream( + new BufferedInputStream(new FileInputStream(className))); + for(int i = 0; dis.available() != 0; i++){ + a[i] = dis.readByte(); + countForReadBinaryCode++; + } + byte []target = new byte[countForReadBinaryCode]; + System.arraycopy(a, 0, target, 0, countForReadBinaryCode); + dis.close(); + return target; + } + + public void addClassPath(String path){ + clzPaths.add(path); + countForClassPath++; + } + + public String getClassPath(){ + StringBuffer buffer = new StringBuffer(); + for(int i = 0; i < countForClassPath; i++ ){ + if(i==countForClassPath-1){ + buffer.append(clzPaths.get(i)); + }else{ + buffer.append(clzPaths.get(i)+";"); + } + } + return buffer.toString(); + } +} diff --git a/group11/1310368322/src/FourthHomework/jvm/TestJVM.java b/group11/1310368322/src/FourthHomework/jvm/TestJVM.java new file mode 100644 index 0000000000..735e4d1dc2 --- /dev/null +++ b/group11/1310368322/src/FourthHomework/jvm/TestJVM.java @@ -0,0 +1,7 @@ +package com.coderising.jvm.loader; + +public class TestJVM { + public static void main(String[] args) { + System.out.println("Hello"); + } +} diff --git a/group11/1310368322/test/FourthHomework/BaseDataStructure/TestLRUPageFrame.java b/group11/1310368322/test/FourthHomework/BaseDataStructure/TestLRUPageFrame.java new file mode 100644 index 0000000000..227599c187 --- /dev/null +++ b/group11/1310368322/test/FourthHomework/BaseDataStructure/TestLRUPageFrame.java @@ -0,0 +1,31 @@ +package DataStructure_4_LRU; + +import static org.junit.Assert.*; +import org.junit.*; + +import org.junit.Test; + +public class TestLRUPageFrame { + + @Test + public void testAccess() { + LRUPageFrame frame = new LRUPageFrame(3);// ����ҳ��洢����Ϊ3������ҳ�� + frame.access(7); + frame.access(0); + frame.access(1); + Assert.assertEquals("1,0,7",frame.toString()); + frame.access(2); + Assert.assertEquals("2,1,0",frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1",frame.toString()); + frame.access(3); + Assert.assertEquals("3,0,2",frame.toString()); + frame.access(0); + Assert.assertEquals("0,3,2",frame.toString()); + frame.access(4); + Assert.assertEquals("4,0,3",frame.toString()); + } + +} diff --git a/group11/1310368322/test/FourthHomework/JVM/EmployeeV1.java b/group11/1310368322/test/FourthHomework/JVM/EmployeeV1.java new file mode 100644 index 0000000000..acbc34c9bb --- /dev/null +++ b/group11/1310368322/test/FourthHomework/JVM/EmployeeV1.java @@ -0,0 +1,28 @@ +package com.coderising.jvm.loader; + +public class EmployeeV1 { + private String name; + private int age; + + public EmployeeV1(String name, int age){ + this.name = name; + this.age = age; + } + + public void setName(String name){ + this.name = name; + } + + public void setAge(int age){ + this.age = age; + } + + public void sayHello(){ + System.out.println("Hello, this is class Employee"); + } + + public static void main(String[] args) { + EmployeeV1 p = new EmployeeV1("Andy",29); + p.sayHello(); + } +} diff --git a/group11/1310368322/test/FourthHomework/JVM/TestClassFileLoader.java b/group11/1310368322/test/FourthHomework/JVM/TestClassFileLoader.java new file mode 100644 index 0000000000..263384e71a --- /dev/null +++ b/group11/1310368322/test/FourthHomework/JVM/TestClassFileLoader.java @@ -0,0 +1,67 @@ +package com.coderising.jvm.loader; + +import static org.junit.Assert.*; + +import java.io.IOException; + +import org.junit.*; + +public class TestClassFileLoader { + static String path1 = "D:/ProgramWorld"; + static String path2 = "D:/ProgramWorld/Java"; + @Test + public void test() { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + loader.addClassPath(path2); + String clzPath = loader.getClassPath(); + Assert.assertEquals(path1 + ";" + path2, clzPath); + } + @Test + public void testClassFileLength() throws IOException{ + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + + String className = "D:/ProgramWorld/Java/Practice/LangSi/2017������Ⱥ/bin/com/coderising/jvm/loader/EmployeeV1.class"; + + byte[] byteCodes = loader.readBinaryCode(className); + + // ע�⣺ ����ֽ������ܺ����JVM�汾�й�ϵ������Կ�������õ��ൽ���ж�� + Assert.assertEquals(1058,byteCodes.length); + } + @Test + public void testMagicNumber() throws IOException{ + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "D:/ProgramWorld/Java/Practice/LangSi/2017������Ⱥ/bin/com/coderising/jvm/loader/EmployeeV1.class"; + byte[] byteCodes = loader.readBinaryCode(className); + byte[] codes = new byte[]{ + byteCodes[0],byteCodes[1],byteCodes[2],byteCodes[3] + }; + String actualValue = this.byteToHexString(codes); + Assert.assertEquals("cafebabe",actualValue); + + } + + private String byteToHexString(byte[] codes){ + StringBuffer buffer = new StringBuffer(); + for(int i = 0; i < codes.length; i++){ + byte b = codes[i]; + int value = b & 0xFF; + String strHex = Integer.toHexString(value); + if(strHex.length() < 2){ + strHex = "0" + strHex; + } + buffer.append(strHex); + } + return buffer.toString(); + } + + + + + + + + +} From 940cd35cccf649b6500cada71581e0dfad2eb706 Mon Sep 17 00:00:00 2001 From: Ralf_Nick Date: Sat, 1 Apr 2017 23:43:17 +0800 Subject: [PATCH 044/203] =?UTF-8?q?Update=20=E6=96=87=E7=AB=A0=E9=93=BE?= =?UTF-8?q?=E6=8E=A5.txt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../\346\226\207\347\253\240\351\223\276\346\216\245.txt" | 1 + 1 file changed, 1 insertion(+) diff --git "a/group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/\346\226\207\347\253\240\351\223\276\346\216\245.txt" "b/group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/\346\226\207\347\253\240\351\223\276\346\216\245.txt" index e69de29bb2..5516f95009 100644 --- "a/group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/\346\226\207\347\253\240\351\223\276\346\216\245.txt" +++ "b/group20/925290009/\347\254\254\345\233\233\346\254\241\344\275\234\344\270\232/\346\226\207\347\253\240\351\223\276\346\216\245.txt" @@ -0,0 +1 @@ +http://blog.csdn.net/u011371324/article/details/68946779 From ad9f5357d165dd14e82d9471a5185e51f6b1c3a2 Mon Sep 17 00:00:00 2001 From: xukai Date: Sun, 2 Apr 2017 22:09:42 +0800 Subject: [PATCH 045/203] =?UTF-8?q?jvm=E7=AC=AC=E4=B8=80=E6=AC=A1=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A=E5=92=8C=E5=AE=9E=E7=8E=B0LRU=E7=AE=97=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coderising/download/api/Connection.java | 2 - .../download/impl/ConnectionImpl.java | 1 - .../org/xukai/coderising/util/FileUtil.java | 55 +++++++++ .../xukai/common/linklist/LRUPageFrame.java | 107 +++++++++++++++++ .../common/linklist/LRUPageFrameTest.java | 35 ++++++ .../org/xukai/jvm/loader/ClassFileLoader.java | 53 +++++++++ .../xukai/jvm/test/ClassFileloaderTest.java | 112 ++++++++++++++++++ .../java/org/xukai/jvm/test/EmployeeV1.java | 28 +++++ 8 files changed, 390 insertions(+), 3 deletions(-) create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/util/FileUtil.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/common/linklist/LRUPageFrame.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/common/linklist/LRUPageFrameTest.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/loader/ClassFileLoader.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/test/ClassFileloaderTest.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/test/EmployeeV1.java diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/download/api/Connection.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/download/api/Connection.java index 2bcddfcca8..c94d12e92d 100644 --- a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/download/api/Connection.java +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/download/api/Connection.java @@ -1,7 +1,5 @@ package org.xukai.coderising.download.api; -import java.io.IOException; - public interface Connection { /** * 给定开始和结束位置, 读取数据, 返回值是字节数组 diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/download/impl/ConnectionImpl.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/download/impl/ConnectionImpl.java index 8794707fa6..4698bb2825 100644 --- a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/download/impl/ConnectionImpl.java +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/download/impl/ConnectionImpl.java @@ -21,7 +21,6 @@ public byte[] read(int startPos, int endPos) throws ConnectionException { BufferedInputStream inputStream = null; try { urlConnection.setRequestProperty("Range","bytes=" + startPos + "-" + (endPos)); - System.out.println(urlConnection.getResponseCode()); inputStream = new BufferedInputStream(urlConnection.getInputStream()); buff = new byte[endPos-startPos]; int len = 0; diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/util/FileUtil.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/util/FileUtil.java new file mode 100644 index 0000000000..2f511dbb0c --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/util/FileUtil.java @@ -0,0 +1,55 @@ +package org.xukai.coderising.util; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +/** + * @author xukai + * @desc + * @date 2017-04-02-13:22 + */ +public class FileUtil { + + public static byte[] toByteArray(String fileName) throws IOException { + File file = new File(fileName); + return toByteArray(file); + } + + public static byte[] toByteArray(File file) throws IOException { + if (!file.exists()) { + throw new FileNotFoundException(); + } + BufferedInputStream in = new BufferedInputStream(new FileInputStream(file)); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] buff = new byte[1024]; + int len = 0; + try { + while((len = in.read(buff)) != -1){ + out.write(buff,0,len); + } + return out.toByteArray(); + } catch (IOException e) { + e.printStackTrace(); + throw e; + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (out != null) { + try { + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/common/linklist/LRUPageFrame.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/common/linklist/LRUPageFrame.java new file mode 100644 index 0000000000..35bd2f218d --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/common/linklist/LRUPageFrame.java @@ -0,0 +1,107 @@ +package org.xukai.common.linklist; + +/** + * 用双向链表实现LRU算法 + * @author liuxin + * + */ +public class LRUPageFrame { + + private static class Node { + + Node prev; + Node next; + int pageNum; + + Node() { + } + + Node(int pageNum){ + this.pageNum = pageNum; + } + } + + private int capacity; + private int size; + + private Node first;// 链表头 + private Node last;// 链表尾 + + + public LRUPageFrame(int capacity) { + + this.capacity = capacity; + + } + + /** + * 获取缓存中对象 + * + * @param pageNum + * @return + */ + public void access(int pageNum) { + //先遍历,看是否已存在缓存中 + if (first != null) { + Node node = first; + while (node != null){ + if (node.pageNum == pageNum) { + if (node.prev != null) { + node.prev.next = node.next; + if (node.next != null) { + node.next.prev = node.prev; + } else { + last = node.prev; + } + node.next = first; + node.prev = null; + first.prev = node; + first = node; + } + return; + } + node = node.next; + } + } + //遍历不到,插入缓存中,并去除最少用的缓存 + if (last == null) { + if (!(capacity > 0)) { + return; + } + //一开始没有缓存的边界条件 + last = new Node(pageNum); + first = last; + size++; + return; + } + Node node = new Node(pageNum); + node.next = first; + first.prev = node; + first = node; + size++; + if (size > capacity) { + //缓存已满,去除最少用缓存 + Node node2 = last.prev; + node2.next = null; + last = node2; + size--; + } + } + + + + public String toString(){ + StringBuilder buffer = new StringBuilder(); + Node node = first; + while(node != null){ + buffer.append(node.pageNum); + + node = node.next; + if(node != null){ + buffer.append(","); + } + } + return buffer.toString(); + } + +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/common/linklist/LRUPageFrameTest.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/common/linklist/LRUPageFrameTest.java new file mode 100644 index 0000000000..5f09e7fc70 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/common/linklist/LRUPageFrameTest.java @@ -0,0 +1,35 @@ +package org.xukai.common.linklist; + +import org.junit.Assert; + +import org.junit.Test; + + +public class LRUPageFrameTest { + + @Test + public void testAccess() { + LRUPageFrame frame = new LRUPageFrame(3); + frame.access(7); + frame.access(7); + Assert.assertEquals("7", frame.toString()); + frame.access(0); + frame.access(0); + Assert.assertEquals("0,7", frame.toString()); + frame.access(1); + Assert.assertEquals("1,0,7", frame.toString()); + frame.access(2); + Assert.assertEquals("2,1,0", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(3); + Assert.assertEquals("3,0,2", frame.toString()); + frame.access(0); + Assert.assertEquals("0,3,2", frame.toString()); + frame.access(4); + Assert.assertEquals("4,0,3", frame.toString()); + } + +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/loader/ClassFileLoader.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..5f03628651 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/loader/ClassFileLoader.java @@ -0,0 +1,53 @@ +package org.xukai.jvm.loader; + +import com.google.common.base.Joiner; +import com.google.common.base.Splitter; +import org.xukai.coderising.util.FileUtil; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + + + +public class ClassFileLoader { + + private List clzPaths = new ArrayList(); + + public byte[] readBinaryCode(String className) throws IOException, ClassNotFoundException { + for(String classPath : clzPaths){ + File classFile = findClassFile(classPath, className); + if (classFile.exists()) { + return FileUtil.toByteArray(classFile); + } + } + throw new ClassNotFoundException(); + } + + + public void addClassPath(String path) { + if (path != null && !path.trim().equals("")) { + if (!path.endsWith("\\")) { + path = path + "\\"; + } + clzPaths.add(path); + } + } + + + + public String getClassPath(){ + Joiner joiner = Joiner.on(";"); + return joiner.join(clzPaths); + } + + private File findClassFile(String classPath, String className){ + className = className.replaceAll("\\.", "/"); + return new File(classPath + "\\" + className + ".class"); + } + + + + +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/test/ClassFileloaderTest.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..c2112cba9c --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,112 @@ +package org.xukai.jvm.test; + +import com.google.common.base.Splitter; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.xukai.coderising.util.FileUtil; +import org.xukai.jvm.loader.ClassFileLoader; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.channels.FileChannel; + + +public class ClassFileloaderTest { + + + static String path1 = "D:\\java\\IDEA-Workspace\\coding2017\\group19\\527220084\\xukai_coding\\coding-common\\target\\classes"; + static String path2 = "C:\temp"; + + + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testClassPath(){ + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + loader.addClassPath(path2); + + String clzPath = loader.getClassPath(); + + Assert.assertEquals(path1+";"+path2,clzPath); + + } + + @Test + public void testClassFileLength() throws IOException, ClassNotFoundException { + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + + String className = "org.xukai.jvm.test.EmployeeV1"; + + byte[] byteCodes = loader.readBinaryCode(className); + + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + Assert.assertEquals(1046, byteCodes.length); + + } + + + @Test + public void testMagicNumber() throws IOException, ClassNotFoundException { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "org.xukai.jvm.test.EmployeeV1"; + byte[] byteCodes = loader.readBinaryCode(className); + byte[] codes = new byte[]{byteCodes[0],byteCodes[1],byteCodes[2],byteCodes[3]}; + + + String acctualValue = this.byteToHexString(codes); + + Assert.assertEquals("cafebabe", acctualValue); + } + + private File findClassFile(String classPath, String className){ + className = className.replaceAll("\\.", "/"); + System.out.println(classPath + "\\" + className + ".class"); + return new File(classPath + "\\" + className + ".class"); + } + + @Test + public void testFile() throws IOException { + File file = findClassFile(path1, "org.xukai.jvm.test.EmployeeV1"); + Assert.assertTrue(file.exists()); + byte[] bytes = FileUtil.toByteArray(file); + System.out.println(bytes.length); + } + + + + + private String byteToHexString(byte[] codes ){ + StringBuffer buffer = new StringBuffer(); + for(int i=0;i Date: Mon, 3 Apr 2017 12:41:45 +0800 Subject: [PATCH 046/203] c --- group15/1511_714512544/.idea/workspace.xml | 50 +++++++++------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/group15/1511_714512544/.idea/workspace.xml b/group15/1511_714512544/.idea/workspace.xml index 9cd6e9b941..8858b7e84c 100644 --- a/group15/1511_714512544/.idea/workspace.xml +++ b/group15/1511_714512544/.idea/workspace.xml @@ -3,8 +3,6 @@ - - - + @@ -199,6 +197,18 @@ + + + @@ -770,6 +780,7 @@ + 1488937445293 @@ -877,7 +888,7 @@ - @@ -890,7 +901,6 @@ - @@ -900,20 +910,20 @@ - + - + - + @@ -1215,24 +1225,6 @@ - - - - - - - - - - - - - - - - - - From 9b1c2357d2f46475f6110f9bcb84175711c4546e Mon Sep 17 00:00:00 2001 From: 592146505 <592146505@qq.com> Date: Mon, 3 Apr 2017 13:32:03 +0800 Subject: [PATCH 047/203] =?UTF-8?q?=E6=95=B4=E7=90=86=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E7=BB=93=E6=9E=84=EF=BC=8C=E6=8F=90=E4=BA=A4mini-jvm=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/wsc/coderising/litestruts/struts.xml | 11 -- .../coderising/download/DownloadThread.java | 0 .../coderising/download/FileDownloader.java | 0 .../download/FileDownloaderTest.java | 0 .../coderising/download/api/Connection.java | 0 .../download/api/ConnectionException.java | 0 .../download/api/ConnectionManager.java | 0 .../download/api/DownloadListener.java | 0 .../download/impl/ConnectionImpl.java | 0 .../download/impl/ConnectionManagerImpl.java | 0 .../org/wsc/coderising/litestruts/Action.java | 0 .../coderising/litestruts/LoginAction.java | 0 .../org/wsc/coderising/litestruts/Struts.java | 0 .../wsc/coderising/litestruts/StrutsTest.java | 0 .../org/wsc/coderising/litestruts/View.java | 0 .../litestruts/util/DocumentUtil.java | 0 .../wsc/coding/basic}/array/ArrayUtil.java | 2 +- .../coding/basic}/array/ArrayUtilTest.java | 2 +- .../basic/exception/NullElementException.java | 0 .../exception/RepeatingElementException.java | 0 .../coding/basic/linklist/LRUPageFrame.java | 139 ++++++++++++++++++ .../basic/linklist/LRUPageFrameTest.java | 29 ++++ .../org/wsc/coding/basic/list/ArrayList.java | 0 .../org/wsc/coding/basic/list/Iterator.java | 0 .../org/wsc/coding/basic/list/LinkedList.java | 0 .../src/org/wsc/coding/basic/list/List.java | 0 .../wsc/coding/basic/list/MyLinkedList.java | 0 .../src/org/wsc/coding/basic/list/Queue.java | 0 .../src/org/wsc/coding/basic/stack/Stack.java | 0 .../basic/tree_node/BinaryTreeNode.java | 0 .../jvm/loader/ClassFileLoader.java | 75 ++++++++++ .../jvm/test/ClassFileloaderTest.java | 79 ++++++++++ .../wsc/coderising/jvm/test/EmployeeV1.java | 30 ++++ 33 files changed, 354 insertions(+), 13 deletions(-) delete mode 100644 group20/592146505/592146505Learning/src/org/wsc/coderising/litestruts/struts.xml rename group20/592146505/{592146505Learning => data-structure}/src/org/wsc/coderising/download/DownloadThread.java (100%) rename group20/592146505/{592146505Learning => data-structure}/src/org/wsc/coderising/download/FileDownloader.java (100%) rename group20/592146505/{592146505Learning => data-structure}/src/org/wsc/coderising/download/FileDownloaderTest.java (100%) rename group20/592146505/{592146505Learning => data-structure}/src/org/wsc/coderising/download/api/Connection.java (100%) rename group20/592146505/{592146505Learning => data-structure}/src/org/wsc/coderising/download/api/ConnectionException.java (100%) rename group20/592146505/{592146505Learning => data-structure}/src/org/wsc/coderising/download/api/ConnectionManager.java (100%) rename group20/592146505/{592146505Learning => data-structure}/src/org/wsc/coderising/download/api/DownloadListener.java (100%) rename group20/592146505/{592146505Learning => data-structure}/src/org/wsc/coderising/download/impl/ConnectionImpl.java (100%) rename group20/592146505/{592146505Learning => data-structure}/src/org/wsc/coderising/download/impl/ConnectionManagerImpl.java (100%) rename group20/592146505/{592146505Learning => data-structure}/src/org/wsc/coderising/litestruts/Action.java (100%) rename group20/592146505/{592146505Learning => data-structure}/src/org/wsc/coderising/litestruts/LoginAction.java (100%) rename group20/592146505/{592146505Learning => data-structure}/src/org/wsc/coderising/litestruts/Struts.java (100%) rename group20/592146505/{592146505Learning => data-structure}/src/org/wsc/coderising/litestruts/StrutsTest.java (100%) rename group20/592146505/{592146505Learning => data-structure}/src/org/wsc/coderising/litestruts/View.java (100%) rename group20/592146505/{592146505Learning => data-structure}/src/org/wsc/coderising/litestruts/util/DocumentUtil.java (100%) rename group20/592146505/{592146505Learning/src/org/wsc/coderising => data-structure/src/org/wsc/coding/basic}/array/ArrayUtil.java (99%) rename group20/592146505/{592146505Learning/src/org/wsc/coderising => data-structure/src/org/wsc/coding/basic}/array/ArrayUtilTest.java (98%) rename group20/592146505/{592146505Learning => data-structure}/src/org/wsc/coding/basic/exception/NullElementException.java (100%) rename group20/592146505/{592146505Learning => data-structure}/src/org/wsc/coding/basic/exception/RepeatingElementException.java (100%) create mode 100644 group20/592146505/data-structure/src/org/wsc/coding/basic/linklist/LRUPageFrame.java create mode 100644 group20/592146505/data-structure/src/org/wsc/coding/basic/linklist/LRUPageFrameTest.java rename group20/592146505/{592146505Learning => data-structure}/src/org/wsc/coding/basic/list/ArrayList.java (100%) rename group20/592146505/{592146505Learning => data-structure}/src/org/wsc/coding/basic/list/Iterator.java (100%) rename group20/592146505/{592146505Learning => data-structure}/src/org/wsc/coding/basic/list/LinkedList.java (100%) rename group20/592146505/{592146505Learning => data-structure}/src/org/wsc/coding/basic/list/List.java (100%) rename group20/592146505/{592146505Learning => data-structure}/src/org/wsc/coding/basic/list/MyLinkedList.java (100%) rename group20/592146505/{592146505Learning => data-structure}/src/org/wsc/coding/basic/list/Queue.java (100%) rename group20/592146505/{592146505Learning => data-structure}/src/org/wsc/coding/basic/stack/Stack.java (100%) rename group20/592146505/{592146505Learning => data-structure}/src/org/wsc/coding/basic/tree_node/BinaryTreeNode.java (100%) create mode 100644 group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/loader/ClassFileLoader.java create mode 100644 group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/test/ClassFileloaderTest.java create mode 100644 group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/test/EmployeeV1.java diff --git a/group20/592146505/592146505Learning/src/org/wsc/coderising/litestruts/struts.xml b/group20/592146505/592146505Learning/src/org/wsc/coderising/litestruts/struts.xml deleted file mode 100644 index b709ec6636..0000000000 --- a/group20/592146505/592146505Learning/src/org/wsc/coderising/litestruts/struts.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - /jsp/homepage.jsp - /jsp/showLogin.jsp - - - /jsp/welcome.jsp - /jsp/error.jsp - - \ No newline at end of file diff --git a/group20/592146505/592146505Learning/src/org/wsc/coderising/download/DownloadThread.java b/group20/592146505/data-structure/src/org/wsc/coderising/download/DownloadThread.java similarity index 100% rename from group20/592146505/592146505Learning/src/org/wsc/coderising/download/DownloadThread.java rename to group20/592146505/data-structure/src/org/wsc/coderising/download/DownloadThread.java diff --git a/group20/592146505/592146505Learning/src/org/wsc/coderising/download/FileDownloader.java b/group20/592146505/data-structure/src/org/wsc/coderising/download/FileDownloader.java similarity index 100% rename from group20/592146505/592146505Learning/src/org/wsc/coderising/download/FileDownloader.java rename to group20/592146505/data-structure/src/org/wsc/coderising/download/FileDownloader.java diff --git a/group20/592146505/592146505Learning/src/org/wsc/coderising/download/FileDownloaderTest.java b/group20/592146505/data-structure/src/org/wsc/coderising/download/FileDownloaderTest.java similarity index 100% rename from group20/592146505/592146505Learning/src/org/wsc/coderising/download/FileDownloaderTest.java rename to group20/592146505/data-structure/src/org/wsc/coderising/download/FileDownloaderTest.java diff --git a/group20/592146505/592146505Learning/src/org/wsc/coderising/download/api/Connection.java b/group20/592146505/data-structure/src/org/wsc/coderising/download/api/Connection.java similarity index 100% rename from group20/592146505/592146505Learning/src/org/wsc/coderising/download/api/Connection.java rename to group20/592146505/data-structure/src/org/wsc/coderising/download/api/Connection.java diff --git a/group20/592146505/592146505Learning/src/org/wsc/coderising/download/api/ConnectionException.java b/group20/592146505/data-structure/src/org/wsc/coderising/download/api/ConnectionException.java similarity index 100% rename from group20/592146505/592146505Learning/src/org/wsc/coderising/download/api/ConnectionException.java rename to group20/592146505/data-structure/src/org/wsc/coderising/download/api/ConnectionException.java diff --git a/group20/592146505/592146505Learning/src/org/wsc/coderising/download/api/ConnectionManager.java b/group20/592146505/data-structure/src/org/wsc/coderising/download/api/ConnectionManager.java similarity index 100% rename from group20/592146505/592146505Learning/src/org/wsc/coderising/download/api/ConnectionManager.java rename to group20/592146505/data-structure/src/org/wsc/coderising/download/api/ConnectionManager.java diff --git a/group20/592146505/592146505Learning/src/org/wsc/coderising/download/api/DownloadListener.java b/group20/592146505/data-structure/src/org/wsc/coderising/download/api/DownloadListener.java similarity index 100% rename from group20/592146505/592146505Learning/src/org/wsc/coderising/download/api/DownloadListener.java rename to group20/592146505/data-structure/src/org/wsc/coderising/download/api/DownloadListener.java diff --git a/group20/592146505/592146505Learning/src/org/wsc/coderising/download/impl/ConnectionImpl.java b/group20/592146505/data-structure/src/org/wsc/coderising/download/impl/ConnectionImpl.java similarity index 100% rename from group20/592146505/592146505Learning/src/org/wsc/coderising/download/impl/ConnectionImpl.java rename to group20/592146505/data-structure/src/org/wsc/coderising/download/impl/ConnectionImpl.java diff --git a/group20/592146505/592146505Learning/src/org/wsc/coderising/download/impl/ConnectionManagerImpl.java b/group20/592146505/data-structure/src/org/wsc/coderising/download/impl/ConnectionManagerImpl.java similarity index 100% rename from group20/592146505/592146505Learning/src/org/wsc/coderising/download/impl/ConnectionManagerImpl.java rename to group20/592146505/data-structure/src/org/wsc/coderising/download/impl/ConnectionManagerImpl.java diff --git a/group20/592146505/592146505Learning/src/org/wsc/coderising/litestruts/Action.java b/group20/592146505/data-structure/src/org/wsc/coderising/litestruts/Action.java similarity index 100% rename from group20/592146505/592146505Learning/src/org/wsc/coderising/litestruts/Action.java rename to group20/592146505/data-structure/src/org/wsc/coderising/litestruts/Action.java diff --git a/group20/592146505/592146505Learning/src/org/wsc/coderising/litestruts/LoginAction.java b/group20/592146505/data-structure/src/org/wsc/coderising/litestruts/LoginAction.java similarity index 100% rename from group20/592146505/592146505Learning/src/org/wsc/coderising/litestruts/LoginAction.java rename to group20/592146505/data-structure/src/org/wsc/coderising/litestruts/LoginAction.java diff --git a/group20/592146505/592146505Learning/src/org/wsc/coderising/litestruts/Struts.java b/group20/592146505/data-structure/src/org/wsc/coderising/litestruts/Struts.java similarity index 100% rename from group20/592146505/592146505Learning/src/org/wsc/coderising/litestruts/Struts.java rename to group20/592146505/data-structure/src/org/wsc/coderising/litestruts/Struts.java diff --git a/group20/592146505/592146505Learning/src/org/wsc/coderising/litestruts/StrutsTest.java b/group20/592146505/data-structure/src/org/wsc/coderising/litestruts/StrutsTest.java similarity index 100% rename from group20/592146505/592146505Learning/src/org/wsc/coderising/litestruts/StrutsTest.java rename to group20/592146505/data-structure/src/org/wsc/coderising/litestruts/StrutsTest.java diff --git a/group20/592146505/592146505Learning/src/org/wsc/coderising/litestruts/View.java b/group20/592146505/data-structure/src/org/wsc/coderising/litestruts/View.java similarity index 100% rename from group20/592146505/592146505Learning/src/org/wsc/coderising/litestruts/View.java rename to group20/592146505/data-structure/src/org/wsc/coderising/litestruts/View.java diff --git a/group20/592146505/592146505Learning/src/org/wsc/coderising/litestruts/util/DocumentUtil.java b/group20/592146505/data-structure/src/org/wsc/coderising/litestruts/util/DocumentUtil.java similarity index 100% rename from group20/592146505/592146505Learning/src/org/wsc/coderising/litestruts/util/DocumentUtil.java rename to group20/592146505/data-structure/src/org/wsc/coderising/litestruts/util/DocumentUtil.java diff --git a/group20/592146505/592146505Learning/src/org/wsc/coderising/array/ArrayUtil.java b/group20/592146505/data-structure/src/org/wsc/coding/basic/array/ArrayUtil.java similarity index 99% rename from group20/592146505/592146505Learning/src/org/wsc/coderising/array/ArrayUtil.java rename to group20/592146505/data-structure/src/org/wsc/coding/basic/array/ArrayUtil.java index 3caef64d35..220f88888a 100644 --- a/group20/592146505/592146505Learning/src/org/wsc/coderising/array/ArrayUtil.java +++ b/group20/592146505/data-structure/src/org/wsc/coding/basic/array/ArrayUtil.java @@ -1,4 +1,4 @@ -package org.wsc.coderising.array; +package org.wsc.coding.basic.array; public class ArrayUtil { /** diff --git a/group20/592146505/592146505Learning/src/org/wsc/coderising/array/ArrayUtilTest.java b/group20/592146505/data-structure/src/org/wsc/coding/basic/array/ArrayUtilTest.java similarity index 98% rename from group20/592146505/592146505Learning/src/org/wsc/coderising/array/ArrayUtilTest.java rename to group20/592146505/data-structure/src/org/wsc/coding/basic/array/ArrayUtilTest.java index e459aa175f..cc2641eb14 100644 --- a/group20/592146505/592146505Learning/src/org/wsc/coderising/array/ArrayUtilTest.java +++ b/group20/592146505/data-structure/src/org/wsc/coding/basic/array/ArrayUtilTest.java @@ -1,4 +1,4 @@ -package org.wsc.coderising.array; +package org.wsc.coding.basic.array; import static org.junit.Assert.*; diff --git a/group20/592146505/592146505Learning/src/org/wsc/coding/basic/exception/NullElementException.java b/group20/592146505/data-structure/src/org/wsc/coding/basic/exception/NullElementException.java similarity index 100% rename from group20/592146505/592146505Learning/src/org/wsc/coding/basic/exception/NullElementException.java rename to group20/592146505/data-structure/src/org/wsc/coding/basic/exception/NullElementException.java diff --git a/group20/592146505/592146505Learning/src/org/wsc/coding/basic/exception/RepeatingElementException.java b/group20/592146505/data-structure/src/org/wsc/coding/basic/exception/RepeatingElementException.java similarity index 100% rename from group20/592146505/592146505Learning/src/org/wsc/coding/basic/exception/RepeatingElementException.java rename to group20/592146505/data-structure/src/org/wsc/coding/basic/exception/RepeatingElementException.java diff --git a/group20/592146505/data-structure/src/org/wsc/coding/basic/linklist/LRUPageFrame.java b/group20/592146505/data-structure/src/org/wsc/coding/basic/linklist/LRUPageFrame.java new file mode 100644 index 0000000000..44ae0e3d05 --- /dev/null +++ b/group20/592146505/data-structure/src/org/wsc/coding/basic/linklist/LRUPageFrame.java @@ -0,0 +1,139 @@ +package org.wsc.coding.basic.linklist; + +/** + *

LRU算法

+ *

+ * 最近最少使用 + *

+ * + * @author Administrator + * @date 2017年3月28日上午10:56:33 + * @version v1.0 + * + */ +public class LRUPageFrame { + + private static class Node { + + Node prev; + int pageNum; + Node next; + + Node() { + } + + Node(Node prev, int pageNum, Node next) { + super(); + this.prev = prev; + this.pageNum = pageNum; + this.next = next; + } + + } + + private int capacity; + private Node first;// 链表头 + private Node last;// 链表尾 + private int size;// 长度 + + public LRUPageFrame(int capacity) { + this.capacity = capacity; + } + + /** + * 获取缓存中对象 + * + * @param key + * @return + */ + public void access(int pageNum) { + // 首先检查链表中是否已存在改页码 + Node node = find(pageNum); + if (node == null) { + // 满则删除尾部后插入 + if (isFull()) + unlinkLast(); + put(pageNum); + } else { + Node prev = node.prev; + Node next = node.next; + Node oldFirst = first; + if(prev != null){ + first = node; + prev.next = next; + node.prev = null; + node.next = oldFirst; + oldFirst.prev = node; + if(next == null) + last = prev; + else + next.prev = prev; + + } + } + + } + + /** + * 添加至头节点 + * + * @param pageNum + */ + void put(int pageNum) { + Node oldFirst = first; + Node newNode = new Node(null, pageNum, oldFirst); + first = newNode; + if (oldFirst == null) { + last = newNode; + } else { + oldFirst.prev = newNode; + } + size++; + } + + /** + * 删除尾节点 + */ + void unlinkLast() { + Node oldLast = last; + Node prev = oldLast.prev; + if (oldLast != null) { + if (prev == null) + first = null; + else { + prev.next = null; + } + last = prev; + } + size--; + } + + Node find(int pageNum) { + Node node = last; + while (node != null) { + if (node.pageNum == pageNum) + return node; + node = node.prev; + } + return node; + } + + boolean isFull() { + return size == capacity ? true : false; + + } + + public String toString() { + StringBuilder buffer = new StringBuilder(); + Node node = first; + while (node != null) { + buffer.append(node.pageNum); + + node = node.next; + if (node != null) { + buffer.append(","); + } + } + return buffer.toString(); + } +} diff --git a/group20/592146505/data-structure/src/org/wsc/coding/basic/linklist/LRUPageFrameTest.java b/group20/592146505/data-structure/src/org/wsc/coding/basic/linklist/LRUPageFrameTest.java new file mode 100644 index 0000000000..c496b6c023 --- /dev/null +++ b/group20/592146505/data-structure/src/org/wsc/coding/basic/linklist/LRUPageFrameTest.java @@ -0,0 +1,29 @@ +package org.wsc.coding.basic.linklist; + +import org.junit.Assert; +import org.junit.Test; + +public class LRUPageFrameTest { + + @Test + public void testAccess() { + LRUPageFrame frame = new LRUPageFrame(3); + frame.access(7); + frame.access(0); + frame.access(1); + Assert.assertEquals("1,0,7", frame.toString()); + frame.access(2); + Assert.assertEquals("2,1,0", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(3); + Assert.assertEquals("3,0,2", frame.toString()); + frame.access(0); + Assert.assertEquals("0,3,2", frame.toString()); + frame.access(4); + Assert.assertEquals("4,0,3", frame.toString()); + } + +} diff --git a/group20/592146505/592146505Learning/src/org/wsc/coding/basic/list/ArrayList.java b/group20/592146505/data-structure/src/org/wsc/coding/basic/list/ArrayList.java similarity index 100% rename from group20/592146505/592146505Learning/src/org/wsc/coding/basic/list/ArrayList.java rename to group20/592146505/data-structure/src/org/wsc/coding/basic/list/ArrayList.java diff --git a/group20/592146505/592146505Learning/src/org/wsc/coding/basic/list/Iterator.java b/group20/592146505/data-structure/src/org/wsc/coding/basic/list/Iterator.java similarity index 100% rename from group20/592146505/592146505Learning/src/org/wsc/coding/basic/list/Iterator.java rename to group20/592146505/data-structure/src/org/wsc/coding/basic/list/Iterator.java diff --git a/group20/592146505/592146505Learning/src/org/wsc/coding/basic/list/LinkedList.java b/group20/592146505/data-structure/src/org/wsc/coding/basic/list/LinkedList.java similarity index 100% rename from group20/592146505/592146505Learning/src/org/wsc/coding/basic/list/LinkedList.java rename to group20/592146505/data-structure/src/org/wsc/coding/basic/list/LinkedList.java diff --git a/group20/592146505/592146505Learning/src/org/wsc/coding/basic/list/List.java b/group20/592146505/data-structure/src/org/wsc/coding/basic/list/List.java similarity index 100% rename from group20/592146505/592146505Learning/src/org/wsc/coding/basic/list/List.java rename to group20/592146505/data-structure/src/org/wsc/coding/basic/list/List.java diff --git a/group20/592146505/592146505Learning/src/org/wsc/coding/basic/list/MyLinkedList.java b/group20/592146505/data-structure/src/org/wsc/coding/basic/list/MyLinkedList.java similarity index 100% rename from group20/592146505/592146505Learning/src/org/wsc/coding/basic/list/MyLinkedList.java rename to group20/592146505/data-structure/src/org/wsc/coding/basic/list/MyLinkedList.java diff --git a/group20/592146505/592146505Learning/src/org/wsc/coding/basic/list/Queue.java b/group20/592146505/data-structure/src/org/wsc/coding/basic/list/Queue.java similarity index 100% rename from group20/592146505/592146505Learning/src/org/wsc/coding/basic/list/Queue.java rename to group20/592146505/data-structure/src/org/wsc/coding/basic/list/Queue.java diff --git a/group20/592146505/592146505Learning/src/org/wsc/coding/basic/stack/Stack.java b/group20/592146505/data-structure/src/org/wsc/coding/basic/stack/Stack.java similarity index 100% rename from group20/592146505/592146505Learning/src/org/wsc/coding/basic/stack/Stack.java rename to group20/592146505/data-structure/src/org/wsc/coding/basic/stack/Stack.java diff --git a/group20/592146505/592146505Learning/src/org/wsc/coding/basic/tree_node/BinaryTreeNode.java b/group20/592146505/data-structure/src/org/wsc/coding/basic/tree_node/BinaryTreeNode.java similarity index 100% rename from group20/592146505/592146505Learning/src/org/wsc/coding/basic/tree_node/BinaryTreeNode.java rename to group20/592146505/data-structure/src/org/wsc/coding/basic/tree_node/BinaryTreeNode.java diff --git a/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/loader/ClassFileLoader.java b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..6732cf28c7 --- /dev/null +++ b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,75 @@ +package org.wsc.coderising.jvm.loader; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class ClassFileLoader { + + private List clzPaths = new ArrayList(); + /** 默认缓冲大小 */ + private final static int DEFAULT_SIZE = 32; + DataInputStream dis; + private ByteArrayOutputStream baos; + + public byte[] readBinaryCode(String className) throws ClassNotFoundException, IOException { + byte[] buffer = null; + File file = null; + for (String clzPath : clzPaths) { + clzPath += "/" + className.replace(".", "/") + ".class"; + file = new File(clzPath); + if (file.exists()) + buffer = getFileToByte(new File(clzPath)); + close(); + } + if (buffer == null) { + throw new ClassNotFoundException(); + } + return buffer; + + } + + public void addClassPath(String path) { + clzPaths.add(path); + } + + public String getClassPath() { + StringBuffer clzPath = new StringBuffer(); + for (int i = 0; i < clzPaths.size(); i++) { + clzPath.append(clzPaths.get(i)); + if (i < clzPaths.size() - 1) + clzPath.append(";"); + } + return clzPath.toString(); + } + + private byte[] getFileToByte(File file) throws IOException { + byte[] buffer = new byte[DEFAULT_SIZE]; + dis = new DataInputStream(new FileInputStream(file)); + baos = new ByteArrayOutputStream(); + int lenth; + // 读取 + while ((lenth = dis.read(buffer)) != -1) { + baos.write(buffer, 0, lenth); + } + return baos.toByteArray(); + } + + private void close() { + try { + if (dis != null) { + dis.close(); + } + if (baos != null) { + baos.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + +} diff --git a/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/test/ClassFileloaderTest.java b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..e3dabb26ab --- /dev/null +++ b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,79 @@ +package org.wsc.coderising.jvm.test; + +import java.io.IOException; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.wsc.coderising.jvm.loader.ClassFileLoader; + +public class ClassFileloaderTest { + + static String path1 = "./bin"; + static String path2 = "C:/temp"; + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testClassPath() { + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + loader.addClassPath(path2); + + String clzPath = loader.getClassPath(); + + Assert.assertEquals(path1 + ";" + path2, clzPath); + + } + + @Test + public void testClassFileLength() throws ClassNotFoundException, IOException { + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + + String className = "org.wsc.coderising.jvm.test.EmployeeV1"; + + byte[] byteCodes = loader.readBinaryCode(className); + + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + Assert.assertEquals(1064, byteCodes.length); + + } + + @Test + public void testMagicNumber() throws ClassNotFoundException, IOException { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "org.wsc.coderising.jvm.test.EmployeeV1"; + byte[] byteCodes = loader.readBinaryCode(className); + byte[] codes = new byte[] { byteCodes[0], byteCodes[1], byteCodes[2], byteCodes[3] }; + + String acctualValue = this.byteToHexString(codes); + + Assert.assertEquals("cafebabe", acctualValue); + } + + private String byteToHexString(byte[] codes) { + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < codes.length; i++) { + byte b = codes[i]; + int value = b & 0xFF; + String strHex = Integer.toHexString(value); + if (strHex.length() < 2) { + strHex = "0" + strHex; + } + buffer.append(strHex); + } + return buffer.toString(); + } + +} diff --git a/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/test/EmployeeV1.java b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..13f562506b --- /dev/null +++ b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/test/EmployeeV1.java @@ -0,0 +1,30 @@ +package org.wsc.coderising.jvm.test; + +public class EmployeeV1 { + + private String name; + private int age; + + public EmployeeV1(String name, int age) { + this.name = name; + this.age = age; + } + + public void setName(String name) { + this.name = name; + } + + public void setAge(int age) { + this.age = age; + } + + public void sayHello() { + System.out.println("Hello , this is class Employee "); + } + + public static void main(String[] args) { + EmployeeV1 p = new EmployeeV1("Andy", 29); + p.sayHello(); + + } +} \ No newline at end of file From d52a65677809d31c07414e24f6292dba84e3598d Mon Sep 17 00:00:00 2001 From: wdn <626451284@163.com> Date: Mon, 3 Apr 2017 14:44:47 +0800 Subject: [PATCH 048/203] =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=A4=9A=E7=BA=BF?= =?UTF-8?q?=E7=A8=8B=E4=B8=8B=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coderising/download/DownloadThread.java | 48 +++++++++++++++--- .../coderising/download/FileDownloader.java | 45 +++++++++++------ .../download/FileDownloaderTest.java | 10 ++-- .../coderising/download/api/Connection.java | 6 ++- .../download/api/ConnectionException.java | 2 +- .../download/api/ConnectionManager.java | 2 +- .../download/api/DownloadListener.java | 2 +- .../download/impl/ConnectionImpl.java | 50 +++++++++++++++---- .../download/impl/ConnectionManagerImpl.java | 21 ++++++-- 9 files changed, 138 insertions(+), 48 deletions(-) diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/DownloadThread.java b/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/DownloadThread.java index 900a3ad358..7238acf44d 100644 --- a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/DownloadThread.java +++ b/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/DownloadThread.java @@ -1,20 +1,54 @@ -package com.coderising.download; +package com.github.wdn.coding2017.coderising.download; -import com.coderising.download.api.Connection; + +import com.github.wdn.coding2017.coderising.download.api.Connection; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.concurrent.CountDownLatch; public class DownloadThread extends Thread{ Connection conn; int startPos; int endPos; - - public DownloadThread( Connection conn, int startPos, int endPos){ - + private static final Object lock = new Object(); + private static final File file = new File("E:\\down.jpg"); + private CountDownLatch latch; + public DownloadThread(Connection conn, int startPos, int endPos,CountDownLatch latch){ this.conn = conn; this.startPos = startPos; this.endPos = endPos; + this.latch = latch; + } + public boolean writeFile(){ + if (file.length()==startPos) { + synchronized (lock){ + byte[] image = new byte[0]; + try { + image = conn.read(startPos, endPos); + FileOutputStream fos = new FileOutputStream(file,true); + fos.write(image); + fos.close(); + return true; + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } + }else{ + return false; + } } - public void run(){ - + public void run(){ + while (!writeFile()){ + try { + Thread.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + latch.countDown(); } } diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/FileDownloader.java b/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/FileDownloader.java index c3c8a3f27d..ca3709a549 100644 --- a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/FileDownloader.java +++ b/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/FileDownloader.java @@ -1,10 +1,14 @@ -package com.coderising.download; +package com.github.wdn.coding2017.coderising.download; -import com.coderising.download.api.Connection; -import com.coderising.download.api.ConnectionException; -import com.coderising.download.api.ConnectionManager; -import com.coderising.download.api.DownloadListener; +import com.github.wdn.coding2017.coderising.download.api.Connection; +import com.github.wdn.coding2017.coderising.download.api.ConnectionException; +import com.github.wdn.coding2017.coderising.download.api.ConnectionManager; +import com.github.wdn.coding2017.coderising.download.api.DownloadListener; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.concurrent.CountDownLatch; public class FileDownloader { @@ -35,25 +39,34 @@ public void execute(){ // 下面的代码是示例代码, 也就是说只有一个线程, 你需要改造成多线程的。 Connection conn = null; + try { - conn = cm.open(this.url); - - int length = conn.getContentLength(); - - new DownloadThread(conn,0,length-1).start(); - - } catch (ConnectionException e) { + int threadSum = 4; + final CountDownLatch latch = new CountDownLatch(threadSum); + int length = conn.getContentLength(); + if(length<=1024){ + new DownloadThread(cm.open(this.url),0,length,latch).start(); + }else{ + int partLength = length/threadSum; + for (int i = 0; i < threadSum; i++) { + if(i==threadSum-1){ + new DownloadThread(cm.open(this.url),i*partLength,length,latch).start(); + }else{ + new DownloadThread(cm.open(this.url),i*partLength,i*partLength+partLength,latch).start(); + } + + } + } + latch.await(); + listener.notifyFinished(); + } catch (Exception e) { e.printStackTrace(); }finally{ if(conn != null){ conn.close(); } } - - - - } public void setListener(DownloadListener listener) { diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/FileDownloaderTest.java b/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/FileDownloaderTest.java index 4ff7f46ae0..8ca48ad471 100644 --- a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/FileDownloaderTest.java +++ b/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/FileDownloaderTest.java @@ -1,12 +1,12 @@ -package com.coderising.download; +package com.github.wdn.coding2017.coderising.download; +import com.github.wdn.coding2017.coderising.download.api.ConnectionManager; +import com.github.wdn.coding2017.coderising.download.api.DownloadListener; +import com.github.wdn.coding2017.coderising.download.impl.ConnectionManagerImpl; import org.junit.After; import org.junit.Before; import org.junit.Test; -import com.coderising.download.api.ConnectionManager; -import com.coderising.download.api.DownloadListener; -import com.coderising.download.impl.ConnectionManagerImpl; public class FileDownloaderTest { boolean downloadFinished = false; @@ -21,7 +21,7 @@ public void tearDown() throws Exception { @Test public void testDownload() { - String url = "http://localhost:8080/test.jpg"; + String url = "http://pic1.win4000.com/wallpaper/9/58dcbb7ee7de0.jpg"; FileDownloader downloader = new FileDownloader(url); diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/api/Connection.java b/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/api/Connection.java index 0957eaf7f4..8b0e057a32 100644 --- a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/api/Connection.java +++ b/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/api/Connection.java @@ -1,6 +1,7 @@ -package com.coderising.download.api; +package com.github.wdn.coding2017.coderising.download.api; import java.io.IOException; +import java.net.HttpURLConnection; public interface Connection { /** @@ -20,4 +21,7 @@ public interface Connection { * 关闭连接 */ public void close(); + + + void setHttpURLConnection(HttpURLConnection httpURLConnection); } diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/api/ConnectionException.java b/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/api/ConnectionException.java index 1551a80b3d..5c90080401 100644 --- a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/api/ConnectionException.java +++ b/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/api/ConnectionException.java @@ -1,4 +1,4 @@ -package com.coderising.download.api; +package com.github.wdn.coding2017.coderising.download.api; public class ConnectionException extends Exception { diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/api/ConnectionManager.java b/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/api/ConnectionManager.java index ce045393b1..f814016839 100644 --- a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/api/ConnectionManager.java +++ b/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/api/ConnectionManager.java @@ -1,4 +1,4 @@ -package com.coderising.download.api; +package com.github.wdn.coding2017.coderising.download.api; public interface ConnectionManager { /** diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/api/DownloadListener.java b/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/api/DownloadListener.java index bf9807b307..078b14365d 100644 --- a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/api/DownloadListener.java +++ b/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/api/DownloadListener.java @@ -1,4 +1,4 @@ -package com.coderising.download.api; +package com.github.wdn.coding2017.coderising.download.api; public interface DownloadListener { public void notifyFinished(); diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/impl/ConnectionImpl.java b/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/impl/ConnectionImpl.java index 36a9d2ce15..7f9e090a1e 100644 --- a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/impl/ConnectionImpl.java +++ b/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/impl/ConnectionImpl.java @@ -1,27 +1,55 @@ -package com.coderising.download.impl; +package com.github.wdn.coding2017.coderising.download.impl; -import java.io.IOException; +import com.github.wdn.coding2017.coderising.download.api.Connection; -import com.coderising.download.api.Connection; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.util.Arrays; -public class ConnectionImpl implements Connection{ +public class ConnectionImpl implements Connection { + HttpURLConnection connection; @Override public byte[] read(int startPos, int endPos) throws IOException { - - return null; + if (connection == null) { + throw new IllegalArgumentException("connection is null"); + } + int code = connection.getResponseCode(); + ByteArrayOutputStream baos=null; + InputStream is=null; + if(code==200){ + //5读取服务器资源的流 + is= connection.getInputStream(); + //准备内存输出流 临时存储的 + baos = new ByteArrayOutputStream(); + byte buff[] = new byte[1024]; + int len=0; + int sum = 0; + while((len=is.read(buff))!=-1){ + baos.write(buff,0,len); + baos.flush(); + sum+=len; + if(sum>=endPos){ + break; + } + } + } + byte[] readResult = baos.toByteArray(); + return Arrays.copyOfRange(readResult,startPos,endPos); } @Override public int getContentLength() { - - return 0; + return connection.getContentLength(); } @Override public void close() { - - - } + } + public void setHttpURLConnection(HttpURLConnection httpURLConnection){ + this.connection = httpURLConnection; + } } diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/impl/ConnectionManagerImpl.java b/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/impl/ConnectionManagerImpl.java index 172371dd55..bcdad865aa 100644 --- a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/impl/ConnectionManagerImpl.java +++ b/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/impl/ConnectionManagerImpl.java @@ -1,14 +1,25 @@ -package com.coderising.download.impl; +package com.github.wdn.coding2017.coderising.download.impl; -import com.coderising.download.api.Connection; -import com.coderising.download.api.ConnectionException; -import com.coderising.download.api.ConnectionManager; + +import com.github.wdn.coding2017.coderising.download.api.Connection; +import com.github.wdn.coding2017.coderising.download.api.ConnectionException; +import com.github.wdn.coding2017.coderising.download.api.ConnectionManager; + +import java.net.HttpURLConnection; +import java.net.URL; public class ConnectionManagerImpl implements ConnectionManager { @Override public Connection open(String url) throws ConnectionException { - + try { + URL targetUrl = new URL(url); + Connection connection = new ConnectionImpl(); + connection.setHttpURLConnection((HttpURLConnection) targetUrl.openConnection()); + return connection; + } catch (Exception e) { + e.printStackTrace(); + } return null; } From ff4814d22cfffc72d67a94db5ba0f68e25cbe6a9 Mon Sep 17 00:00:00 2001 From: Patrick Date: Mon, 3 Apr 2017 21:26:52 +0800 Subject: [PATCH 049/203] =?UTF-8?q?LRU=E7=AE=97=E6=B3=95=E5=92=8CJVM?= =?UTF-8?q?=E7=AC=AC=E4=B8=80=E6=AC=A1=E4=BD=9C=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ipk2015/coding2017/basic/Queue.java | 40 +++--- .../basic/linkedlist/LRUPageFrame.java | 119 ++++++++++++++++++ .../basic/linkedlist/LRUPageFrameTest.java | 33 +++++ .../basic/{ => linkedlist}/LinkedList.java | 6 +- .../coding2017/basic/test/LinkedListTest.java | 3 +- .../minijvm/loader/ClassFileLoader.java | 72 +++++++++++ .../minijvm/test/ClassFileloaderTest.java | 97 ++++++++++++++ .../coding2017/minijvm/test/EmployeeV1.java | 30 +++++ 8 files changed, 379 insertions(+), 21 deletions(-) create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/basic/linkedlist/LRUPageFrame.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/basic/linkedlist/LRUPageFrameTest.java rename group24/121111914/src/com/github/ipk2015/coding2017/basic/{ => linkedlist}/LinkedList.java (93%) create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ClassFileLoader.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/test/ClassFileloaderTest.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/test/EmployeeV1.java diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/basic/Queue.java b/group24/121111914/src/com/github/ipk2015/coding2017/basic/Queue.java index 6342314df6..5b13d3340a 100644 --- a/group24/121111914/src/com/github/ipk2015/coding2017/basic/Queue.java +++ b/group24/121111914/src/com/github/ipk2015/coding2017/basic/Queue.java @@ -1,19 +1,21 @@ -package com.github.ipk2015.coding2017.basic; - -public class Queue { - private LinkedList elementDatas=new LinkedList(); - public void enQueue(Object o){ - elementDatas.add(o); - } - public Object deQueue(){ - return elementDatas.removeFirst(); - } - - public boolean isEmpty(){ - return size()==0; - } - - public int size(){ - return elementDatas.size(); - } -} +package com.github.ipk2015.coding2017.basic; + +import com.github.ipk2015.coding2017.basic.linkedlist.LinkedList; + +public class Queue { + private LinkedList elementDatas=new LinkedList(); + public void enQueue(Object o){ + elementDatas.add(o); + } + public Object deQueue(){ + return elementDatas.removeFirst(); + } + + public boolean isEmpty(){ + return size()==0; + } + + public int size(){ + return elementDatas.size(); + } +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/basic/linkedlist/LRUPageFrame.java b/group24/121111914/src/com/github/ipk2015/coding2017/basic/linkedlist/LRUPageFrame.java new file mode 100644 index 0000000000..81a3cb3554 --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/basic/linkedlist/LRUPageFrame.java @@ -0,0 +1,119 @@ +package com.github.ipk2015.coding2017.basic.linkedlist; + + + +/** + * 用双向链表实现LRU算法 + * @author liuxin + * + */ +public class LRUPageFrame { + + private static class Node { + + Node prev; + Node next; + int pageNum; + + Node() { + } + } + + private int capacity; + private int size=0; + + private Node first;// 链表头 + private Node last;// 链表尾 + + + public LRUPageFrame(int capacity) { + + this.capacity = capacity; + + } + + /** + * 获取缓存中对象 + * + * @param key + * @return + */ + public void access(int pageNum) { + if(this.capacity<=1){ + throw new RuntimeException("MeaningLess"); + } + int pos=searchPageNum(pageNum); + if(pos==-1){ + addFirst(pageNum); + return; + } + if(pos==0){ + return; + } + Node tempNode=first; + for(int i=0;i clzPaths = new ArrayList(); + + public byte[] readBinaryCode(String className) throws IOException { + className=getCompleteClassName(className); + File file=null; + for(String path:clzPaths){ + file=new File(path+"\\"+className); + if(file.exists()){ + break; + } + } + if(null==file){ + throw new FileNotFoundException(className); + } + ByteArrayOutputStream bos=new ByteArrayOutputStream((int)file.length()); + BufferedInputStream in=new BufferedInputStream(new FileInputStream(file)); + int size=1024; + byte[] buffer=new byte[size]; + int length=0; + while((length=in.read(buffer, 0, size))!=-1){ + bos.write(buffer,0,length); + } + return bos.toByteArray(); + } + + + public void addClassPath(String path) { + clzPaths.add(path); + } + + + + public String getClassPath(){ + StringBuffer buffer=new StringBuffer(); + for(String path:clzPaths){ + buffer.append(path+";"); + } + buffer.deleteCharAt(buffer.length()-1); + return buffer.toString(); + } + + private String getCompleteClassName(String name){ + if(!name.endsWith(".class")){ + name=name+".class"; + } + int pointPos=name.lastIndexOf(".", name.length()-7); + if(pointPos>-1){ + name=name.substring(pointPos+1); + } + return name; + } + + + +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/test/ClassFileloaderTest.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..61440e39c2 --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/test/ClassFileloaderTest.java @@ -0,0 +1,97 @@ +package com.github.ipk2015.coding2017.minijvm.test; + + + +import java.io.IOException; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.github.ipk2015.coding2017.minijvm.loader.ClassFileLoader; + + + + + + +public class ClassFileloaderTest { + + + static String path1 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\mini-jvm\\bin"; + static String path2 = "C:\temp"; + static String path3 = "E:\\javaImprove\\git\\group24\\121111914\\src\\com\\github\\ipk2015\\coding2017\\minijvm\\bin"; + + + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testClassPath(){ + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + loader.addClassPath(path2); + + String clzPath = loader.getClassPath(); + + Assert.assertEquals(path1+";"+path2,clzPath); + + } + + @Test + public void testClassFileLength() throws IOException { + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path3); + + String className = "com.coderising.jvm.test.EmployeeV1"; + byte[] byteCodes = loader.readBinaryCode(className); + System.out.println( byteCodes.length+""); + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + Assert.assertEquals(835, byteCodes.length); + + } + + + @Test + public void testMagicNumber() throws IOException{ + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path3); + String className = "com.coderising.jvm.test.EmployeeV1"; + byte[] byteCodes = loader.readBinaryCode(className); + byte[] codes = new byte[]{byteCodes[0],byteCodes[1],byteCodes[2],byteCodes[3]}; + + + String acctualValue = this.byteToHexString(codes); + + Assert.assertEquals("cafebabe", acctualValue); + } + + + + + + + private String byteToHexString(byte[] codes ){ + StringBuffer buffer = new StringBuffer(); + for(int i=0;i Date: Mon, 3 Apr 2017 22:40:21 +0800 Subject: [PATCH 050/203] =?UTF-8?q?=E5=A6=82=E6=9E=9Cpath=E6=B2=A1?= =?UTF-8?q?=E6=9C=89=E6=B7=BB=E5=8A=A0=20=E6=8A=9B=E5=87=BAClassNotFoundEx?= =?UTF-8?q?ception?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java | 2 +- .../src/com/coderising/jvm/test/ClassFileloaderTest.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java index 86f1100e6c..25b8bacf1f 100644 --- a/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -16,7 +16,7 @@ public class ClassFileLoader { public byte[] readBinaryCode(String className) throws ClassNotFoundException, IOException { if (clzPaths.size() == 0) { - return new byte[0]; + throw new ClassNotFoundException(className); } String actualPath = getActualPath(className); diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java index b15eb7e99d..392c4a479a 100644 --- a/group05/1094051862/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -60,7 +60,6 @@ public void testClassFileLength() throws ClassNotFoundException, IOException { @Test public void testMagicNumber() throws ClassNotFoundException, IOException{ - ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); String className = "com.coderising.jvm.test.EmployeeV1"; From 0799034299cd4a1dbc240a9a160d49fdec74723c Mon Sep 17 00:00:00 2001 From: lzb Date: Tue, 4 Apr 2017 01:27:26 +0800 Subject: [PATCH 051/203] =?UTF-8?q?=E4=BA=A4=E4=BD=9C=E4=B8=9A=EF=BC=8C04/?= =?UTF-8?q?04=EF=BC=8C=E4=BF=AE=E6=94=B9=E9=A1=B9=E7=9B=AE=E5=8C=85?= =?UTF-8?q?=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group24/1148285693/.gitignore | 4 +- .../java/me/lzb/algorithm/LRUPageFrame.java | 173 ++++++++++++++++++ .../basic => datastructure}/ArrayList.java | 2 +- .../array => datastructure}/ArrayUtil.java | 2 +- .../BinaryTreeNode.java | 4 +- .../basic => datastructure}/Iterator.java | 2 +- .../basic => datastructure}/LinkedList.java | 2 +- .../basic => datastructure}/List.java | 2 +- .../basic => datastructure}/Queue.java | 8 +- .../basic => datastructure}/Stack.java | 2 +- .../download/DownloadThread.java | 4 +- .../download/FileDownloader.java | 12 +- .../download/api/Connection.java | 4 +- .../download/api/ConnectionException.java | 2 +- .../download/api/ConnectionManager.java | 2 +- .../download/api/DownloadListener.java | 2 +- .../download/impl/ConnectionImpl.java | 8 +- .../download/impl/ConnectionManagerImpl.java | 17 ++ .../lzb/homework0326/download/FileUtil.java | 9 - .../download/impl/ConnectionManagerImpl.java | 17 -- .../litestruts/LoginAction.java | 2 +- .../{homework0319 => }/litestruts/Struts.java | 2 +- .../{homework0319 => }/litestruts/View.java | 4 +- .../litestruts/XmlUtil.java | 2 +- .../src/main/resources/litestruts/struts.xml | 4 +- .../me/lzb/algorithm/LRUPageFrameTest.java | 41 +++++ .../ArrayListTest.java | 6 +- .../LinkedListTest.java | 4 +- .../download/ConnectionTest.java | 12 +- .../download/FileDownloaderTest.java | 8 +- .../litestruts/StrutsTest.java | 2 +- .../src/test/resources/litestruts/struts.xml | 4 +- .../java/me/lzb/loader/ClassFileLoader.java | 57 ++++++ .../src/main/java/me/lzb/utils/FileUtils.java | 63 +++++++ .../main/java/me/lzb/utils/StringUtils.java | 7 + .../me/lzb/loader/ClassFileloaderTest.java | 103 +++++++++++ .../test/java/me/lzb/loader/EmployeeV1.java | 27 +++ group24/1148285693/learning2017/pom.xml | 2 + 38 files changed, 549 insertions(+), 79 deletions(-) create mode 100644 group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/algorithm/LRUPageFrame.java rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{homework0312/basic => datastructure}/ArrayList.java (98%) rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{homework0319/array => datastructure}/ArrayUtil.java (99%) rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{homework0312/basic => datastructure}/BinaryTreeNode.java (96%) rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{homework0312/basic => datastructure}/Iterator.java (77%) rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{homework0312/basic => datastructure}/LinkedList.java (99%) rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{homework0312/basic => datastructure}/List.java (84%) rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{homework0312/basic => datastructure}/Queue.java (92%) rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{homework0312/basic => datastructure}/Stack.java (96%) rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{homework0326 => }/download/DownloadThread.java (91%) rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{homework0326 => }/download/FileDownloader.java (93%) rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{homework0326 => }/download/api/Connection.java (90%) rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{homework0326 => }/download/api/ConnectionException.java (75%) rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{homework0326 => }/download/api/ConnectionManager.java (80%) rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{homework0326 => }/download/api/DownloadListener.java (60%) rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{homework0326 => }/download/impl/ConnectionImpl.java (92%) create mode 100644 group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/download/impl/ConnectionManagerImpl.java delete mode 100644 group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/FileUtil.java delete mode 100644 group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/impl/ConnectionManagerImpl.java rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{homework0319 => }/litestruts/LoginAction.java (95%) rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{homework0319 => }/litestruts/Struts.java (99%) rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{homework0319 => }/litestruts/View.java (89%) rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{homework0319 => }/litestruts/XmlUtil.java (96%) create mode 100644 group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/algorithm/LRUPageFrameTest.java rename group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/{homework0312/basic => datastructure}/ArrayListTest.java (95%) rename group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/{homework0312/basic => datastructure}/LinkedListTest.java (98%) rename group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/{homework0326 => }/download/ConnectionTest.java (78%) rename group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/{homework0326 => }/download/FileDownloaderTest.java (85%) rename group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/{homework0319 => }/litestruts/StrutsTest.java (96%) create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/loader/ClassFileLoader.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/utils/FileUtils.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/utils/StringUtils.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/test/java/me/lzb/loader/ClassFileloaderTest.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/test/java/me/lzb/loader/EmployeeV1.java diff --git a/group24/1148285693/.gitignore b/group24/1148285693/.gitignore index 23f75414d3..f41f37aecb 100644 --- a/group24/1148285693/.gitignore +++ b/group24/1148285693/.gitignore @@ -35,4 +35,6 @@ logs .directory .DS_Store -Test.java \ No newline at end of file + +Test.java +example \ No newline at end of file diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/algorithm/LRUPageFrame.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/algorithm/LRUPageFrame.java new file mode 100644 index 0000000000..1f1d0a36b7 --- /dev/null +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/algorithm/LRUPageFrame.java @@ -0,0 +1,173 @@ +package me.lzb.algorithm; + +/** + * 用双向链表实现LRU算法 + * @author lzb + * + */ +public class LRUPageFrame { + + private static class Node { + + Node prev; + Node next; + int pageNum; + + Node(Node prev, Node next, int pageNum) { + this.prev = prev; + this.next = next; + this.pageNum = pageNum; + } + } + + private int capacity; + + + private Node first;// 链表头 + private Node last;// 链表尾 + + + public LRUPageFrame(int capacity) { + if(capacity < 1){ +// throw new Exception("capacity boom"); + } + this.capacity = capacity; + + } + + /** + * 获取缓存中对象 + * + * @param pageNum + * @return + */ + public void access(int pageNum) { + if(capacity == 1){ + first = last = new Node(null, null, pageNum); + return; + } + + + if(first == null){ + first = last = new Node(null, null, pageNum); + return; + } + + if(first.pageNum == pageNum){ + return; + } + + Node tmp = first; + int size = 0; + for (int i = 0; i < capacity; i++) { + size = size + 1; + //如果发现一样的,把这个挪到最前面 + if(tmp.pageNum == pageNum){ + moveToFirst(tmp); + return; + } + //链表已经循环结束,但是个数还没满,更新last + if(tmp.next == null){ + last = tmp; + break; + } + tmp = tmp.next; + } + + + //没有相同的,在最顶端插入 + Node f = new Node(null, first, pageNum); + addAsFirst(f); + + //已经放满,更新last + if(size >= capacity){ + removeLastOne(); + } + + } + + /** + * 删除最后一个节点 + */ + private void removeLastOne(){ + last = last.prev; + //使GC ROOT 不可达 + last.next.prev = null; + last.next = null; + } + + /** + * 把某节点移动到最顶部 + * @param tmp 在链表中的任意节点 + */ + private void moveToFirst(Node tmp){ + if(tmp == first){ + return; + } + + if (tmp.next != null){ + tmp.next.prev = tmp.prev; + tmp.prev.next = tmp.next; + }else { + tmp.prev.next = null; + //当这个节点是last的时候,更新last + last = tmp.prev; + } + + tmp.next = first; + tmp.prev = null; + + first.prev = tmp; + first = tmp; + } + + /** + * 在顶部增加一个节点 + * @param node node + */ + private void addAsFirst(Node node){ + first.prev = node; + first = node; + } + + + + /** + * ASC + * @return + */ + public String toString(){ + StringBuilder buffer = new StringBuilder(); + Node node = first; + while(node != null){ + buffer.append(node.pageNum); + + node = node.next; + if(node != null){ + buffer.append(","); + } + } + return buffer.toString(); + } + + + /** + * DESC + * @return + */ + public String toStringDESC(){ + + StringBuilder buffer = new StringBuilder(); + Node node = last; + while(node != null){ + buffer.append(node.pageNum); + + node = node.prev; + if(node != null){ + buffer.append(","); + } + } + return buffer.toString(); + } + +} diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0312/basic/ArrayList.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/ArrayList.java similarity index 98% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0312/basic/ArrayList.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/ArrayList.java index 6fde63911f..080aa4f724 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0312/basic/ArrayList.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/ArrayList.java @@ -1,4 +1,4 @@ -package me.lzb.homework0312.basic; +package me.lzb.datastructure; /** * 简易ArrayList diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0319/array/ArrayUtil.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/ArrayUtil.java similarity index 99% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0319/array/ArrayUtil.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/ArrayUtil.java index 94f7b60c64..de101845aa 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0319/array/ArrayUtil.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/ArrayUtil.java @@ -1,4 +1,4 @@ -package me.lzb.homework0319.array; +package me.lzb.datastructure; public class ArrayUtil { diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0312/basic/BinaryTreeNode.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/BinaryTreeNode.java similarity index 96% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0312/basic/BinaryTreeNode.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/BinaryTreeNode.java index 053baad0d4..dfcaa60300 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0312/basic/BinaryTreeNode.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/BinaryTreeNode.java @@ -1,11 +1,11 @@ -package me.lzb.homework0312.basic; +package me.lzb.datastructure; /** * 左边比父节点小,右边比父节点大 * Created by LZB on 2017/3/11. */ public class BinaryTreeNode { - + private int data; private BinaryTreeNode left; private BinaryTreeNode right; diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0312/basic/Iterator.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/Iterator.java similarity index 77% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0312/basic/Iterator.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/Iterator.java index 138e090126..b65f73b2e3 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0312/basic/Iterator.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/Iterator.java @@ -1,4 +1,4 @@ -package me.lzb.homework0312.basic; +package me.lzb.datastructure; /** * Created by LZB on 2017/3/11. diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0312/basic/LinkedList.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/LinkedList.java similarity index 99% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0312/basic/LinkedList.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/LinkedList.java index e3cd7e9fa1..f79b7eaf18 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0312/basic/LinkedList.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/LinkedList.java @@ -1,4 +1,4 @@ -package me.lzb.homework0312.basic; +package me.lzb.datastructure; /** diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0312/basic/List.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/List.java similarity index 84% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0312/basic/List.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/List.java index bd66593efa..8f6478c49e 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0312/basic/List.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/List.java @@ -1,4 +1,4 @@ -package me.lzb.homework0312.basic; +package me.lzb.datastructure; /** * list接口 diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0312/basic/Queue.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/Queue.java similarity index 92% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0312/basic/Queue.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/Queue.java index 50ea66f1a2..35dc95f688 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0312/basic/Queue.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/Queue.java @@ -1,4 +1,4 @@ -package me.lzb.homework0312.basic; +package me.lzb.datastructure; /** * 先进先出 @@ -10,21 +10,21 @@ public class Queue { public void enQueue(Object o){ elementData.add(o); } - + public Object deQueue() throws IndexOutOfBoundsException{ if(isEmpty()){ throw new IndexOutOfBoundsException("index boom"); } return elementData.remove(elementData.size() - 1); } - + public boolean isEmpty(){ if(elementData.size() <= 0){ return true; } return false; } - + public int size(){ return elementData.size(); } diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0312/basic/Stack.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/Stack.java similarity index 96% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0312/basic/Stack.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/Stack.java index 4cd8d3dfd9..367b7210e6 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0312/basic/Stack.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/Stack.java @@ -1,4 +1,4 @@ -package me.lzb.homework0312.basic; +package me.lzb.datastructure; /** * 先进后出 diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/DownloadThread.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/download/DownloadThread.java similarity index 91% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/DownloadThread.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/download/DownloadThread.java index 68e8fe9fc8..9db5e9fc86 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/DownloadThread.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/download/DownloadThread.java @@ -1,6 +1,6 @@ -package me.lzb.homework0326.download; +package me.lzb.download; -import me.lzb.homework0326.download.api.Connection; +import me.lzb.download.api.Connection; import java.io.RandomAccessFile; import java.util.concurrent.CyclicBarrier; diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/FileDownloader.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/download/FileDownloader.java similarity index 93% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/FileDownloader.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/download/FileDownloader.java index d0867fa022..b64ddebd9c 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/FileDownloader.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/download/FileDownloader.java @@ -1,8 +1,8 @@ -package me.lzb.homework0326.download; +package me.lzb.download; -import me.lzb.homework0326.download.api.Connection; -import me.lzb.homework0326.download.api.ConnectionManager; -import me.lzb.homework0326.download.api.DownloadListener; +import me.lzb.download.api.Connection; +import me.lzb.download.api.ConnectionManager; +import me.lzb.download.api.DownloadListener; import java.io.IOException; import java.io.RandomAccessFile; @@ -69,9 +69,7 @@ public void run() { } catch (Exception e) { e.printStackTrace(); } finally { - if (conn != null) { - conn.close(); - } + } diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/api/Connection.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/download/api/Connection.java similarity index 90% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/api/Connection.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/download/api/Connection.java index 5e5d70f7e7..17413ca23b 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/api/Connection.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/download/api/Connection.java @@ -1,4 +1,4 @@ -package me.lzb.homework0326.download.api; +package me.lzb.download.api; import java.io.IOException; @@ -15,7 +15,7 @@ public interface Connection { * @return */ int getContentLength(); - + /** * 关闭连接 */ diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/api/ConnectionException.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/download/api/ConnectionException.java similarity index 75% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/api/ConnectionException.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/download/api/ConnectionException.java index a31e69b1aa..6c1f4defbe 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/api/ConnectionException.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/download/api/ConnectionException.java @@ -1,4 +1,4 @@ -package me.lzb.homework0326.download.api; +package me.lzb.download.api; public class ConnectionException extends Exception { diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/api/ConnectionManager.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/download/api/ConnectionManager.java similarity index 80% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/api/ConnectionManager.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/download/api/ConnectionManager.java index c15482bb1b..abec231748 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/api/ConnectionManager.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/download/api/ConnectionManager.java @@ -1,4 +1,4 @@ -package me.lzb.homework0326.download.api; +package me.lzb.download.api; public interface ConnectionManager { /** diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/api/DownloadListener.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/download/api/DownloadListener.java similarity index 60% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/api/DownloadListener.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/download/api/DownloadListener.java index 5969f87969..3131ec9966 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/api/DownloadListener.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/download/api/DownloadListener.java @@ -1,4 +1,4 @@ -package me.lzb.homework0326.download.api; +package me.lzb.download.api; public interface DownloadListener { void notifyFinished(); diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/impl/ConnectionImpl.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/download/impl/ConnectionImpl.java similarity index 92% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/impl/ConnectionImpl.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/download/impl/ConnectionImpl.java index a3ec1d6c8b..6fc42341db 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/impl/ConnectionImpl.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/download/impl/ConnectionImpl.java @@ -1,7 +1,7 @@ -package me.lzb.homework0326.download.impl; +package me.lzb.download.impl; -import me.lzb.homework0326.download.api.Connection; -import me.lzb.homework0326.download.api.ConnectionException; +import me.lzb.download.api.Connection; +import me.lzb.download.api.ConnectionException; import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; @@ -35,7 +35,9 @@ public ConnectionImpl(String url) throws ConnectionException{ @Override public byte[] read(int startPos, int endPos) throws IOException { + httpget.removeHeaders("Range"); httpget.addHeader("Range", "bytes=" + startPos + "-" + endPos); + CloseableHttpResponse response = httpClient.execute(httpget); InputStream inputStream = response.getEntity().getContent(); diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/download/impl/ConnectionManagerImpl.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/download/impl/ConnectionManagerImpl.java new file mode 100644 index 0000000000..d450f5aa92 --- /dev/null +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/download/impl/ConnectionManagerImpl.java @@ -0,0 +1,17 @@ +package me.lzb.download.impl; + + +import me.lzb.download.api.Connection; +import me.lzb.download.api.ConnectionException; +import me.lzb.download.api.ConnectionManager; + +public class ConnectionManagerImpl implements ConnectionManager { + + + @Override + public Connection open(String url) throws ConnectionException { + return new ConnectionImpl(url); + } + + +} diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/FileUtil.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/FileUtil.java deleted file mode 100644 index 57f9e75cdb..0000000000 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/FileUtil.java +++ /dev/null @@ -1,9 +0,0 @@ -package me.lzb.homework0326.download; - -/** - * Created by LZB on 2017/3/27. - */ -public class FileUtil { - - -} diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/impl/ConnectionManagerImpl.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/impl/ConnectionManagerImpl.java deleted file mode 100644 index e341546897..0000000000 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0326/download/impl/ConnectionManagerImpl.java +++ /dev/null @@ -1,17 +0,0 @@ -package me.lzb.homework0326.download.impl; - - -import me.lzb.homework0326.download.api.Connection; -import me.lzb.homework0326.download.api.ConnectionException; -import me.lzb.homework0326.download.api.ConnectionManager; - -public class ConnectionManagerImpl implements ConnectionManager { - - - @Override - public Connection open(String url) throws ConnectionException { - return new ConnectionImpl(url); - } - - -} diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0319/litestruts/LoginAction.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/litestruts/LoginAction.java similarity index 95% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0319/litestruts/LoginAction.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/litestruts/LoginAction.java index 4c4ca22187..5ea923c5b4 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0319/litestruts/LoginAction.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/litestruts/LoginAction.java @@ -1,4 +1,4 @@ -package me.lzb.homework0319.litestruts; +package me.lzb.litestruts; /** * 这是一个用来展示登录的业务类, 其中的用户名和密码都是硬编码的。 diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0319/litestruts/Struts.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/litestruts/Struts.java similarity index 99% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0319/litestruts/Struts.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/litestruts/Struts.java index aea8d1105d..7841100872 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0319/litestruts/Struts.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/litestruts/Struts.java @@ -1,4 +1,4 @@ -package me.lzb.homework0319.litestruts; +package me.lzb.litestruts; import org.apache.commons.lang3.StringUtils; import org.dom4j.DocumentException; diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0319/litestruts/View.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/litestruts/View.java similarity index 89% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0319/litestruts/View.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/litestruts/View.java index 614b4a584f..db8e6e1a9c 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0319/litestruts/View.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/litestruts/View.java @@ -1,11 +1,11 @@ -package me.lzb.homework0319.litestruts; +package me.lzb.litestruts; import java.util.Map; public class View { private String jsp; private Map parameters; - + public String getJsp() { return jsp; } diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0319/litestruts/XmlUtil.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/litestruts/XmlUtil.java similarity index 96% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0319/litestruts/XmlUtil.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/litestruts/XmlUtil.java index c8ad10c83b..8c58fb7902 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/homework0319/litestruts/XmlUtil.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/litestruts/XmlUtil.java @@ -1,4 +1,4 @@ -package me.lzb.homework0319.litestruts; +package me.lzb.litestruts; import org.dom4j.Document; import org.dom4j.DocumentException; diff --git a/group24/1148285693/learning2017/learning-basic/src/main/resources/litestruts/struts.xml b/group24/1148285693/learning2017/learning-basic/src/main/resources/litestruts/struts.xml index 81c153757c..a4859a04b2 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/resources/litestruts/struts.xml +++ b/group24/1148285693/learning2017/learning-basic/src/main/resources/litestruts/struts.xml @@ -1,10 +1,10 @@ - + /jsp/homepage.jsp /jsp/showLogin.jsp - + /jsp/welcome.jsp /jsp/error.jsp diff --git a/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/algorithm/LRUPageFrameTest.java b/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/algorithm/LRUPageFrameTest.java new file mode 100644 index 0000000000..66bfd42119 --- /dev/null +++ b/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/algorithm/LRUPageFrameTest.java @@ -0,0 +1,41 @@ +package me.lzb.algorithm; + +import org.junit.Assert; +import org.junit.Test; + + +public class LRUPageFrameTest { + + @Test + public void testAccess() { + LRUPageFrame frame = new LRUPageFrame(3); + frame.access(7); + Assert.assertEquals("7", frame.toString()); + Assert.assertEquals("7", frame.toStringDESC()); + frame.access(0); + Assert.assertEquals("0,7", frame.toString()); + Assert.assertEquals("7,0", frame.toStringDESC()); + frame.access(1); + Assert.assertEquals("1,0,7", frame.toString()); + Assert.assertEquals("7,0,1", frame.toStringDESC()); + frame.access(2); + Assert.assertEquals("2,1,0", frame.toString()); + Assert.assertEquals("0,1,2", frame.toStringDESC()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + Assert.assertEquals("1,2,0", frame.toStringDESC()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + Assert.assertEquals("1,2,0", frame.toStringDESC()); + frame.access(3); + Assert.assertEquals("3,0,2", frame.toString()); + Assert.assertEquals("2,0,3", frame.toStringDESC()); + frame.access(0); + Assert.assertEquals("0,3,2", frame.toString()); + Assert.assertEquals("2,3,0", frame.toStringDESC()); + frame.access(4); + Assert.assertEquals("4,0,3", frame.toString()); + Assert.assertEquals("3,0,4", frame.toStringDESC()); + } + +} diff --git a/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/homework0312/basic/ArrayListTest.java b/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/datastructure/ArrayListTest.java similarity index 95% rename from group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/homework0312/basic/ArrayListTest.java rename to group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/datastructure/ArrayListTest.java index 4938e6a8ac..dcb879a948 100644 --- a/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/homework0312/basic/ArrayListTest.java +++ b/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/datastructure/ArrayListTest.java @@ -1,7 +1,7 @@ -package me.lzb.homework0312.basic; +package me.lzb.datastructure; -import me.lzb.homework0312.basic.ArrayList; -import me.lzb.homework0312.basic.Iterator; +import me.lzb.datastructure.ArrayList; +import me.lzb.datastructure.Iterator; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; diff --git a/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/homework0312/basic/LinkedListTest.java b/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/datastructure/LinkedListTest.java similarity index 98% rename from group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/homework0312/basic/LinkedListTest.java rename to group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/datastructure/LinkedListTest.java index ef0e043a11..1914195aa5 100644 --- a/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/homework0312/basic/LinkedListTest.java +++ b/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/datastructure/LinkedListTest.java @@ -1,5 +1,7 @@ -package me.lzb.homework0312.basic; +package me.lzb.datastructure; +import me.lzb.datastructure.Iterator; +import me.lzb.datastructure.LinkedList; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; diff --git a/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/homework0326/download/ConnectionTest.java b/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/download/ConnectionTest.java similarity index 78% rename from group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/homework0326/download/ConnectionTest.java rename to group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/download/ConnectionTest.java index 10eb296623..884c309765 100644 --- a/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/homework0326/download/ConnectionTest.java +++ b/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/download/ConnectionTest.java @@ -1,8 +1,8 @@ -package me.lzb.homework0326.download; +package me.lzb.download; -import me.lzb.homework0326.download.api.Connection; -import me.lzb.homework0326.download.api.ConnectionManager; -import me.lzb.homework0326.download.impl.ConnectionManagerImpl; +import me.lzb.download.api.Connection; +import me.lzb.download.api.ConnectionManager; +import me.lzb.download.impl.ConnectionManagerImpl; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -28,7 +28,8 @@ public void tearDown() throws Exception { public void testContentLength() throws Exception{ ConnectionManager connMan = new ConnectionManagerImpl(); Connection conn = connMan.open(imageUrl); - Assert.assertEquals(35470, conn.getContentLength()); + Assert.assertEquals(3440179, conn.getContentLength()); + conn.close(); } @Test @@ -45,6 +46,7 @@ public void testRead() throws Exception{ Assert.assertEquals(1024, data.length); + //TODO 这个地方会一直卡住不执行 data = conn.read(1024, 2023); Assert.assertEquals(1000, data.length); diff --git a/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/homework0326/download/FileDownloaderTest.java b/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/download/FileDownloaderTest.java similarity index 85% rename from group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/homework0326/download/FileDownloaderTest.java rename to group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/download/FileDownloaderTest.java index c1c459184f..76c3edf432 100644 --- a/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/homework0326/download/FileDownloaderTest.java +++ b/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/download/FileDownloaderTest.java @@ -1,8 +1,8 @@ -package me.lzb.homework0326.download; +package me.lzb.download; -import me.lzb.homework0326.download.api.ConnectionManager; -import me.lzb.homework0326.download.api.DownloadListener; -import me.lzb.homework0326.download.impl.ConnectionManagerImpl; +import me.lzb.download.api.ConnectionManager; +import me.lzb.download.api.DownloadListener; +import me.lzb.download.impl.ConnectionManagerImpl; import org.junit.After; import org.junit.Before; import org.junit.Test; diff --git a/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/homework0319/litestruts/StrutsTest.java b/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/litestruts/StrutsTest.java similarity index 96% rename from group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/homework0319/litestruts/StrutsTest.java rename to group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/litestruts/StrutsTest.java index 027c33eba9..a970d742b4 100644 --- a/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/homework0319/litestruts/StrutsTest.java +++ b/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/litestruts/StrutsTest.java @@ -1,4 +1,4 @@ -package me.lzb.homework0319.litestruts; +package me.lzb.litestruts; import org.junit.Assert; import org.junit.Test; diff --git a/group24/1148285693/learning2017/learning-basic/src/test/resources/litestruts/struts.xml b/group24/1148285693/learning2017/learning-basic/src/test/resources/litestruts/struts.xml index 81c153757c..a4859a04b2 100644 --- a/group24/1148285693/learning2017/learning-basic/src/test/resources/litestruts/struts.xml +++ b/group24/1148285693/learning2017/learning-basic/src/test/resources/litestruts/struts.xml @@ -1,10 +1,10 @@ - + /jsp/homepage.jsp /jsp/showLogin.jsp - + /jsp/welcome.jsp /jsp/error.jsp diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/loader/ClassFileLoader.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/loader/ClassFileLoader.java new file mode 100644 index 0000000000..86f017cebf --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/loader/ClassFileLoader.java @@ -0,0 +1,57 @@ +package me.lzb.loader; + +import me.lzb.utils.FileUtils; +import me.lzb.utils.StringUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + + + +public class ClassFileLoader { + + private List clzPaths = new ArrayList<>(); + + public byte[] readBinaryCode(String className) throws IOException { + String fileName = className.replaceAll(".*\\.", "") + ".class"; + String pkg = className.replaceAll("\\.[^\\.]+$", ""); + String packagePath = pkg.replaceAll("\\.", "\\\\"); + + + String path = ""; + for (String s : clzPaths) { + if (FileUtils.isFileExist(s + packagePath, fileName)){ + path = s; + break; + } + } + + if(StringUtils.isBlank(path)){ + throw new IOException("class file not found"); + } + + return FileUtils.readByteCodes(path + packagePath + "\\" + fileName); + + } + + + public void addClassPath(String path) { + clzPaths.add(path); + } + + + + public String getClassPath(){ + StringBuilder buffer = new StringBuilder(); + for (Iterator iterator = clzPaths.iterator(); iterator.hasNext();) { + buffer.append(iterator.next() + (iterator.hasNext() ? ";" : "")); + } + return buffer.toString(); + } + + + + +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/utils/FileUtils.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/utils/FileUtils.java new file mode 100644 index 0000000000..b0947d4326 --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/utils/FileUtils.java @@ -0,0 +1,63 @@ +package me.lzb.utils; + +import java.io.*; + +/** + * Created by LZB on 2017/4/4. + */ +public class FileUtils { + + /** + * 判断文件是否存在 + * + * @param path 路径 + * @param name 文件名 + * @return true false + */ + public static boolean isFileExist(String path, String name) { + File file = new File(path + "\\" + name); + return file.exists(); + } + + /** + * 读取文件为二进制数组 + * @param clzFileName 文件路径 + * @return 数组 + * @throws IOException + */ + public static byte[] readByteCodes(String clzFileName) throws IOException { + + File f = new File(clzFileName); + + BufferedInputStream bis = new BufferedInputStream(new FileInputStream(f)); + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + + byte[] buffer = new byte[1024]; + int length = -1; + try { + while ((length = bis.read(buffer)) != -1) { + bos.write(buffer, 0, length); + } + } catch (IOException e) { + e.printStackTrace(); + throw e; + } finally { + if (bis != null) { + bis.close(); + } + if (bos != null) { + bos.close(); + } + } + + byte[] codes = bos.toByteArray(); + + bis.close(); + + return codes; + } + + +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/utils/StringUtils.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/utils/StringUtils.java new file mode 100644 index 0000000000..b4ec543d49 --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/utils/StringUtils.java @@ -0,0 +1,7 @@ +package me.lzb.utils; + +/** + * Created by LZB on 2017/4/4. + */ +public class StringUtils extends org.apache.commons.lang3.StringUtils { +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/test/java/me/lzb/loader/ClassFileloaderTest.java b/group24/1148285693/learning2017/mini-jvm/src/test/java/me/lzb/loader/ClassFileloaderTest.java new file mode 100644 index 0000000000..b544e7ddc4 --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/test/java/me/lzb/loader/ClassFileloaderTest.java @@ -0,0 +1,103 @@ +package me.lzb.loader; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + + + + +public class ClassFileloaderTest { + + + static String path1 = EmployeeV1.class.getResource("/").getPath(); + static String path2 = "C:\\temp"; + + + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + + + @Test + public void testPath(){ + + String s = EmployeeV1.class.getResource("/").getPath(); + String s2 = EmployeeV1.class.getResource("").getPath(); + System.out.println(s); + System.out.println(s2); + + } + + + + @Test + public void testClassPath(){ + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + loader.addClassPath(path2); + + String clzPath = loader.getClassPath(); + + Assert.assertEquals(path1+";"+path2,clzPath); + + } + + @Test + public void testClassFileLength() throws Exception{ + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + + String className = "me.lzb.loader.EmployeeV1"; + + byte[] byteCodes = loader.readBinaryCode(className); + + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + Assert.assertEquals(1036, byteCodes.length); + + } + + + @Test + public void testMagicNumber() throws Exception{ + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "me.lzb.loader.EmployeeV1"; + byte[] byteCodes = loader.readBinaryCode(className); + byte[] codes = new byte[]{byteCodes[0],byteCodes[1],byteCodes[2],byteCodes[3]}; + + String acctualValue = this.byteToHexString(codes); + + Assert.assertEquals("cafebabe", acctualValue); + } + + + + + + + private String byteToHexString(byte[] codes ){ + StringBuffer buffer = new StringBuffer(); + for(int i=0;i learning-basic + mini-jvm + From 75cafe0bfe3cfa5e8e92bc838c5f755dafb82c7b Mon Sep 17 00:00:00 2001 From: sdnb Date: Tue, 4 Apr 2017 11:36:44 +0800 Subject: [PATCH 052/203] =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=A4=9A=E7=BA=BF?= =?UTF-8?q?=E7=A8=8B=E4=B8=8B=E8=BD=BD=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../week3/download/impl/ConnectionImpl.java | 17 +++- .../coding/week3/download1/DownloadTask.java | 77 +++++++++++++++---- .../week3/download1/FileDownloader.java | 75 ++++++++++++++---- .../download1/api/ConnectionException.java | 4 +- .../download1/api/ConnectionManager.java | 5 +- .../api/ConnectionRefuseException.java | 23 ++++++ .../download1/impl/ConnectionManagerImpl.java | 64 ++++++++++----- .../com/coding/week3/FileDownloaderTest.java | 12 +-- 8 files changed, 215 insertions(+), 62 deletions(-) create mode 100644 group24/494800949/src/main/java/com/coding/week3/download1/api/ConnectionRefuseException.java diff --git a/group24/494800949/src/main/java/com/coding/week3/download/impl/ConnectionImpl.java b/group24/494800949/src/main/java/com/coding/week3/download/impl/ConnectionImpl.java index fe9b0a9079..9617474677 100644 --- a/group24/494800949/src/main/java/com/coding/week3/download/impl/ConnectionImpl.java +++ b/group24/494800949/src/main/java/com/coding/week3/download/impl/ConnectionImpl.java @@ -6,6 +6,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; +import java.util.concurrent.TimeUnit; public class ConnectionImpl implements Connection { @@ -48,8 +49,20 @@ public void close() { } @Override - public InputStream getInputStream() throws IOException { - return httpURLConnection.getInputStream(); + public InputStream getInputStream() { + try { + return httpURLConnection.getInputStream(); + } catch (IOException e) { + for (int i = 0; i < 5; i++) { + try { + TimeUnit.SECONDS.sleep(10); + return httpURLConnection.getInputStream(); + } catch (IOException | InterruptedException e1) { + e1.printStackTrace(); + } + } + throw new RuntimeException(e); + } } } diff --git a/group24/494800949/src/main/java/com/coding/week3/download1/DownloadTask.java b/group24/494800949/src/main/java/com/coding/week3/download1/DownloadTask.java index 0c09657dc4..2ef5729241 100644 --- a/group24/494800949/src/main/java/com/coding/week3/download1/DownloadTask.java +++ b/group24/494800949/src/main/java/com/coding/week3/download1/DownloadTask.java @@ -1,10 +1,10 @@ package com.coding.week3.download1; -import com.coding.week3.download.api.Connection; +import com.coding.week3.download1.api.Connection; +import com.coding.week3.download1.api.ConnectionManager; -import java.io.IOException; -import java.io.InputStream; -import java.io.RandomAccessFile; +import java.io.*; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; /** @@ -12,39 +12,82 @@ */ public class DownloadTask implements Runnable { private static final int BUFF_SIZE = 1024; - Connection conn; - int startPos; - int endPos; - RandomAccessFile ras; - AtomicInteger downloadBytesCount; - - public DownloadTask(Connection conn, int startPos, int endPos, RandomAccessFile ras, AtomicInteger downloadBytesCount) { - this.conn = conn; + ConnectionManager connectionManager; + int startPos; + int endPos; + RandomAccessFile ras; + AtomicInteger totalDownloadBytesCount; + AtomicInteger eachThreadDownloadBytesCount; + String url; + + public DownloadTask(String url, ConnectionManager connectionManager, int startPos, int endPos, RandomAccessFile ras, AtomicInteger totalDownloadBytesCount) { + this.url = url; + this.connectionManager = connectionManager; this.startPos = startPos; this.endPos = endPos; this.ras = ras; - this.downloadBytesCount = downloadBytesCount; + this.totalDownloadBytesCount = totalDownloadBytesCount; + this.eachThreadDownloadBytesCount = new AtomicInteger(0); } @Override public void run() { + Connection conn = null; + InputStream is = null; try { - InputStream is = conn.getInputStream(); + conn = connectionManager.open(url); + is = getInputStream(conn); is.skip(startPos); ras.seek(startPos); byte[] bytes = new byte[BUFF_SIZE]; - int hasRead = 0; + int hasRead; int readTimes = (endPos - startPos) / BUFF_SIZE + 4; for (int i = 0; i < readTimes; i++) { - hasRead = is.read(bytes ); + hasRead = is.read(bytes); if (hasRead == -1) { break; } ras.write(bytes, 0, hasRead); - downloadBytesCount.getAndAdd(hasRead); + totalDownloadBytesCount.getAndAdd(hasRead); + eachThreadDownloadBytesCount.getAndAdd(hasRead); } + } catch (IOException e) { e.printStackTrace(); } } + + + private InputStream getInputStream(Connection connection){ + Connection conn = null; + InputStream is = null; + try { + conn = connectionManager.open(url); + is = conn.getInputStream(); + return is; + } catch (IOException e) { + for (int i = 0; i < 5; i++) { + try { + TimeUnit.SECONDS.sleep(5); + conn = connectionManager.open(url); + is = conn.getInputStream(); + is.skip(startPos); + break; + } catch (InterruptedException e1) { + e1.printStackTrace(); + } catch (IOException e1) { + System.out.println(e1.getMessage()); + } + } + throw new RuntimeException("连接超时", e); + } + + } + + + + + public int getEachThreadDownloadBytesCount() { + return eachThreadDownloadBytesCount.get(); + } } diff --git a/group24/494800949/src/main/java/com/coding/week3/download1/FileDownloader.java b/group24/494800949/src/main/java/com/coding/week3/download1/FileDownloader.java index 81c7c87508..72b11c120e 100644 --- a/group24/494800949/src/main/java/com/coding/week3/download1/FileDownloader.java +++ b/group24/494800949/src/main/java/com/coding/week3/download1/FileDownloader.java @@ -1,13 +1,12 @@ package com.coding.week3.download1; -import com.coding.week3.download.api.Connection; -import com.coding.week3.download.api.ConnectionException; -import com.coding.week3.download.api.ConnectionManager; -import com.coding.week3.download.api.DownloadListener; +import com.coding.week3.download1.api.Connection; +import com.coding.week3.download1.api.ConnectionException; +import com.coding.week3.download1.api.ConnectionManager; +import com.coding.week3.download1.api.DownloadListener; -import java.io.IOException; -import java.io.RandomAccessFile; +import java.io.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @@ -55,36 +54,39 @@ public void execute() throws IOException { // 下面的代码是示例代码, 也就是说只有一个线程, 你需要改造成多线程的。 Connection conn = null; + DownloadTask[] downloadTasks = new DownloadTask[nThread]; try { //根据文件长度为每个线程分配下载字节数量 conn = cm.open(this.url); fileLength = conn.getContentLength(); //已读字节数量 - ExecutorService executorService = Executors.newFixedThreadPool(nThread); - int[][] allotSize = alloctSize(nThread, fileLength); - +// int[][] allotSize = alloctSize(nThread, fileLength); + int[][] allotSize = readPos(nThread, fileLength); for (int i = 0; i < nThread; i++) { RandomAccessFile ras = new RandomAccessFile(savePath, "rw"); - executorService.execute(new DownloadTask(cm.open(url), allotSize[0][i], - allotSize[1][i], ras , downloadBytesCount)); + downloadTasks[i] = new DownloadTask(url, cm, allotSize[0][i], + allotSize[1][i], ras , downloadBytesCount); + executorService.execute(downloadTasks[i]); } //关闭线程池 executorService.shutdown(); boolean isTermination ; do { - System.out.println("已下载:"+(downloadBytesCount.get()/1024)+"K,百分比:"+ (downloadBytesCount.get()/ (fileLength/100))+"%" ); - //循环等待,直到线程全部关闭 isTermination = executorService.awaitTermination(500, TimeUnit.MILLISECONDS); + if (fileLength > 0) + System.out.println("已下载:"+(downloadBytesCount.get()/1024)+"K,百分比:"+ (downloadBytesCount.get()/ (fileLength/100))+"%" ); + //循环等待,直到线程全部关闭 } while (!isTermination); - + System.out.println(111111); } catch (ConnectionException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } finally{ + writePos(downloadTasks); if(conn != null){ conn.close(); } @@ -118,5 +120,48 @@ public void setConnectionManager(ConnectionManager ucm){ public DownloadListener getListener(){ return this.listener; } - + + private void writePos(DownloadTask[] tasks){ + File file = new File(""); + File posFile = new File(file.getAbsolutePath()+"/tempPos"); + RandomAccessFile ras = null; + try { + ras = new RandomAccessFile(posFile, "rw"); + if (!posFile.exists()) { + posFile.createNewFile(); + } + for (int i = 0; i < tasks.length; i++) { + ras.writeInt(tasks[i].getEachThreadDownloadBytesCount()); + ras.writeInt(tasks[i].endPos); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private int[][] readPos(int nThread, int fileLength){ + File file = new File(""); + File posFile = new File(file.getAbsolutePath()+"/tempPos"); + if (!posFile.exists()) { + return alloctSize(nThread, fileLength); + } + RandomAccessFile ras = null; + int[][] pos = new int[2][nThread]; + try { + ras = new RandomAccessFile(posFile, "r"); + ras.seek(0); + for (int i = 0; i < nThread; i++) { + pos[0][i] = ras.readInt(); + pos[1][i] = ras.readInt(); + } + return pos; + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return pos; + } } diff --git a/group24/494800949/src/main/java/com/coding/week3/download1/api/ConnectionException.java b/group24/494800949/src/main/java/com/coding/week3/download1/api/ConnectionException.java index 14f1291198..b1d8dddc42 100644 --- a/group24/494800949/src/main/java/com/coding/week3/download1/api/ConnectionException.java +++ b/group24/494800949/src/main/java/com/coding/week3/download1/api/ConnectionException.java @@ -1,6 +1,8 @@ package com.coding.week3.download1.api; -public class ConnectionException extends Exception { +import java.io.IOException; + +public class ConnectionException extends IOException { public ConnectionException() { } diff --git a/group24/494800949/src/main/java/com/coding/week3/download1/api/ConnectionManager.java b/group24/494800949/src/main/java/com/coding/week3/download1/api/ConnectionManager.java index 9674179b7a..f9ab90bc59 100644 --- a/group24/494800949/src/main/java/com/coding/week3/download1/api/ConnectionManager.java +++ b/group24/494800949/src/main/java/com/coding/week3/download1/api/ConnectionManager.java @@ -1,10 +1,13 @@ package com.coding.week3.download1.api; +import java.io.IOException; +import java.net.MalformedURLException; + public interface ConnectionManager { /** * 给定一个url , 打开一个连接 * @param url * @return */ - Connection open(String url) throws ConnectionException; + Connection open(String url) throws IOException; } diff --git a/group24/494800949/src/main/java/com/coding/week3/download1/api/ConnectionRefuseException.java b/group24/494800949/src/main/java/com/coding/week3/download1/api/ConnectionRefuseException.java new file mode 100644 index 0000000000..653d9520a4 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/week3/download1/api/ConnectionRefuseException.java @@ -0,0 +1,23 @@ +package com.coding.week3.download1.api; + +import java.io.IOException; + +/** + * Created by Administrator on 2017/4/2 0002. + */ +public class ConnectionRefuseException extends IOException{ + public ConnectionRefuseException() { + } + + public ConnectionRefuseException(String message) { + super(message); + } + + public ConnectionRefuseException(String message, Throwable cause) { + super(message, cause); + } + + public ConnectionRefuseException(Throwable cause) { + super(cause); + } +} diff --git a/group24/494800949/src/main/java/com/coding/week3/download1/impl/ConnectionManagerImpl.java b/group24/494800949/src/main/java/com/coding/week3/download1/impl/ConnectionManagerImpl.java index 3e65687879..927fc30d90 100644 --- a/group24/494800949/src/main/java/com/coding/week3/download1/impl/ConnectionManagerImpl.java +++ b/group24/494800949/src/main/java/com/coding/week3/download1/impl/ConnectionManagerImpl.java @@ -2,9 +2,9 @@ import com.coding.week3.download1.api.Connection; -import com.coding.week3.download1.api.ConnectionException; import com.coding.week3.download1.api.ConnectionManager; +import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; @@ -12,26 +12,48 @@ public class ConnectionManagerImpl implements ConnectionManager { @Override - public Connection open(String url) throws ConnectionException { - try { - // 统一资源 - URL realurl = new URL(url); - // 连接类的父类,抽象类 - URLConnection urlConnection = realurl.openConnection(); - // http的连接类 - HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection; - // 设定请求的方法,默认是GET - httpURLConnection.setRequestMethod("GET"); - httpURLConnection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); - // 设置字符编码 - httpURLConnection.setRequestProperty("Charset", "UTF-8"); - // 打开到此 URL 引用的资源的通信链接(如果尚未建立这样的连接)。 - httpURLConnection.connect(); - return new ConnectionImpl(httpURLConnection); - } catch (java.io.IOException e) { - e.printStackTrace(); - throw new ConnectionException(e.getMessage()); - } + public Connection open(String url) throws IOException { + HttpURLConnection httpURLConnection = null; + // 统一资源 + URL realurl = new URL(url); + // 连接类的父类,抽象类 + URLConnection urlConnection = realurl.openConnection(); + // http的连接类 + httpURLConnection = (HttpURLConnection) urlConnection; + //设置属性 + setHeader(httpURLConnection); + + //设置连接超时时间 + setWaitTime(httpURLConnection); + + // 打开到此 URL 引用的资源的通信链接(如果尚未建立这样的连接)。 + httpURLConnection.connect(); + return new ConnectionImpl(httpURLConnection); + } + + private void setHeader(HttpURLConnection con){ + con.setRequestProperty( + "User-Agent", + "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.3) Gecko/2008092510 Ubuntu/8.04 (hardy) Firefox/3.0.3"); + con.setRequestProperty("Accept-Language", "en-us,en;q=0.7,zh-cn;q=0.3"); + con.setRequestProperty("Accept-Encoding", "aa"); + con.setRequestProperty("Accept-Charset", + "ISO-8859-1,utf-8;q=0.7,*;q=0.7"); + con.setRequestProperty("Keep-Alive", "300"); + con.setRequestProperty("Connection", "keep-alive"); + con.setRequestProperty("If-Modified-Since", + "Fri, 02 Jan 2009 17:00:05 GMT"); + con.setRequestProperty("If-None-Match", "\"1261d8-4290-df64d224\""); + con.setRequestProperty("Cache-Control", "max-age=0"); + con.setRequestProperty("Referer", + "http://www.skycn.com/soft/14857.html"); + } + + + private void setWaitTime(HttpURLConnection con) { + //防止网络阻塞,设置指定的超时时间;单位都是ms。超过指定时间,就会抛出异常 + con.setConnectTimeout(10000); //连接超时设置 + con.setReadTimeout(10000); //读取超时设置 } } diff --git a/group24/494800949/src/test/java/com/coding/week3/FileDownloaderTest.java b/group24/494800949/src/test/java/com/coding/week3/FileDownloaderTest.java index d0985c04d4..524e3aaabb 100644 --- a/group24/494800949/src/test/java/com/coding/week3/FileDownloaderTest.java +++ b/group24/494800949/src/test/java/com/coding/week3/FileDownloaderTest.java @@ -1,8 +1,8 @@ package com.coding.week3; -import com.coding.week3.download.api.ConnectionManager; -import com.coding.week3.download.api.DownloadListener; -import com.coding.week3.download.impl.ConnectionManagerImpl; +import com.coding.week3.download1.api.ConnectionManager; +import com.coding.week3.download1.api.DownloadListener; +import com.coding.week3.download1.impl.ConnectionManagerImpl; import com.coding.week3.download1.FileDownloader; import org.junit.After; import org.junit.Assert; @@ -28,10 +28,12 @@ public void tearDown() throws Exception { @Test public void testDownload() throws IOException { -// String url = "http://101.95.48.97:8005/res/upload/interface/apptutorials/manualstypeico/6f83ce8f-0da5-49b3-bac8-fd5fc67d2725.png"; + String url = "http://101.95.48.97:8005/res/upload/interface/apptutorials/manualstypeico/6f83ce8f-0da5-49b3-bac8-fd5fc67d2725.png"; // String url = "http://download.oracle.com/otn-pub/java/jdk/8u121-b13/e9e7ea248e2c4826b92b3f075a80e441/jdk-8u121-linux-arm32-vfp-hflt.tar.gz"; // String url = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1490808670106&di=48aa6fb7af641f0cb6f9e19120b60c7c&imgtype=0&src=http%3A%2F%2Fwww.ntjoy.com%2Fliv_loadfile%2Fhealth%2Fdzcs%2Fnvr%2Ffold1%2F1360480639_97304600.jpg"; - String url = "https://download.jetbrains.com/idea/ideaIU-2017.1.exe"; +// String url = "https://download.jetbrains.com/idea/ideaIU-2017.1.exe"; +// String url = "https://nodejs.org/dist/v6.10.1/node-v6.10.1-win-x64.zip"; +// String url = "http://download.oracle.com/otn-pub/java/jdk/8u121-b13-demos/e9e7ea248e2c4826b92b3f075a80e441/jdk-8u121-windows-x64-demos.zip"; String path = new File("").getAbsolutePath(); String filename = url.substring(url.lastIndexOf("/"), url.length()); filename = path +File.separator + filename; From a17141689b46f95b1d9e85c5f4e044e868a1b0d9 Mon Sep 17 00:00:00 2001 From: wdn <626451284@163.com> Date: Tue, 4 Apr 2017 13:45:21 +0800 Subject: [PATCH 053/203] =?UTF-8?q?=E5=AE=8C=E6=88=90linkedlist=E6=89=80?= =?UTF-8?q?=E6=9C=89=E6=96=B9=E6=B3=95=EF=BC=8C=E8=B0=83=E6=95=B4=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=E6=B7=BB=E5=8A=A0minijvm=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wdn/coding2017/basic/ArrayList.java | 0 .../wdn/coding2017/basic/BinaryTreeNode.java | 0 .../github/wdn/coding2017/basic/Iterator.java | 0 .../wdn/coding2017/basic/LinkedList.java | 181 ++++++++++++++++-- .../com/github/wdn/coding2017/basic/List.java | 0 .../github/wdn/coding2017/basic/Queue.java | 0 .../github/wdn/coding2017/basic/Stack.java | 0 .../coding2017/basic/lru/LRUPageFrame.java | 60 ++++++ .../basic/lru/LRUPageFrameTest.java | 31 +++ .../wdn/coding2017/basic/lru/LinkedList.java | 126 ++++++++++++ .../coderising/array/ArrayUtil.java | 0 .../coderising/array/ArrayUtilTest.java | 0 .../coderising/download/DownloadThread.java | 0 .../coderising/download/FileDownloader.java | 0 .../download/FileDownloaderTest.java | 0 .../coderising/download/api/Connection.java | 0 .../download/api/ConnectionException.java | 0 .../download/api/ConnectionManager.java | 0 .../download/api/DownloadListener.java | 0 .../download/impl/ConnectionImpl.java | 0 .../download/impl/ConnectionManagerImpl.java | 0 .../coderising/litestruts/LoginAction.java | 0 .../coderising/litestruts/Struts.java | 0 .../coderising/litestruts/StrutsTest.java | 0 .../coderising/litestruts/View.java | 0 .../wdn/coding2017/basic/LinkedListTest.java | 91 +++++++++ .../jvm/loader/ClassFileLoader.java | 34 ++++ .../jvm/test/ClassFileloaderTest.java | 92 +++++++++ .../wdn/coding2017/jvm/test/EmployeeV1.java | 28 +++ group24/626451284/pom.xml | 10 - .../coderising/litestruts/struts.xml | 11 -- 31 files changed, 632 insertions(+), 32 deletions(-) rename group24/626451284/{ => data-structure}/src/main/java/com/github/wdn/coding2017/basic/ArrayList.java (100%) rename group24/626451284/{ => data-structure}/src/main/java/com/github/wdn/coding2017/basic/BinaryTreeNode.java (100%) rename group24/626451284/{ => data-structure}/src/main/java/com/github/wdn/coding2017/basic/Iterator.java (100%) rename group24/626451284/{ => data-structure}/src/main/java/com/github/wdn/coding2017/basic/LinkedList.java (54%) rename group24/626451284/{ => data-structure}/src/main/java/com/github/wdn/coding2017/basic/List.java (100%) rename group24/626451284/{ => data-structure}/src/main/java/com/github/wdn/coding2017/basic/Queue.java (100%) rename group24/626451284/{ => data-structure}/src/main/java/com/github/wdn/coding2017/basic/Stack.java (100%) create mode 100644 group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/lru/LRUPageFrame.java create mode 100644 group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/lru/LRUPageFrameTest.java create mode 100644 group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/lru/LinkedList.java rename group24/626451284/{ => data-structure}/src/main/java/com/github/wdn/coding2017/coderising/array/ArrayUtil.java (100%) rename group24/626451284/{ => data-structure}/src/main/java/com/github/wdn/coding2017/coderising/array/ArrayUtilTest.java (100%) rename group24/626451284/{ => data-structure}/src/main/java/com/github/wdn/coding2017/coderising/download/DownloadThread.java (100%) rename group24/626451284/{ => data-structure}/src/main/java/com/github/wdn/coding2017/coderising/download/FileDownloader.java (100%) rename group24/626451284/{ => data-structure}/src/main/java/com/github/wdn/coding2017/coderising/download/FileDownloaderTest.java (100%) rename group24/626451284/{ => data-structure}/src/main/java/com/github/wdn/coding2017/coderising/download/api/Connection.java (100%) rename group24/626451284/{ => data-structure}/src/main/java/com/github/wdn/coding2017/coderising/download/api/ConnectionException.java (100%) rename group24/626451284/{ => data-structure}/src/main/java/com/github/wdn/coding2017/coderising/download/api/ConnectionManager.java (100%) rename group24/626451284/{ => data-structure}/src/main/java/com/github/wdn/coding2017/coderising/download/api/DownloadListener.java (100%) rename group24/626451284/{ => data-structure}/src/main/java/com/github/wdn/coding2017/coderising/download/impl/ConnectionImpl.java (100%) rename group24/626451284/{ => data-structure}/src/main/java/com/github/wdn/coding2017/coderising/download/impl/ConnectionManagerImpl.java (100%) rename group24/626451284/{ => data-structure}/src/main/java/com/github/wdn/coding2017/coderising/litestruts/LoginAction.java (100%) rename group24/626451284/{ => data-structure}/src/main/java/com/github/wdn/coding2017/coderising/litestruts/Struts.java (100%) rename group24/626451284/{ => data-structure}/src/main/java/com/github/wdn/coding2017/coderising/litestruts/StrutsTest.java (100%) rename group24/626451284/{ => data-structure}/src/main/java/com/github/wdn/coding2017/coderising/litestruts/View.java (100%) create mode 100644 group24/626451284/data-structure/src/main/test/com/github/wdn/coding2017/basic/LinkedListTest.java create mode 100644 group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/loader/ClassFileLoader.java create mode 100644 group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/test/ClassFileloaderTest.java create mode 100644 group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/test/EmployeeV1.java delete mode 100644 group24/626451284/pom.xml delete mode 100644 group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/litestruts/struts.xml diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/basic/ArrayList.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/ArrayList.java similarity index 100% rename from group24/626451284/src/main/java/com/github/wdn/coding2017/basic/ArrayList.java rename to group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/ArrayList.java diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/basic/BinaryTreeNode.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/BinaryTreeNode.java similarity index 100% rename from group24/626451284/src/main/java/com/github/wdn/coding2017/basic/BinaryTreeNode.java rename to group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/BinaryTreeNode.java diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/basic/Iterator.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/Iterator.java similarity index 100% rename from group24/626451284/src/main/java/com/github/wdn/coding2017/basic/Iterator.java rename to group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/Iterator.java diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/basic/LinkedList.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/LinkedList.java similarity index 54% rename from group24/626451284/src/main/java/com/github/wdn/coding2017/basic/LinkedList.java rename to group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/LinkedList.java index 6040cb5a47..089e0f2210 100644 --- a/group24/626451284/src/main/java/com/github/wdn/coding2017/basic/LinkedList.java +++ b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/LinkedList.java @@ -40,6 +40,7 @@ public void add(int index , Object o){ newNode.setPre(pre); newNode.setNext(indexNode); indexNode.setPre(newNode); + size++; } private void checkIndex(int index){ if(index >= size || index <0){ @@ -56,8 +57,10 @@ private Node getNode(int index){ if(index==size-1){ return tail; } + Node current = head; for (int i = 0; i < index; i++) { - result = head.getNext(); + result = current.getNext(); + current = result; } return result; } @@ -79,6 +82,7 @@ public Object remove(int index){ }else{ tail = pre; } + size--; return indexNode.getData(); } @@ -91,25 +95,43 @@ public void addFirst(Object o){ head.setPre(newNode); newNode.setNext(head); head = newNode; + size++; } public void addLast(Object o){ Node newNode = new Node(o); tail.setNext(newNode); newNode.setPre(tail); tail = newNode; + size++; } public Object removeFirst(){ + if(size<1){ + throw new IllegalArgumentException(); + } + if(size==1){ + tail=null; + } Node next = head.getNext(); Node oldHead = head; - head = next; head.setPre(null); + head = next; + oldHead.setNext(null); + size--; return oldHead; } public Object removeLast(){ + if(size<1){ + throw new IllegalArgumentException(); + } + if(size==1){ + head=null; + } Node oldTail = tail; Node pre = tail.getPre(); tail = pre; tail.setNext(null); + oldTail.setPre(null); + size--; return oldTail; } public Iterator iterator(){ @@ -161,6 +183,28 @@ public void setPre(Node pre) { * 例如链表为 3->7->10 , 逆置后变为 10->7->3 */ public void reverse(){ + Node current = head; + Node next = current.getNext(); + Node pre = current.getPre(); + while(next!=null){ + Node nNext = next.getNext(); + if(pre!=null){ + pre.setPre(current); + } + if(current!=null){ + current.setPre(next); + current.setNext(pre); + } + if(next!=null){ + next.setNext(current); + } + pre = current; + current = next; + next = nNext; + } + Node oldHead = head; + head = tail; + tail = oldHead; } /** @@ -170,16 +214,54 @@ public void reverse(){ */ public void removeFirstHalf(){ - + int removeSize = size/2; + for (int i = 0; i < removeSize; i++) { + removeFirst(); + } } /** * 从第i个元素开始, 删除length 个元素 , 注意i从0开始 - * @param i - * @param length + * @param start 开始位置 + * @param length 长度 */ - public void remove(int i, int length){ + public void remove(int start, int length){ + checkIndex(start); + if(length<1){ + return; + } + if(start==0 && length>=size){ + int removeSum = size; + for (int j = 0; j < removeSum; j++) { + removeFirst(); + } + size = size-length; + return; + } + int customMaxIndex = start+length; + int endIndex = customMaxIndex < size ? customMaxIndex : size; + if(start==0){ + for (int j = 0; j < length; j++) { + removeFirst(); + } + size = size-length; + return; + } + if(endIndex==size){ + int removeSum = size-start; + for (int j = 0; j < removeSum; j++) { + removeLast(); + } + return; + } + Node startNode = getNode(start-1); + Node endNode = getNode(endIndex); + startNode.getNext().setPre(null); + startNode.setNext(endNode); + endNode.getPre().setNext(null); + endNode.setPre(startNode); + size = size-length; } /** * 假定当前链表和list均包含已升序排列的整数 @@ -189,8 +271,24 @@ public void remove(int i, int length){ * 返回的结果应该是[101,301,401,601] * @param list */ - public static int[] getElements(LinkedList list){ - return null; + public int[] getElements(LinkedList list){ + for (int i = 0; i < list.size; i++) { + if(Integer.parseInt(list.get(i).toString())>=this.size){ + throw new IndexOutOfBoundsException(); + } + } + int[] result = new int[list.size]; + int index = 0; + for (int i = 0; i < this.size; i++) { + if (index==list.size()){ + break; + } + if(Integer.parseInt(list.get(index).toString())==i){ + result[index] = Integer.parseInt(this.get(i).toString()); + index++; + } + } + return result; } /** @@ -201,7 +299,22 @@ public static int[] getElements(LinkedList list){ */ public void subtract(LinkedList list){ - + int index = 0; + Object compare = list.get(index); + Node current = head; + while(current!=null && compare!=null){ + Node preCurrent = current; + current = current.getNext(); + // TODO 这里不能删除重复元素只能删除一次 + if(preCurrent.getData().equals(compare)){ + preCurrent.getPre().setNext(preCurrent.getNext()); + preCurrent.getNext().setPre(preCurrent.getPre()); + preCurrent.setPre(null); + preCurrent.setNext(null); + size--; + compare = ++index < list.size ? list.get(index) : null; + } + } } /** @@ -209,7 +322,24 @@ public void subtract(LinkedList list){ * 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) */ public void removeDuplicateValues(){ - + Node current = head; + Node next = current.getNext(); + while (next!=null){ + if(next.getData().equals(current.getData())){ + Node preNext = next; + next = preNext.getNext(); + current.setNext(preNext.getNext()); + if (next != null) { + next.setPre(current); + } + preNext.setPre(null); + preNext.setNext(null); + size--; + }else{ + current = next; + next = next.getNext(); + } + } } /** @@ -219,7 +349,23 @@ public void removeDuplicateValues(){ * @param max */ public void removeRange(int min, int max){ - + int minIndex = -1; + int maxIndex = -1; + int index = 0; + Node current = head; + while (current!=null){ + if(current.getData().equals(min)){ + minIndex = index; + } + if(current.getData().equals(max)){ + maxIndex = index; + } + index++; + current = current.getNext(); + } + if (minIndex > -1 && maxIndex > -1 && min <= max && minIndex + 1 < size) { + remove(minIndex + 1, maxIndex - minIndex - 1); + } } /** @@ -230,4 +376,17 @@ public void removeRange(int min, int max){ public LinkedList intersection( LinkedList list){ return null; } + @Override + public String toString(){ + StringBuffer stringBuffer = new StringBuffer(); + stringBuffer.append("["); + for (int i = 0; i < size; i++) { + stringBuffer.append(get(i)); + if(i!=size-1){ + stringBuffer.append(","); + } + } + stringBuffer.append("]"); + return stringBuffer.toString(); + } } diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/basic/List.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/List.java similarity index 100% rename from group24/626451284/src/main/java/com/github/wdn/coding2017/basic/List.java rename to group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/List.java diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/basic/Queue.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/Queue.java similarity index 100% rename from group24/626451284/src/main/java/com/github/wdn/coding2017/basic/Queue.java rename to group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/Queue.java diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/basic/Stack.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/Stack.java similarity index 100% rename from group24/626451284/src/main/java/com/github/wdn/coding2017/basic/Stack.java rename to group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/Stack.java diff --git a/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/lru/LRUPageFrame.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/lru/LRUPageFrame.java new file mode 100644 index 0000000000..fbaea5e4a7 --- /dev/null +++ b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/lru/LRUPageFrame.java @@ -0,0 +1,60 @@ +package com.github.wdn.coding2017.basic.lru; + +/** + * 用双向链表实现LRU算法 + * @author liuxin + * + */ +public class LRUPageFrame { + + private static class Node { + + Node prev; + Node next; + int pageNum; + + Node() { + } + } + + private int capacity; + + + private Node first;// 链表头 + private Node last;// 链表尾 + + + public LRUPageFrame(int capacity) { + + this.capacity = capacity; + + } + + /** + * 获取缓存中对象 + * + * @param key + * @return + */ + public void access(int pageNum) { + + + } + + + + public String toString(){ + StringBuilder buffer = new StringBuilder(); + Node node = first; + while(node != null){ + buffer.append(node.pageNum); + + node = node.next; + if(node != null){ + buffer.append(","); + } + } + return buffer.toString(); + } + +} diff --git a/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/lru/LRUPageFrameTest.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/lru/LRUPageFrameTest.java new file mode 100644 index 0000000000..62edda7ec8 --- /dev/null +++ b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/lru/LRUPageFrameTest.java @@ -0,0 +1,31 @@ +package com.github.wdn.coding2017.basic.lru; + +import org.junit.Assert; + +import org.junit.Test; + + +public class LRUPageFrameTest { + + @Test + public void testAccess() { + LRUPageFrame frame = new LRUPageFrame(3); + frame.access(7); + frame.access(0); + frame.access(1); + Assert.assertEquals("1,0,7", frame.toString()); + frame.access(2); + Assert.assertEquals("2,1,0", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(3); + Assert.assertEquals("3,0,2", frame.toString()); + frame.access(0); + Assert.assertEquals("0,3,2", frame.toString()); + frame.access(4); + Assert.assertEquals("4,0,3", frame.toString()); + } + +} diff --git a/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/lru/LinkedList.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/lru/LinkedList.java new file mode 100644 index 0000000000..0553f5357e --- /dev/null +++ b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/lru/LinkedList.java @@ -0,0 +1,126 @@ +package com.github.wdn.coding2017.basic.lru; + + +import com.github.wdn.coding2017.basic.Iterator; +import com.github.wdn.coding2017.basic.List; + +public class LinkedList implements List { + + private Node head; + + public void add(Object o){ + + } + public void add(int index , Object o){ + + } + public Object get(int index){ + return null; + } + public Object remove(int index){ + return null; + } + + public int size(){ + return -1; + } + + public void addFirst(Object o){ + + } + public void addLast(Object o){ + + } + public Object removeFirst(){ + return null; + } + public Object removeLast(){ + return null; + } + public Iterator iterator(){ + return null; + } + + + private static class Node{ + Object data; + Node next; + + } + + /** + * 把该链表逆置 + * 例如链表为 3->7->10 , 逆置后变为 10->7->3 + */ + public void reverse(){ + + } + + /** + * 删除一个单链表的前半部分 + * 例如:list = 2->5->7->8 , 删除以后的值为 7->8 + * 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10 + + */ + public void removeFirstHalf(){ + + } + + /** + * 从第i个元素开始, 删除length 个元素 , 注意i从0开始 + * @param i + * @param length + */ + public void remove(int i, int length){ + + } + /** + * 假定当前链表和listB均包含已升序排列的整数 + * 从当前链表中取出那些listB所指定的元素 + * 例如当前链表 = 11->101->201->301->401->501->601->701 + * listB = 1->3->4->6 + * 返回的结果应该是[101,301,401,601] + * @param list + */ + public int[] getElements(LinkedList list){ + return null; + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 从当前链表中中删除在listB中出现的元素 + + * @param list + */ + + public void subtract(LinkedList list){ + + } + + /** + * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) + */ + public void removeDuplicateValues(){ + + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 试写一高效的算法,删除表中所有值大于min且小于max的元素(若表中存在这样的元素) + * @param min + * @param max + */ + public void removeRange(int min, int max){ + + } + + /** + * 假设当前链表和参数list指定的链表均以元素依值递增有序排列(同一表中的元素值各不相同) + * 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列 + * @param list + */ + public LinkedList intersection( LinkedList list){ + return null; + } +} diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/array/ArrayUtil.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/array/ArrayUtil.java similarity index 100% rename from group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/array/ArrayUtil.java rename to group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/array/ArrayUtil.java diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/array/ArrayUtilTest.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/array/ArrayUtilTest.java similarity index 100% rename from group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/array/ArrayUtilTest.java rename to group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/array/ArrayUtilTest.java diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/DownloadThread.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/download/DownloadThread.java similarity index 100% rename from group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/DownloadThread.java rename to group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/download/DownloadThread.java diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/FileDownloader.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/download/FileDownloader.java similarity index 100% rename from group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/FileDownloader.java rename to group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/download/FileDownloader.java diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/FileDownloaderTest.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/download/FileDownloaderTest.java similarity index 100% rename from group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/FileDownloaderTest.java rename to group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/download/FileDownloaderTest.java diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/api/Connection.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/download/api/Connection.java similarity index 100% rename from group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/api/Connection.java rename to group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/download/api/Connection.java diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/api/ConnectionException.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/download/api/ConnectionException.java similarity index 100% rename from group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/api/ConnectionException.java rename to group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/download/api/ConnectionException.java diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/api/ConnectionManager.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/download/api/ConnectionManager.java similarity index 100% rename from group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/api/ConnectionManager.java rename to group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/download/api/ConnectionManager.java diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/api/DownloadListener.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/download/api/DownloadListener.java similarity index 100% rename from group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/api/DownloadListener.java rename to group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/download/api/DownloadListener.java diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/impl/ConnectionImpl.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/download/impl/ConnectionImpl.java similarity index 100% rename from group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/impl/ConnectionImpl.java rename to group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/download/impl/ConnectionImpl.java diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/impl/ConnectionManagerImpl.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/download/impl/ConnectionManagerImpl.java similarity index 100% rename from group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/download/impl/ConnectionManagerImpl.java rename to group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/download/impl/ConnectionManagerImpl.java diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/litestruts/LoginAction.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/litestruts/LoginAction.java similarity index 100% rename from group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/litestruts/LoginAction.java rename to group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/litestruts/LoginAction.java diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/litestruts/Struts.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/litestruts/Struts.java similarity index 100% rename from group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/litestruts/Struts.java rename to group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/litestruts/Struts.java diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/litestruts/StrutsTest.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/litestruts/StrutsTest.java similarity index 100% rename from group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/litestruts/StrutsTest.java rename to group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/litestruts/StrutsTest.java diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/litestruts/View.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/litestruts/View.java similarity index 100% rename from group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/litestruts/View.java rename to group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/coderising/litestruts/View.java diff --git a/group24/626451284/data-structure/src/main/test/com/github/wdn/coding2017/basic/LinkedListTest.java b/group24/626451284/data-structure/src/main/test/com/github/wdn/coding2017/basic/LinkedListTest.java new file mode 100644 index 0000000000..7a967cea64 --- /dev/null +++ b/group24/626451284/data-structure/src/main/test/com/github/wdn/coding2017/basic/LinkedListTest.java @@ -0,0 +1,91 @@ +package com.github.wdn.coding2017.basic; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; + +/** + * Created by Administrator on 2017/4/3 0003. + */ +public class LinkedListTest { + LinkedList linkedList = new LinkedList(); + @Before + public void initLinkedList(){ + for (int i = 0; i < 12; i++) { + linkedList.add(i); + } + } + @Test + public void testReverse(){ + + System.out.println(linkedList.size()); + System.out.println(linkedList); + linkedList.reverse(); + System.out.println(""); + System.out.println(linkedList); + } + @Test + public void testRemoveFirstHalf(){ + System.out.println(linkedList); + linkedList.removeFirstHalf(); + System.out.println(linkedList); + } + @Test + public void testRemove(){ + System.out.println(linkedList); + //linkedList.remove(0,30); + //System.out.println(linkedList); + //linkedList.remove(2,30); + //System.out.println(linkedList); + linkedList.remove(2,0); + System.out.println(linkedList); + } + @Test + public void testGetElements(){ + LinkedList indexs = new LinkedList(); + indexs.add(3); + indexs.add(5); + indexs.add(7); + indexs.add(9); + int[] result = linkedList.getElements(indexs); + System.out.println(Arrays.toString(result)); + Assert.assertArrayEquals(new int[]{3, 5, 7, 9},result); + } + @Test + public void testSubtract(){ + LinkedList indexs = new LinkedList(); + indexs.add(3); + indexs.add(5); + indexs.add(7); + indexs.add(9); + linkedList.subtract(indexs); + System.out.println(linkedList); + System.out.println(linkedList.size()); + } + @Test + public void testRemoveDuplicateValues(){ + LinkedList list = new LinkedList(); + list.add(3); + //list.add(3); + list.add(5); + //list.add(5); + list.add(7); + list.add(7); + list.add(9); + list.add(9); + list.removeDuplicateValues(); + System.out.println(list); + } + @Test + public void testRemoveRange(){ + LinkedList indexs = new LinkedList(); + indexs.add(3); + indexs.add(5); + indexs.add(7); + indexs.add(9); + indexs.removeRange(9, 9); + System.out.println(indexs); + } +} diff --git a/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/loader/ClassFileLoader.java b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..53a9c12ece --- /dev/null +++ b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/loader/ClassFileLoader.java @@ -0,0 +1,34 @@ +package com.github.wdn.coding2017.jvm.loader; + +import java.util.ArrayList; +import java.util.List; + + + +public class ClassFileLoader { + + private List clzPaths = new ArrayList(); + + public byte[] readBinaryCode(String className) { + + return null; + + + } + + + public void addClassPath(String path) { + + } + + + + public String getClassPath(){ + return null; + } + + + + + +} diff --git a/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/test/ClassFileloaderTest.java b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..141ecb4b78 --- /dev/null +++ b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,92 @@ +package com.github.wdn.coding2017.jvm.test; + +import com.github.wdn.coding2017.jvm.loader.ClassFileLoader; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + + + + + +public class ClassFileloaderTest { + + + static String path1 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\mini-jvm\\bin"; + static String path2 = "C:\temp"; + + + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testClassPath(){ + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + loader.addClassPath(path2); + + String clzPath = loader.getClassPath(); + + Assert.assertEquals(path1+";"+path2,clzPath); + + } + + @Test + public void testClassFileLength() { + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + + String className = "com.coderising.jvm.test.EmployeeV1"; + + byte[] byteCodes = loader.readBinaryCode(className); + + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + Assert.assertEquals(1056, byteCodes.length); + + } + + + @Test + public void testMagicNumber(){ + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "com.coderising.jvm.test.EmployeeV1"; + byte[] byteCodes = loader.readBinaryCode(className); + byte[] codes = new byte[]{byteCodes[0],byteCodes[1],byteCodes[2],byteCodes[3]}; + + + String acctualValue = this.byteToHexString(codes); + + Assert.assertEquals("cafebabe", acctualValue); + } + + + + + + + private String byteToHexString(byte[] codes ){ + StringBuffer buffer = new StringBuffer(); + for(int i=0;i - - 4.0.0 - - com.github.wdn - coding2017 - 1.0-SNAPSHOT - \ No newline at end of file diff --git a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/litestruts/struts.xml b/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/litestruts/struts.xml deleted file mode 100644 index fb12bdc239..0000000000 --- a/group24/626451284/src/main/java/com/github/wdn/coding2017/coderising/litestruts/struts.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - /jsp/homepage.jsp - /jsp/showLogin.jsp - - - /jsp/welcome.jsp - /jsp/error.jsp - - From e7ec67889ae24f6a895d69511bc18864eaab36ed Mon Sep 17 00:00:00 2001 From: wdn <626451284@163.com> Date: Tue, 4 Apr 2017 14:08:47 +0800 Subject: [PATCH 054/203] =?UTF-8?q?=E5=AE=9E=E7=8E=B0lru=E7=AE=97=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wdn/coding2017/basic/LinkedList.java | 8 ++ .../coding2017/basic/lru/LRUPageFrame.java | 57 ++++---- .../wdn/coding2017/basic/lru/LinkedList.java | 126 ------------------ 3 files changed, 31 insertions(+), 160 deletions(-) delete mode 100644 group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/lru/LinkedList.java diff --git a/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/LinkedList.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/LinkedList.java index 089e0f2210..55d8839b02 100644 --- a/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/LinkedList.java +++ b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/LinkedList.java @@ -92,12 +92,20 @@ public int size(){ public void addFirst(Object o){ Node newNode = new Node(o); + if (size==0){ + add(o); + return; + } head.setPre(newNode); newNode.setNext(head); head = newNode; size++; } public void addLast(Object o){ + if (size == 0) { + add(o); + return; + } Node newNode = new Node(o); tail.setNext(newNode); newNode.setPre(tail); diff --git a/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/lru/LRUPageFrame.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/lru/LRUPageFrame.java index fbaea5e4a7..7e3c07737d 100644 --- a/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/lru/LRUPageFrame.java +++ b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/lru/LRUPageFrame.java @@ -1,60 +1,49 @@ package com.github.wdn.coding2017.basic.lru; +import com.github.wdn.coding2017.basic.LinkedList; + /** * 用双向链表实现LRU算法 * @author liuxin * */ public class LRUPageFrame { - - private static class Node { - - Node prev; - Node next; - int pageNum; - - Node() { - } - } - private int capacity; - - - private Node first;// 链表头 - private Node last;// 链表尾 - - + private LinkedList cache = new LinkedList(); public LRUPageFrame(int capacity) { - this.capacity = capacity; - } /** * 获取缓存中对象 * - * @param key + * @param pageNum * @return */ public void access(int pageNum) { - + if(capacity==cache.size()){ + int exist = exist(pageNum); + if(exist>-1){ + cache.addFirst(cache.remove(exist)); + }else{ + cache.removeLast(); + cache.addFirst(pageNum); + } + }else { + cache.addFirst(pageNum); + } } - - - - public String toString(){ - StringBuilder buffer = new StringBuilder(); - Node node = first; - while(node != null){ - buffer.append(node.pageNum); - - node = node.next; - if(node != null){ - buffer.append(","); + private int exist(int pageNum){ + for (int i = 0; i < cache.size(); i++) { + if(cache.get(i).equals(pageNum)){ + return i; } } - return buffer.toString(); + return -1; + } + public String toString(){ + return cache.toString().replace("[","").replace("]",""); } } diff --git a/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/lru/LinkedList.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/lru/LinkedList.java deleted file mode 100644 index 0553f5357e..0000000000 --- a/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/lru/LinkedList.java +++ /dev/null @@ -1,126 +0,0 @@ -package com.github.wdn.coding2017.basic.lru; - - -import com.github.wdn.coding2017.basic.Iterator; -import com.github.wdn.coding2017.basic.List; - -public class LinkedList implements List { - - private Node head; - - public void add(Object o){ - - } - public void add(int index , Object o){ - - } - public Object get(int index){ - return null; - } - public Object remove(int index){ - return null; - } - - public int size(){ - return -1; - } - - public void addFirst(Object o){ - - } - public void addLast(Object o){ - - } - public Object removeFirst(){ - return null; - } - public Object removeLast(){ - return null; - } - public Iterator iterator(){ - return null; - } - - - private static class Node{ - Object data; - Node next; - - } - - /** - * 把该链表逆置 - * 例如链表为 3->7->10 , 逆置后变为 10->7->3 - */ - public void reverse(){ - - } - - /** - * 删除一个单链表的前半部分 - * 例如:list = 2->5->7->8 , 删除以后的值为 7->8 - * 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10 - - */ - public void removeFirstHalf(){ - - } - - /** - * 从第i个元素开始, 删除length 个元素 , 注意i从0开始 - * @param i - * @param length - */ - public void remove(int i, int length){ - - } - /** - * 假定当前链表和listB均包含已升序排列的整数 - * 从当前链表中取出那些listB所指定的元素 - * 例如当前链表 = 11->101->201->301->401->501->601->701 - * listB = 1->3->4->6 - * 返回的结果应该是[101,301,401,601] - * @param list - */ - public int[] getElements(LinkedList list){ - return null; - } - - /** - * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 - * 从当前链表中中删除在listB中出现的元素 - - * @param list - */ - - public void subtract(LinkedList list){ - - } - - /** - * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 - * 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) - */ - public void removeDuplicateValues(){ - - } - - /** - * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 - * 试写一高效的算法,删除表中所有值大于min且小于max的元素(若表中存在这样的元素) - * @param min - * @param max - */ - public void removeRange(int min, int max){ - - } - - /** - * 假设当前链表和参数list指定的链表均以元素依值递增有序排列(同一表中的元素值各不相同) - * 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列 - * @param list - */ - public LinkedList intersection( LinkedList list){ - return null; - } -} From c676a45356275d00096ab2f2040e6b169bea45c4 Mon Sep 17 00:00:00 2001 From: wdn <626451284@163.com> Date: Tue, 4 Apr 2017 15:08:32 +0800 Subject: [PATCH 055/203] =?UTF-8?q?=E5=AE=8C=E6=88=90jvm=E7=AC=AC=E4=B8=80?= =?UTF-8?q?=E6=AC=A1=E4=BD=9C=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jvm/loader/ClassFileLoader.java | 58 +++++++++++++++++-- .../jvm/test/ClassFileloaderTest.java | 11 ++-- 2 files changed, 57 insertions(+), 12 deletions(-) diff --git a/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/loader/ClassFileLoader.java b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/loader/ClassFileLoader.java index 53a9c12ece..20c8183f3a 100644 --- a/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/loader/ClassFileLoader.java +++ b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/loader/ClassFileLoader.java @@ -1,5 +1,11 @@ package com.github.wdn.coding2017.jvm.loader; +import org.apache.commons.io.FileUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -10,21 +16,61 @@ public class ClassFileLoader { private List clzPaths = new ArrayList(); public byte[] readBinaryCode(String className) { - - return null; - - + File file = null; + for (int i = 0; i < clzPaths.size(); i++) { + String path = clzPaths.get(i); + String fullPath = path +File.separator+ className.replace(".", File.separator)+".class"; + file = new File(fullPath); + } + + try { + if(file.exists()){ + // 使用FileUtils最简单 + // return FileUtils.readFileToByteArray(file); + FileInputStream inputStream = new FileInputStream(file); + long fileLength = file.length(); + if (fileLength>Integer.MAX_VALUE) { + throw new IllegalArgumentException("Size cannot be greater than Integer max value: " + fileLength); + } + byte[] fileBytes = new byte[(int)fileLength]; + byte[] bytes = new byte[1024]; + int len; + int offset=0; + // for循环使用inputStream api读取 一次读完。。 + for(offset = 0; offset < fileLength && (len = inputStream.read(fileBytes, offset, (int)fileLength - offset)) != -1; offset += len) { + System.out.println("dd"); + } + // while循环使用System.arraycopy读取 + /*while ((len = inputStream.read(bytes))>-1){ + System.arraycopy(bytes, 0, fileBytes, offset, len); + offset += len; + }*/ + return fileBytes; + } + throw new FileNotFoundException(); + } catch (IOException e) { + e.printStackTrace(); + } + return null; } public void addClassPath(String path) { - + clzPaths.add(path); } public String getClassPath(){ - return null; + StringBuffer stringBuffer = new StringBuffer(); + for (int i = 0; i < clzPaths.size(); i++) { + if (i==clzPaths.size()-1) { + stringBuffer.append(clzPaths.get(i)); + }else{ + stringBuffer.append(clzPaths.get(i)).append(";"); + } + } + return stringBuffer.toString(); } diff --git a/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/test/ClassFileloaderTest.java b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/test/ClassFileloaderTest.java index 141ecb4b78..346159abb5 100644 --- a/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/test/ClassFileloaderTest.java +++ b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/test/ClassFileloaderTest.java @@ -14,8 +14,8 @@ public class ClassFileloaderTest { - static String path1 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\mini-jvm\\bin"; - static String path2 = "C:\temp"; + static String path1 = "E:\\softdata\\ideaworkspace\\self\\coding2017\\group24\\626451284\\mini-jvm\\target\\classes"; + static String path2 = "E:\\temp"; @@ -46,12 +46,12 @@ public void testClassFileLength() { ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); - String className = "com.coderising.jvm.test.EmployeeV1"; + String className = "com.github.wdn.coding2017.jvm.test.EmployeeV1"; byte[] byteCodes = loader.readBinaryCode(className); // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 - Assert.assertEquals(1056, byteCodes.length); + Assert.assertEquals(1078, byteCodes.length); } @@ -60,13 +60,12 @@ public void testClassFileLength() { public void testMagicNumber(){ ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); - String className = "com.coderising.jvm.test.EmployeeV1"; + String className = "com.github.wdn.coding2017.jvm.test.EmployeeV1"; byte[] byteCodes = loader.readBinaryCode(className); byte[] codes = new byte[]{byteCodes[0],byteCodes[1],byteCodes[2],byteCodes[3]}; String acctualValue = this.byteToHexString(codes); - Assert.assertEquals("cafebabe", acctualValue); } From e18897028bb21f136eacf0cc0f76f27fb1bdfe92 Mon Sep 17 00:00:00 2001 From: liangduoduo666666 <798277403@qq.com> Date: Tue, 4 Apr 2017 19:19:27 +0800 Subject: [PATCH 056/203] =?UTF-8?q?zl=E8=A1=A5=E4=BA=A4=E7=AC=AC=E4=B8=89?= =?UTF-8?q?=E5=91=A8=E7=AC=AC=E5=9B=9B=E5=91=A8=E4=BD=9C=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group24/798277403/src/week1/LinkedList.java | 73 ++++ .../798277403/src/week3/DownloadThread.java | 50 +++ .../798277403/src/week3/FileDownloader.java | 116 ++++++ .../798277403/src/week3/api/Connection.java | 23 ++ .../src/week3/api/ConnectionException.java | 7 + .../src/week3/api/ConnectionManager.java | 10 + .../src/week3/api/DownloadListener.java | 5 + .../src/week3/impl/ConnectionImpl.java | 73 ++++ .../src/week3/impl/ConnectionManagerImpl.java | 14 + .../src/week3/linkedlist/LinkedList.java | 360 ++++++++++++++++++ .../src/week3/linkedlist/LinkedListTest.java | 121 ++++++ .../798277403/src/week3/linkedlist/List.java | 13 + .../src/week3/test/ConnectionTest.java | 52 +++ .../src/week3/test/FileDownloaderTest.java | 62 +++ .../798277403/src/week4/LRU/LRUPageFrame.java | 130 +++++++ .../src/week4/LRU/LRUPageFrameTest.java | 33 ++ .../src/week4/LRU/MyLRUPageFrame.java | 133 +++++++ .../src/week4/loader/ClassFileLoader.java | 67 ++++ .../src/week4/test/ClassFileloaderTest.java | 84 ++++ .../798277403/src/week4/test/EmployeeV1.java | 29 ++ 20 files changed, 1455 insertions(+) create mode 100644 group24/798277403/src/week3/DownloadThread.java create mode 100644 group24/798277403/src/week3/FileDownloader.java create mode 100644 group24/798277403/src/week3/api/Connection.java create mode 100644 group24/798277403/src/week3/api/ConnectionException.java create mode 100644 group24/798277403/src/week3/api/ConnectionManager.java create mode 100644 group24/798277403/src/week3/api/DownloadListener.java create mode 100644 group24/798277403/src/week3/impl/ConnectionImpl.java create mode 100644 group24/798277403/src/week3/impl/ConnectionManagerImpl.java create mode 100644 group24/798277403/src/week3/linkedlist/LinkedList.java create mode 100644 group24/798277403/src/week3/linkedlist/LinkedListTest.java create mode 100644 group24/798277403/src/week3/linkedlist/List.java create mode 100644 group24/798277403/src/week3/test/ConnectionTest.java create mode 100644 group24/798277403/src/week3/test/FileDownloaderTest.java create mode 100644 group24/798277403/src/week4/LRU/LRUPageFrame.java create mode 100644 group24/798277403/src/week4/LRU/LRUPageFrameTest.java create mode 100644 group24/798277403/src/week4/LRU/MyLRUPageFrame.java create mode 100644 group24/798277403/src/week4/loader/ClassFileLoader.java create mode 100644 group24/798277403/src/week4/test/ClassFileloaderTest.java create mode 100644 group24/798277403/src/week4/test/EmployeeV1.java diff --git a/group24/798277403/src/week1/LinkedList.java b/group24/798277403/src/week1/LinkedList.java index d0933cfcb1..e0160d0e5f 100644 --- a/group24/798277403/src/week1/LinkedList.java +++ b/group24/798277403/src/week1/LinkedList.java @@ -158,4 +158,77 @@ private static class Node{ this.value = e; } } + + /** + * 把该链表逆置 + * 例如链表为 3->7->10 , 逆置后变为 10->7->3 + */ + public void reverse(){ + + } + + /** + * 删除一个单链表的前半部分 + * 例如:list = 2->5->7->8 , 删除以后的值为 7->8 + * 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10 + */ + public void removeFirstHalf(){ + + } + + /** + * 从第i个元素开始, 删除length 个元素 , 注意i从0开始 + * @param i + * @param length + */ + public void remove(int i, int length){ + + } + /** + * 假定当前链表和listB均包含已升序排列的整数 + * 从当前链表中取出那些listB所指定的元素 + * 例如当前链表 = 11->101->201->301->401->501->601->701 + * listB = 1->3->4->6 + * 返回的结果应该是[101,301,401,601] + * @param list + */ + public int[] getElements(LinkedList list){ + return null; + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 从当前链表中中删除在listB中出现的元素 + * @param list + */ + public void subtract(LinkedList list){ + + } + + /** + * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) + */ + public void removeDuplicateValues(){ + + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 试写一高效的算法,删除表中所有值大于min且小于max的元素(若表中存在这样的元素) + * @param min + * @param max + */ + public void removeRange(int min, int max){ + + } + + /** + * 假设当前链表和参数list指定的链表均以元素依值递增有序排列(同一表中的元素值各不相同) + * 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列 + * @param list + */ + public LinkedList intersection( LinkedList list){ + return null; + } } diff --git a/group24/798277403/src/week3/DownloadThread.java b/group24/798277403/src/week3/DownloadThread.java new file mode 100644 index 0000000000..6361f6b394 --- /dev/null +++ b/group24/798277403/src/week3/DownloadThread.java @@ -0,0 +1,50 @@ +package week3; + + +import week3.api.Connection; + +import java.io.RandomAccessFile; +import java.util.concurrent.CyclicBarrier; + +class DownloadThread extends Thread{ + + private Connection conn; + private int startPos; + private int endPos; + private CyclicBarrier barrier; + private String localFile; + public DownloadThread( Connection conn, int startPos, int endPos, String localFile, CyclicBarrier barrier){ + + this.conn = conn; + this.startPos = startPos; + this.endPos = endPos; + this.localFile = localFile; + this.barrier = barrier; + } + public void run(){ + + + try { + System.out.println("Begin to read [" + startPos +"-"+endPos+"]"); + + byte[] data = conn.read(startPos, endPos); + + RandomAccessFile file = new RandomAccessFile(localFile,"rw"); + + file.seek(startPos); + + file.write(data); + + file.close(); + + conn.close(); + + barrier.await(); //等待别的线程完成 + + } catch (Exception e) { + e.printStackTrace(); + + } + + } +} diff --git a/group24/798277403/src/week3/FileDownloader.java b/group24/798277403/src/week3/FileDownloader.java new file mode 100644 index 0000000000..912fc47df3 --- /dev/null +++ b/group24/798277403/src/week3/FileDownloader.java @@ -0,0 +1,116 @@ +package week3; + + +import week3.api.Connection; +import week3.api.ConnectionManager; +import week3.api.DownloadListener; + +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.concurrent.CyclicBarrier; + +public class FileDownloader { + + private String url; + private String localFile; + + DownloadListener listener; + + ConnectionManager cm; + + + private static final int DOWNLOAD_TRHEAD_NUM = 3; + + public FileDownloader(String _url, String localFile) { + this.url = _url; + this.localFile = localFile; + + } + + public void execute(){ + // 在这里实现你的代码, 注意: 需要用多线程实现下载 + // 这个类依赖于其他几个接口, 你需要写这几个接口的实现代码 + // (1) ConnectionManager , 可以打开一个连接,通过Connection可以读取其中的一段(用startPos, endPos来指定) + // (2) DownloadListener, 由于是多线程下载, 调用这个类的客户端不知道什么时候结束,所以你需要实现当所有 + // 线程都执行完以后, 调用listener的notifiedFinished方法, 这样客户端就能收到通知。 + // 具体的实现思路: + // 1. 需要调用ConnectionManager的open方法打开连接, 然后通过Connection.getContentLength方法获得文件的长度 + // 2. 至少启动3个线程下载, 注意每个线程需要先调用ConnectionManager的open方法 + // 然后调用read方法, read方法中有读取文件的开始位置和结束位置的参数, 返回值是byte[]数组 + // 3. 把byte数组写入到文件中 + // 4. 所有的线程都下载完成以后, 需要调用listener的notifiedFinished方法 + + // 下面的代码是示例代码, 也就是说只有一个线程, 你需要改造成多线程的。 + + CyclicBarrier barrier = new CyclicBarrier(DOWNLOAD_TRHEAD_NUM , new Runnable(){ + public void run(){ + listener.notifyFinished(); + } + }); + + Connection conn = null; + try { + conn = cm.open(this.url); + int length = conn.getContentLength(); + createPlaceHolderFile(this.localFile, length); + int[][] ranges = allocateDownloadRange(DOWNLOAD_TRHEAD_NUM, length); + for(int i=0; i< DOWNLOAD_TRHEAD_NUM; i++){ + DownloadThread thread = new DownloadThread( + cm.open(url), + ranges[i][0], + ranges[i][1], + localFile, + barrier); + thread.start(); + } + } catch (Exception e) { + e.printStackTrace(); + }finally{ + if(conn != null){ + conn.close(); + } + } + } + + //往文件里面写0,占住磁盘 + private void createPlaceHolderFile(String fileName, int contentLen) throws IOException { + RandomAccessFile file = new RandomAccessFile(fileName,"rw"); + for(int i=0; i totalLen){ + byte[] data = baos.toByteArray(); + return Arrays.copyOf(data, totalLen); + } + return baos.toByteArray(); + } + + @Override + public int getContentLength() { + URLConnection con; + try { + con = url.openConnection(); + return con.getContentLength(); + } catch (IOException e) { + e.printStackTrace(); + } + return -1; + } + + @Override + public void close() { + + } + +} diff --git a/group24/798277403/src/week3/impl/ConnectionManagerImpl.java b/group24/798277403/src/week3/impl/ConnectionManagerImpl.java new file mode 100644 index 0000000000..130d7e5aaa --- /dev/null +++ b/group24/798277403/src/week3/impl/ConnectionManagerImpl.java @@ -0,0 +1,14 @@ +package week3.impl; + +import week3.api.Connection; +import week3.api.ConnectionException; +import week3.api.ConnectionManager; + +public class ConnectionManagerImpl implements ConnectionManager { + + @Override + public Connection open(String url) throws ConnectionException { + return new ConnectionImpl(url); + } + +} diff --git a/group24/798277403/src/week3/linkedlist/LinkedList.java b/group24/798277403/src/week3/linkedlist/LinkedList.java new file mode 100644 index 0000000000..ad4560ad7d --- /dev/null +++ b/group24/798277403/src/week3/linkedlist/LinkedList.java @@ -0,0 +1,360 @@ +package week3.linkedlist; + + +/** + * 自己实现的LinkedList + * Created by zhouliang on 2017-03-10. + */ +class LinkedList implements List{ + + private int size; + private Node first; + private Node last; + + public LinkedList(){ + } + + @Override + public void add(E e) { + Node temp = new Node(e); + if(first != null){ + last.next = temp; + last = temp; + }else{ + first = temp; + last = temp; + } + size++; + } + + /** + * 指定下标添加元素 + * @param index 可以在链表末尾加,就是可以的等于size,不能大于size + * @param e 代表Element + */ + @Override + public void add(int index, E e) { + checkPositionIndex(index); + + Node temp = new Node(e); + if(index == size){ + last.next = temp; + last = temp; + }else{ + Node begin = first; + index--; + while(index>0){ + begin = begin.next; + index--; + } + Node next = begin.next; + begin.next = temp; + temp.next = next; + } + size++; + } + + @Override + public E get(int index) { + checkElementIndex(index); + + Node temp = first; + while(index>0){ + temp = temp.next; + index--; + } + return temp.value; + } + + @Override + public E remove(int index) { + checkElementIndex(index); + + Node temp; + if(index == 0){ + temp = first; + first = first.next; + size--; + return temp.value; + }else{ + temp = first; + index--; + //找到要删除节点的前一个节点 + while(index>0){ + temp = temp.next; + index--; + } + Node removeNode = temp.next; + temp.next = removeNode.next; + size--; + return removeNode.value; + + } + + } + + public E removeLast(){ + return remove(size-1); + } + + public void addFirst(E e){ + Node temp = new Node(e); + if(first == null){ + first = temp; + last = temp; + }else{ + temp.next = first; + first = temp; + } + size++; + } + + public void addLast(E e){ + Node temp = new Node(); + if(first == null){ + first = temp; + last = temp; + }else{ + last.next = temp; + last = temp; + } + size++; + } + + //检查index是否是合法的get下标 + private void checkElementIndex(int index) { + if (!isElementIndex(index)) { + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + + size); + } + } + + private boolean isElementIndex(int index) { + return index >= 0 && index < size; + } + + //检查index是否是合法的add下标 + private void checkPositionIndex(int index) { + if (!isPositionIndex(index)) { + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + + size); + } + } + + private boolean isPositionIndex(int index) { + return index >= 0 && index <= size; + } + + @Override + public int size() { + return size; + } + + private static class Node{ + E value; + Node next; + Node(){ + } + Node(E e){ + this.value = e; + } + } + + + /** + * 把该链表逆置 + * 例如链表为 3->7->10 , 逆置后变为 10->7->3 + */ + public void reverse(){ + Node preNode = first; + + //头尾结点互换位置 + Node node = last; + last = first; + first = node; + + node = preNode.next; + Node nextNode; + + while (node != null) { + nextNode = node.next; + node.next = preNode; + preNode = node; + node = nextNode; + } + } + + /** + * 删除一个单链表的前半部分 + * 例如:list = 2->5->7->8 , 删除以后的值为 7->8 + * 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10 + */ + public void removeFirstHalf(){ + int num = this.size/2; + this.size = this.size - num; + while(num>0){ + //Node temp = first.next; + first = first.next; + num--; + } + } + + /** + * 从第i个元素开始, 删除length 个元素 , 注意i从0开始 + * @param i + * @param length + */ + public void remove(int i, int length){ + checkPositionIndex(i); + if(length+i>size-1){ + throw new IndexOutOfBoundsException("Index: " + (i+length) + ", Size: " + + size); + } + int temp = 0; + Node newFirst = first; + Node beginNode = newFirst; + while(temp < i){ + beginNode = beginNode.next; + temp++; + } + Node endNode = beginNode.next; + size = size - length; + while(length>0){ + endNode = endNode.next; + length--; + } + first = newFirst; + beginNode.next = endNode; + } + + /** + * 假定当前链表和listB均包含已升序排列的整数 + * 从当前链表中取出那些listB所指定的元素 + * 例如当前链表 = 11->101->201->301->401->501->601->701 + * listB = 1->3->4->6 + * 返回的结果应该是[101,301,401,601] + * @param list + */ + public int[] getElements(LinkedList list){ + if(list==null || list.size()==0){ + return null; + }else{ + int[] result = new int[list.size()]; + int index = 0; + int length = 0; + Node temp = first; + for (int i=0; imin && (Integer)temp.value myLinkedList = new week3.linkedlist.LinkedList<>(); + + private java.util.LinkedList systemLinkedList = new java.util.LinkedList<>(); + + @Before + public void setUp(){ + for(int i=0; i<10; i++){ + myLinkedList.add(i); + systemLinkedList.add(i); + } + } + @Test + public void add() throws Exception { + for(int i=0; i<10; i++){ + System.out.println(myLinkedList.get(i)); + } + } + + @Test + public void reverse(){ + myLinkedList.reverse(); + for(int i=0; i<10; i++){ + System.out.println(myLinkedList.get(i)); + } + } + + @Test + public void removeFirstHalf(){ + myLinkedList.removeFirstHalf(); + System.out.println(myLinkedList.size()); + for(int i=0; i list = new LinkedList(); + list.add(0); + list.add(7); + list.add(9); + int[] reuslt = myLinkedList.getElements(list); + System.out.println(reuslt.length); + for(int i=0; i list = new LinkedList(); + list.add(0); + list.add(7); + list.add(9); + myLinkedList.subtract(list); + for(int i=0; i list = new LinkedList(); + list.add(0); + list.add(2); + list.add(9); + list.add(9); + list.add(9); + list.add(9); + list.add(9); + list.add(9); + list.add(9); + + + + LinkedList result = myLinkedList.intersection(list); + for(int i=0; i { + void add(E e); + void add(int index, E e); + E get(int index); + E remove(int index); + int size(); +} diff --git a/group24/798277403/src/week3/test/ConnectionTest.java b/group24/798277403/src/week3/test/ConnectionTest.java new file mode 100644 index 0000000000..918f4d0707 --- /dev/null +++ b/group24/798277403/src/week3/test/ConnectionTest.java @@ -0,0 +1,52 @@ +package week3.test; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import week3.api.Connection; +import week3.api.ConnectionManager; +import week3.impl.ConnectionManagerImpl; + + +public class ConnectionTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testContentLength() throws Exception{ + ConnectionManager connMan = new ConnectionManagerImpl(); + Connection conn = connMan.open("http://www.hinews.cn/pic/0/13/91/26/13912621_821796.jpg"); + Assert.assertEquals(35470, conn.getContentLength()); + } + + @Test + public void testRead() throws Exception{ + + ConnectionManager connMan = new ConnectionManagerImpl(); + Connection conn = connMan.open("http://www.hinews.cn/pic/0/13/91/26/13912621_821796.jpg"); + + byte[] data = conn.read(0, 35469); + + Assert.assertEquals(35470, data.length); + + data = conn.read(0, 1023); + + Assert.assertEquals(1024, data.length); + + data = conn.read(1024, 2023); + + Assert.assertEquals(1000, data.length); + + + // 测试不充分,没有断言内容是否正确 + } + + +} diff --git a/group24/798277403/src/week3/test/FileDownloaderTest.java b/group24/798277403/src/week3/test/FileDownloaderTest.java new file mode 100644 index 0000000000..959796399b --- /dev/null +++ b/group24/798277403/src/week3/test/FileDownloaderTest.java @@ -0,0 +1,62 @@ +package week3.test; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import week3.FileDownloader; +import week3.api.ConnectionManager; +import week3.api.DownloadListener; +import week3.impl.ConnectionManagerImpl; + + +public class FileDownloaderTest { + boolean downloadFinished = false; + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testDownload() { + + //String url = "http://www.hinews.cn/pic/0/13/91/26/13912621_821796.jpg"; + + String url = "http://images2015.cnblogs.com/blog/610238/201604/610238-20160421154632101-286208268.png"; + + FileDownloader downloader = new FileDownloader(url,"C:\\Users\\zhouliang\\Desktop\\mycoding\\test.jpg"); + + + ConnectionManager cm = new ConnectionManagerImpl(); + downloader.setConnectionManager(cm); + + downloader.setListener(new DownloadListener() { + @Override + public void notifyFinished() { + downloadFinished = true; + } + + }); + + + downloader.execute(); + + // 等待多线程下载程序执行完毕 + while (!downloadFinished) { + try { + System.out.println("还没有下载完成,休眠五秒"); + //休眠5秒 + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + System.out.println("下载完成!"); + + + + } + +} diff --git a/group24/798277403/src/week4/LRU/LRUPageFrame.java b/group24/798277403/src/week4/LRU/LRUPageFrame.java new file mode 100644 index 0000000000..cbbb26fc7f --- /dev/null +++ b/group24/798277403/src/week4/LRU/LRUPageFrame.java @@ -0,0 +1,130 @@ +package week4.LRU; + +/** + * Created by zhouliang on 2017-04-04. + */ +public class LRUPageFrame { + private static class Node { + Node prev; + Node next; + int pageNum; + Node() { + } + } + + private int capacity; + + private int currentSize; + private Node first;// 链表头 + private Node last;// 链表尾 + + + public LRUPageFrame(int capacity) { + this.currentSize = 0; + this.capacity = capacity; + } + + /** + * 获取缓存中对象 + * @param pageNum + * @return + */ + public void access(int pageNum) { + Node node = find(pageNum); + //在该队列中存在, 则提到队列头 + if (node != null) { + moveExistingNodeToHead(node); + } else{ + node = new Node(); + node.pageNum = pageNum; + // 缓存容器是否已经超过大小. + if (currentSize >= capacity) { + removeLast(); + } + addNewNodetoHead(node); + } + } + + private void addNewNodetoHead(Node node) { + if(isEmpty()){ + node.prev = null; + node.next = null; + first = node; + last = node; + + } else{ + node.prev = null; + node.next = first; + first.prev = node; + first = node; + } + this.currentSize ++; + } + + private Node find(int data){ + Node node = first; + while(node != null){ + if(node.pageNum == data){ + return node; + } + node = node.next; + } + return null; + + } + + /** + * 删除链表尾部节点 表示 删除最少使用的缓存对象 + */ + private void removeLast() { + Node prev = last.prev; + prev.next = null; + last.prev = null; + last = prev; + this.currentSize --; + } + + /** + * 移动到链表头,表示这个节点是最新使用过的 + * + * @param node + */ + private void moveExistingNodeToHead(Node node) { + if (node == first) { + return; + } + else if(node == last){ + //当前节点是链表尾, 需要放到链表头 + Node prevNode = node.prev; + prevNode.next = null; + last.prev = null; + last = prevNode; + } else{ + //node 在链表的中间, 把node 的前后节点连接起来 + Node prevNode = node.prev; + prevNode.next = node.next; + Node nextNode = node.next; + nextNode.prev = prevNode; + } + node.prev = null; + node.next = first; + first.prev = node; + first = node; + } + private boolean isEmpty(){ + return (first == null) && (last == null); + } + + public String toString(){ + StringBuilder buffer = new StringBuilder(); + Node node = first; + while(node != null){ + buffer.append(node.pageNum); + node = node.next; + if(node != null){ + buffer.append(","); + } + } + return buffer.toString(); + } +} diff --git a/group24/798277403/src/week4/LRU/LRUPageFrameTest.java b/group24/798277403/src/week4/LRU/LRUPageFrameTest.java new file mode 100644 index 0000000000..0b6bdf2c25 --- /dev/null +++ b/group24/798277403/src/week4/LRU/LRUPageFrameTest.java @@ -0,0 +1,33 @@ +package week4.LRU; + +import org.junit.Assert; +import org.junit.Test; + +/** + * Created by zhouliang on 2017-04-04. + */ +public class LRUPageFrameTest { + @Test + public void testAccess() { + MyLRUPageFrame frame = new MyLRUPageFrame(3); + frame.access(7); + frame.access(0); + frame.access(1); + Assert.assertEquals("1,0,7", frame.toString()); + frame.access(2); + Assert.assertEquals("2,1,0", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(3); + Assert.assertEquals("3,0,2", frame.toString()); + frame.access(0); + Assert.assertEquals("0,3,2", frame.toString()); + frame.access(4); + Assert.assertEquals("4,0,3", frame.toString()); + frame.access(5); + Assert.assertEquals("5,4,0", frame.toString()); + + } +} diff --git a/group24/798277403/src/week4/LRU/MyLRUPageFrame.java b/group24/798277403/src/week4/LRU/MyLRUPageFrame.java new file mode 100644 index 0000000000..9e720d8589 --- /dev/null +++ b/group24/798277403/src/week4/LRU/MyLRUPageFrame.java @@ -0,0 +1,133 @@ +package week4.LRU; + +/** + * Created by zhouliang on 2017-04-04. + */ +public class MyLRUPageFrame { + private static class Node { + Node prev; + Node next; + int pageNum; + + Node() { + } + } + + private int capacity; + private int currentSize; + private Node first;// 链表头 + private Node last;// 链表尾 + + public MyLRUPageFrame(int capacity) { + this.currentSize = 0; + this.capacity = capacity; + } + + /** + * 获取缓存中对象 + * + * @param pageNum + * @return + */ + public void access(int pageNum) { + //1、是否为空号 + //2、不为空,查找后面有没有出现pageNum,如果出现则把pageNum结点移动到head + //3、如果没有出现pageNum,则判断栈是否满 + //4、如果栈没有满,则添加pageNum到head + //5、否则删除最后一个再添加pageNum到head + Node temp = find(pageNum); + if (temp != null) { + moveExistingNodeToHead(temp); + } else { + temp = new Node(); + temp.pageNum = pageNum; + if (currentSize >= capacity) { + removeLast(); + } + addNewNodetoHead(temp); + } + + } + + private void addNewNodetoHead(Node node) { + if(isEmpty()){ + node.prev = null; + node.next = null; + first = node; + last = node; + }else{ + node.prev = null; + node.next = first; + first.prev = node; + first = node; + } + currentSize++; + } + + private Node find(int data) { + if (isEmpty()) { + return null; + } else { + Node temp = first; + while (temp.next != null) { + if (temp.pageNum == data) { + return temp; + } + temp = temp.next; + } + return null; + } + } + + /** + * 删除链表尾部节点 表示 删除最少使用的缓存对象 + */ + private void removeLast() { + Node temp = last.prev; + temp.next = null; + last.prev = null; + last = temp; + currentSize--; + } + + /** + * 移动到链表头,表示这个节点是最新使用过的 + */ + private void moveExistingNodeToHead(Node node) { + if(node == first){ + return; + } + if(node != last){ + Node prev = node.prev; + Node next = node.next; + prev.next = next; + next.prev = prev; + }else{ + Node prev = node.prev; + prev.next = null; + last.prev = null; + last = prev; + } + node.next = first; + node.prev = null; + first.prev = node; + first = node; + } + + private boolean isEmpty() { + return (first == null) && (last == null); + } + + public String toString() { + StringBuilder buffer = new StringBuilder(); + Node node = first; + while (node != null) { + buffer.append(node.pageNum); + node = node.next; + if (node != null) { + buffer.append(","); + } + } + return buffer.toString(); + } +} diff --git a/group24/798277403/src/week4/loader/ClassFileLoader.java b/group24/798277403/src/week4/loader/ClassFileLoader.java new file mode 100644 index 0000000000..90bce86e77 --- /dev/null +++ b/group24/798277403/src/week4/loader/ClassFileLoader.java @@ -0,0 +1,67 @@ +package week4.loader; + +import java.io.*; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by zhouliang on 2017-04-04. + */ +public class ClassFileLoader { + private List clzPaths = new ArrayList(); + + public byte[] readBinaryCode(String className) { + className = className.replace(".","\\"); + if(!className.endsWith(".class")){ + className=className+".class"; + } + File file = null; + for(String path : clzPaths){ + file = new File(path+"\\"+className); + if(file.exists()){ + break; + } + } + + if(file==null){ + try { + throw new FileNotFoundException(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + return null; + }else{ + byte[] buffer = new byte[1024]; + BufferedInputStream bufferedInputStream = null; + ByteArrayOutputStream byteArrayOutputStream = null; + try { + bufferedInputStream = new BufferedInputStream(new FileInputStream(file)); + byteArrayOutputStream = new ByteArrayOutputStream(); + int length = 0; + while((length = bufferedInputStream.read(buffer))!= -1){ + byteArrayOutputStream.write(buffer,0,length); + } + } catch (IOException e) { + e.printStackTrace(); + } + return byteArrayOutputStream.toByteArray(); + } + } + + + public void addClassPath(String path) { + clzPaths.add(path); + } + + public String getClassPath(){ + StringBuilder stringBuilder = new StringBuilder(); + for(int i=0; i Date: Tue, 4 Apr 2017 23:26:35 +0800 Subject: [PATCH 057/203] =?UTF-8?q?=E7=AC=AC=E5=9B=9B=E5=91=A8=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A-jvm=E5=8F=8ALRU?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jvm/loader/ClassFileLoader.java | 59 +++++++ .../coding/week4/linklist/LRUPageFrame.java | 157 ++++++++++++++++++ .../com/coding/week4/linklist/LinkedList.java | 126 ++++++++++++++ .../mini_jvm/test/ClassFileloaderTest.java | 92 ++++++++++ .../com/coding/mini_jvm/test/EmployeeV1.java | 28 ++++ .../com/coding/week4/LRUPageFrameTest.java | 32 ++++ 6 files changed, 494 insertions(+) create mode 100644 group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/loader/ClassFileLoader.java create mode 100644 group24/494800949/src/main/java/com/coding/week4/linklist/LRUPageFrame.java create mode 100644 group24/494800949/src/main/java/com/coding/week4/linklist/LinkedList.java create mode 100644 group24/494800949/src/test/java/com/coding/mini_jvm/test/ClassFileloaderTest.java create mode 100644 group24/494800949/src/test/java/com/coding/mini_jvm/test/EmployeeV1.java create mode 100644 group24/494800949/src/test/java/com/coding/week4/LRUPageFrameTest.java diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/loader/ClassFileLoader.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..1ca7cc8ece --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,59 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.loader; + +import java.io.*; +import java.util.ArrayList; +import java.util.List; + + + +public class ClassFileLoader { + + private static final String CLASS_FILE_SUFFIX = ".class"; + private List clzPaths = new ArrayList(); + + public byte[] readBinaryCode(String className) { + String classPath = getClassPath(); + String[] paths = classPath.split(File.pathSeparator); + className = className.replaceAll("\\.", "\\"+File.separator) ; + for (String path : paths) { + String filename = path + File.separator + className + CLASS_FILE_SUFFIX; + File file = new File(filename); + if (file.exists()) { + try { + FileInputStream fis = new FileInputStream(file); + BufferedInputStream bis = new BufferedInputStream(fis); + byte[] data = new byte[bis.available()]; + bis.read(data); + return data; + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return null; + } + + + public void addClassPath(String path) { + clzPaths.add(path); + } + + + + public String getClassPath(){ + StringBuffer sb = new StringBuffer(); + for (String path : clzPaths) { + sb.append(path); + sb.append(";"); + } + String path = sb.toString(); + return path.substring(0, path.lastIndexOf(";")); + } + + + + + +} diff --git a/group24/494800949/src/main/java/com/coding/week4/linklist/LRUPageFrame.java b/group24/494800949/src/main/java/com/coding/week4/linklist/LRUPageFrame.java new file mode 100644 index 0000000000..bd31cd26f3 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/week4/linklist/LRUPageFrame.java @@ -0,0 +1,157 @@ +package com.coding.week4.linklist; + +/** + * 用双向链表实现LRU算法 + * @author liuxin + * + */ +public class LRUPageFrame { + + private static class Node { + + Node prev; + Node next; + int pageNum; + + Node() { + } + + public Node(Node prev, int pageNum, Node next) { + this.prev = prev; + this.next = next; + this.pageNum = pageNum; + } + } + + private int capacity; + private int size; + + private Node first;// 链表头 + private Node last;// 链表尾 + + + public LRUPageFrame(int capacity) { + + this.capacity = capacity; + + } + + /** + * 获取缓存中对象 + * + * @param + * @return + */ + public void access(int pageNum) { + if (!isFull()) { + addFirst(pageNum); + } else { + if (contains(pageNum)) { + removePage(pageNum); + addFirst(pageNum); + } else { + removeLast(); + addFirst(pageNum); + } + } + } + + public boolean contains(int pageNum) { + Node node = first; + if (first == null) + return false; + do { + if (pageNum == node.pageNum) + return true; + node = node.next; + } while (node != null ); + return false; + } + + + public void addFirst(int pageNum){ + Node node = new Node(null, pageNum, null); + if (first == null) { + first = node; + last = node; + } else { + Node oldFirst = first; + first = node; + node.next = oldFirst; + oldFirst.prev = node; + } + size++; + } + + + public boolean isFull () { + return size == capacity; + } + + + public void addLast(int pageNum) { + Node oldLast = last; + Node node = new Node(oldLast, pageNum, null); + oldLast.next = node; + last = node; + size++; + } + + + public int removeLast(){ + Node oldLast = last; + last = oldLast.prev; + last.next = null; + size--; + return oldLast.pageNum; + } + + + public void removePage(int pageNum){ + Node node = first; + if (first == null) { + return; + } + do { + if (node.pageNum == pageNum) { + if (node == first) { + removeFirst(); + } else if (node == last) { + removeLast(); + } else { + Node pre = node.prev; + Node nex = node.next; + pre.next = nex; + nex.prev = pre; + size--; + } + return; + } + node = node.next; + } while (node != null); + } + + private void removeFirst() { + Node node = first; + first = node.next; + first.prev = null; + node.next = null; + size--; + } + + + public String toString(){ + StringBuilder buffer = new StringBuilder(); + Node node = first; + while(node != null){ + buffer.append(node.pageNum); + + node = node.next; + if(node != null){ + buffer.append(","); + } + } + return buffer.toString(); + } + +} diff --git a/group24/494800949/src/main/java/com/coding/week4/linklist/LinkedList.java b/group24/494800949/src/main/java/com/coding/week4/linklist/LinkedList.java new file mode 100644 index 0000000000..1285ed8fa1 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/week4/linklist/LinkedList.java @@ -0,0 +1,126 @@ +package com.coding.week4.linklist; + + +import com.coding.weak1.Iterator; +import com.coding.weak1.List; + +public class LinkedList implements List { + + private Node head; + + public void add(Object o){ + + } + public void add(int index , Object o){ + + } + public Object get(int index){ + return null; + } + public Object remove(int index){ + return null; + } + + public int size(){ + return -1; + } + + public void addFirst(Object o){ + + } + public void addLast(Object o){ + + } + public Object removeFirst(){ + return null; + } + public Object removeLast(){ + return null; + } + public Iterator iterator(){ + return null; + } + + + private static class Node{ + Object data; + Node next; + + } + + /** + * 把该链表逆置 + * 例如链表为 3->7->10 , 逆置后变为 10->7->3 + */ + public void reverse(){ + + } + + /** + * 删除一个单链表的前半部分 + * 例如:list = 2->5->7->8 , 删除以后的值为 7->8 + * 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10 + + */ + public void removeFirstHalf(){ + + } + + /** + * 从第i个元素开始, 删除length 个元素 , 注意i从0开始 + * @param i + * @param length + */ + public void remove(int i, int length){ + + } + /** + * 假定当前链表和listB均包含已升序排列的整数 + * 从当前链表中取出那些listB所指定的元素 + * 例如当前链表 = 11->101->201->301->401->501->601->701 + * listB = 1->3->4->6 + * 返回的结果应该是[101,301,401,601] + * @param list + */ + public int[] getElements(LinkedList list){ + return null; + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 从当前链表中中删除在listB中出现的元素 + + * @param list + */ + + public void subtract(LinkedList list){ + + } + + /** + * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) + */ + public void removeDuplicateValues(){ + + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 试写一高效的算法,删除表中所有值大于min且小于max的元素(若表中存在这样的元素) + * @param min + * @param max + */ + public void removeRange(int min, int max){ + + } + + /** + * 假设当前链表和参数list指定的链表均以元素依值递增有序排列(同一表中的元素值各不相同) + * 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列 + * @param list + */ + public LinkedList intersection( LinkedList list){ + return null; + } +} diff --git a/group24/494800949/src/test/java/com/coding/mini_jvm/test/ClassFileloaderTest.java b/group24/494800949/src/test/java/com/coding/mini_jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..830d0b7efe --- /dev/null +++ b/group24/494800949/src/test/java/com/coding/mini_jvm/test/ClassFileloaderTest.java @@ -0,0 +1,92 @@ +package com.coding.mini_jvm.test; + +import com.coding.mini_jvm.src.com.coderising.jvm.loader.ClassFileLoader; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + + + + + +public class ClassFileloaderTest { + + + static String path1 = "H:\\sourceCode\\coding2017\\group24\\494800949\\build\\classes\\test"; + static String path2 = "C:\temp"; + + + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testClassPath(){ + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + loader.addClassPath(path2); + + String clzPath = loader.getClassPath(); + + Assert.assertEquals(path1+";"+path2,clzPath); + + } + + @Test + public void testClassFileLength() { + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + + String className = "com.coding.mini_jvm.test.EmployeeV1"; + + byte[] byteCodes = loader.readBinaryCode(className); + + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + Assert.assertEquals(1058, byteCodes.length); + + } + + + @Test + public void testMagicNumber(){ + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "com.coding.mini_jvm.test.EmployeeV1"; + byte[] byteCodes = loader.readBinaryCode(className); + byte[] codes = new byte[]{byteCodes[0],byteCodes[1],byteCodes[2],byteCodes[3]}; + + + String acctualValue = this.byteToHexString(codes); + + Assert.assertEquals("cafebabe", acctualValue); + } + + + + + + + private String byteToHexString(byte[] codes ){ + StringBuffer buffer = new StringBuffer(); + for(int i=0;i Date: Tue, 4 Apr 2017 23:39:23 +0800 Subject: [PATCH 058/203] 4.4 --- .../main/week03/download/DownloadThread.java | 47 +++++- .../main/week03/download/FileDownloader.java | 136 +++++++++++++----- .../week03/download/FileDownloaderTest.java | 32 +++-- .../main/week03/download/api/Connection.java | 3 +- .../download/api/ConnectionException.java | 14 ++ .../week03/download/impl/ConnectionImpl.java | 68 ++++++++- .../download/impl/ConnectionManagerImpl.java | 5 +- .../src/main/week03/download/test.jpg | Bin 0 -> 234626 bytes 8 files changed, 241 insertions(+), 64 deletions(-) create mode 100644 group24/330657387/src/main/week03/download/test.jpg diff --git a/group24/330657387/src/main/week03/download/DownloadThread.java b/group24/330657387/src/main/week03/download/DownloadThread.java index a88c38eeb4..f18bbf234c 100644 --- a/group24/330657387/src/main/week03/download/DownloadThread.java +++ b/group24/330657387/src/main/week03/download/DownloadThread.java @@ -1,20 +1,55 @@ package main.week03.download; +import java.io.RandomAccessFile; +import java.util.concurrent.CyclicBarrier; + import main.week03.download.api.Connection; -public class DownloadThread extends Thread{ +public class DownloadThread extends Thread { Connection conn; + int startPos; int endPos; + + CyclicBarrier barrier; + + String localFile; + + public DownloadThread(Connection conn, int startPos, int endPos, + String localFile, CyclicBarrier barrier) { - public DownloadThread( Connection conn, int startPos, int endPos){ - - this.conn = conn; + this.conn = conn; this.startPos = startPos; this.endPos = endPos; + this.localFile = localFile; + this.barrier = barrier; } - public void run(){ - + + public void run() { + + try { + System.out.println("Begin to read [" + startPos + "-" + endPos + + "]"); + + byte[] data = conn.read(startPos, endPos); + //设置文件的读取权限 + RandomAccessFile file = new RandomAccessFile(localFile, "rw"); + + file.seek(startPos); + + file.write(data); + + file.close(); + + conn.close(); + + barrier.await(); // 等待别的线程完成 + + } catch (Exception e) { + e.printStackTrace(); + + } + } } diff --git a/group24/330657387/src/main/week03/download/FileDownloader.java b/group24/330657387/src/main/week03/download/FileDownloader.java index a213105b50..54d6c260ad 100644 --- a/group24/330657387/src/main/week03/download/FileDownloader.java +++ b/group24/330657387/src/main/week03/download/FileDownloader.java @@ -1,73 +1,131 @@ package main.week03.download; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.concurrent.CyclicBarrier; + import main.week03.download.api.Connection; import main.week03.download.api.ConnectionException; import main.week03.download.api.ConnectionManager; import main.week03.download.api.DownloadListener; - public class FileDownloader { - - String url; - - DownloadListener listener; - - ConnectionManager cm; - - - public FileDownloader(String _url) { + + private String url; + private String filePath = "/"; + + public DownloadListener listener; + + public ConnectionManager cm; + + private int DOWNLOAD_TRHEAD_NUM = 3; + + public FileDownloader(String _url, String filePath) { this.url = _url; - + this.filePath = filePath; } - - public void execute(){ + + public void execute() throws IOException { // 在这里实现你的代码, 注意: 需要用多线程实现下载 // 这个类依赖于其他几个接口, 你需要写这几个接口的实现代码 - // (1) ConnectionManager , 可以打开一个连接,通过Connection可以读取其中的一段(用startPos, endPos来指定) + // (1) ConnectionManager , 可以打开一个连接,通过Connection可以读取其中的一段(用startPos, + // endPos来指定) // (2) DownloadListener, 由于是多线程下载, 调用这个类的客户端不知道什么时候结束,所以你需要实现当所有 - // 线程都执行完以后, 调用listener的notifiedFinished方法, 这样客户端就能收到通知。 + // 线程都执行完以后, 调用listener的notifiedFinished方法, 这样客户端就能收到通知。 // 具体的实现思路: - // 1. 需要调用ConnectionManager的open方法打开连接, 然后通过Connection.getContentLength方法获得文件的长度 - // 2. 至少启动3个线程下载, 注意每个线程需要先调用ConnectionManager的open方法 + // 1. 需要调用ConnectionManager的open方法打开连接, + // 然后通过Connection.getContentLength方法获得文件的长度 + // 2. 至少启动3个线程下载, 注意每个线程需要先调用ConnectionManager的open方法 // 然后调用read方法, read方法中有读取文件的开始位置和结束位置的参数, 返回值是byte[]数组 // 3. 把byte数组写入到文件中 // 4. 所有的线程都下载完成以后, 需要调用listener的notifiedFinished方法 - + // 下面的代码是示例代码, 也就是说只有一个线程, 你需要改造成多线程的。 + + //当支线线程全部结束,即每个线程都调用了await方法,就会触发主线程,即listener的notify + CyclicBarrier barrier = new CyclicBarrier(DOWNLOAD_TRHEAD_NUM, + new Runnable() { + public void run() { + listener.notifyFinished(); + } + }); + Connection conn = null; try { - + conn = cm.open(this.url); - - int length = conn.getContentLength(); - - new DownloadThread(conn,0,length-1).start(); - - } catch (ConnectionException e) { + + int length = conn.getContentLength(); + + //确保文件里有足够的空间? + createPlaceHolderFile(this.filePath, length); + + //每个线程的读取区间 + int[][] ranges = allocateDownloadRange(DOWNLOAD_TRHEAD_NUM, length); + + for (int i = 0; i < DOWNLOAD_TRHEAD_NUM; i++) { + + DownloadThread thread = new DownloadThread(cm.open(url), + ranges[i][0], ranges[i][1], filePath, barrier); + + thread.start(); + } + + } catch (ConnectionException e) { e.printStackTrace(); - }finally{ - if(conn != null){ + } finally { + if (conn != null) { conn.close(); } } - - - - + + } + + private int[][] allocateDownloadRange(int threadNum, int contentLen) { + int[][] ranges = new int[threadNum][2]; + + int eachThreadSize = contentLen / threadNum;// 每个线程需要下载的文件大小 + int left = contentLen % threadNum;// 剩下的归最后一个线程来处理 + + for (int i = 0; i < threadNum; i++) { + + int startPos = i * eachThreadSize; + + int endPos = (i + 1) * eachThreadSize - 1; + + if ((i == (threadNum - 1))) { + endPos += left; + } + ranges[i][0] = startPos; + ranges[i][1] = endPos; + + } + + return ranges; + } + + private void createPlaceHolderFile(String filePath, int contentLen) + throws IOException { + RandomAccessFile file = new RandomAccessFile(filePath, "rw"); + + for (int i = 0; i < contentLen; i++) { + file.write(1); + } + + file.close(); } - + public void setListener(DownloadListener listener) { this.listener = listener; } - - - public void setConnectionManager(ConnectionManager ucm){ - this.cm = ucm; + public void setConnectionManager(ConnectionManager cm) { + this.cm = cm; } - - public DownloadListener getListener(){ + + public DownloadListener getListener() { return this.listener; } - + } diff --git a/group24/330657387/src/main/week03/download/FileDownloaderTest.java b/group24/330657387/src/main/week03/download/FileDownloaderTest.java index b308c26527..cee0ae1f61 100644 --- a/group24/330657387/src/main/week03/download/FileDownloaderTest.java +++ b/group24/330657387/src/main/week03/download/FileDownloaderTest.java @@ -1,5 +1,9 @@ package main.week03.download; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + import main.week03.download.api.ConnectionManager; import main.week03.download.api.DownloadListener; import main.week03.download.impl.ConnectionManagerImpl; @@ -8,12 +12,25 @@ import org.junit.Before; import org.junit.Test; - - public class FileDownloaderTest { boolean downloadFinished = false; + String _url = "http://images2015.cnblogs.com/blog/610238/201604/610238-20160421154632101-286208268.png"; + String _filePath = "/"; @Before public void setUp() throws Exception { + File file = new File("."); + + String packageName = this.getClass().getPackage().getName(); + // 把包名转化成路径的一部分 + packageName = packageName.replace('.', '/'); + + _filePath = file.getCanonicalPath() + "/src/" + packageName + "/" + "test.jpg"; + try{ + System.out.println(file.getCanonicalPath());//获取标准的路径 + System.out.println(file.getAbsolutePath());//获取绝对路径 + System.out.println(file.getPath()); + System.out.println(packageName); + }catch(Exception e){} } @After @@ -21,13 +38,13 @@ public void tearDown() throws Exception { } @Test - public void testDownload() { - - String url = "http://localhost:8080/test.jpg"; + public void testPath(){} + + @Test + public void testDownload() throws IOException { - FileDownloader downloader = new FileDownloader(url); + FileDownloader downloader = new FileDownloader(_url, _filePath); - ConnectionManager cm = new ConnectionManagerImpl(); downloader.setConnectionManager(cm); @@ -39,7 +56,6 @@ public void notifyFinished() { }); - downloader.execute(); // 等待多线程下载程序执行完毕 diff --git a/group24/330657387/src/main/week03/download/api/Connection.java b/group24/330657387/src/main/week03/download/api/Connection.java index da0bece84f..b75b565af5 100644 --- a/group24/330657387/src/main/week03/download/api/Connection.java +++ b/group24/330657387/src/main/week03/download/api/Connection.java @@ -13,8 +13,9 @@ public interface Connection { /** * 得到数据内容的长度 * @return + * @throws ConnectionException */ - public int getContentLength(); + public int getContentLength() throws ConnectionException; /** * 关闭连接 diff --git a/group24/330657387/src/main/week03/download/api/ConnectionException.java b/group24/330657387/src/main/week03/download/api/ConnectionException.java index 30d6093a17..e929fd388a 100644 --- a/group24/330657387/src/main/week03/download/api/ConnectionException.java +++ b/group24/330657387/src/main/week03/download/api/ConnectionException.java @@ -1,5 +1,19 @@ package main.week03.download.api; +import java.io.IOException; +import java.net.MalformedURLException; + public class ConnectionException extends Exception { + + public ConnectionException(String errmsg){ + super(errmsg); + } + + public ConnectionException(MalformedURLException e) { + super(e); + } + public ConnectionException(IOException e) { + super(e); + } } diff --git a/group24/330657387/src/main/week03/download/impl/ConnectionImpl.java b/group24/330657387/src/main/week03/download/impl/ConnectionImpl.java index 9ffa4f16df..e725ff15a1 100644 --- a/group24/330657387/src/main/week03/download/impl/ConnectionImpl.java +++ b/group24/330657387/src/main/week03/download/impl/ConnectionImpl.java @@ -1,27 +1,81 @@ package main.week03.download.impl; +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Arrays; +import main.week03.download.FileDownloader; import main.week03.download.api.Connection; +import main.week03.download.api.ConnectionException; -public class ConnectionImpl implements Connection{ +public class ConnectionImpl implements Connection { + + URL url; + static final int BUFFER_SIZE = 1024; + + public ConnectionImpl(String _url) throws ConnectionException { + try { + //传入的字符串必须是url格式 + url = new URL(_url); + } catch (MalformedURLException e) { + throw new ConnectionException(e); + } + } @Override public byte[] read(int startPos, int endPos) throws IOException { - - return null; + int totalLen = endPos - startPos + 1; + + //是URLConnection的子类,负责http协议的链接 + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos); + + InputStream inputStream = conn.getInputStream(); + + byte[] buffer = new byte[BUFFER_SIZE]; + + //输出流 + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + while (baos.size() < totalLen) { + + //一次读取1024字节 + int len = inputStream.read(buffer); + if (len < 0) { + break; + } + baos.write(buffer, 0, len); + } + + //防止这个线程过度读取 + if (baos.size() > totalLen) { + byte[] data = baos.toByteArray(); + return Arrays.copyOf(data, totalLen); + } + + return baos.toByteArray(); } @Override - public int getContentLength() { - - return 0; + public int getContentLength() throws ConnectionException { + int res = -1; + try { + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + res = conn.getContentLength(); + conn.disconnect(); + return res; + } catch (IOException e) { + throw new ConnectionException(e); + } } @Override public void close() { - } } diff --git a/group24/330657387/src/main/week03/download/impl/ConnectionManagerImpl.java b/group24/330657387/src/main/week03/download/impl/ConnectionManagerImpl.java index 240371883b..2253f4fa06 100644 --- a/group24/330657387/src/main/week03/download/impl/ConnectionManagerImpl.java +++ b/group24/330657387/src/main/week03/download/impl/ConnectionManagerImpl.java @@ -4,14 +4,13 @@ import main.week03.download.api.ConnectionException; import main.week03.download.api.ConnectionManager; - - public class ConnectionManagerImpl implements ConnectionManager { @Override public Connection open(String url) throws ConnectionException { + Connection res = new ConnectionImpl(url); - return null; + return res; } } diff --git a/group24/330657387/src/main/week03/download/test.jpg b/group24/330657387/src/main/week03/download/test.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3a052212e5720984b62178e147bd71511578a149 GIT binary patch literal 234626 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
TJa?v0Cca|<=co)wV)cqqh& zX?!Sqs*kGG)y)NVYC~@U7~F5xrj$Vw4t?%EPH8?a!@@GokPWCDLSq1mDTpOAbl34* z%wvfCV9GFnb#*JWd8H|y*=Or&^vxSu-p zzv}J1#%)vIK${PRoFR@Zp0}@kxgh+P`%W63YNgG}&qGGO%7^)c#aYjP5&@Ie=a!F6^ zL!)Sab&u497%4Z$^Qwo->p`zvMVp^H#XE&_%db1FFfDX7U{+26mQCnMDbzhF)ni0> z#^pQ4>;fFBldEF=egpFBc{(Eqo`+cz4O&rNVT(ZgB|=5g^5lN%FBSBHEMLL*i?C2- zAhzHv+9a41oC9gefpBwwOrT|xWKxH00b4&~%3*XtU?@T9Z|gU2-nhB(|L0uab2_+# zybLf{;%-Ojz~o4uW9dN5a#M%qo)Dm9-tdJ8(!`7m$|IdEt5reTbnEKWRRN9hS8|HqjxG z=Y3hjZ^vvL9gS+%y16}%eBq6=(wWuTy+8>E1cOvDflZeg&FhQr)!YYXE6f;+H31)z zU2NCXgXMr9&e1@mF6V|FojgL}m1l;*5I}syzPlS~c5AGy7Y06SoYMv0vIObgP7dT7 zj2AAdXX<`QpB+0P{=7BAwwkw8=p>N?@-hO`kXmH#iqA+YhTta##<)slFc&Q^#)yi4 zzxxjY>=yCgiVQXU2NP`<>mW=sgDmrqu7i(6(dmY)fq+XQa{{Z)ynoHc~_t85bhldPzDqB_ez6zHt2 zt)=J!^IcJZ-On^+0n=A=D5Na&=`%2bkS^TUxY4zss0bD7U=Wz@6CRX-kL9dH8p#VJ z6%pO_%51YZ%(};K*%@tSCy35d3Dn~k7yeFYa&p8_lzmW%7ZltLft5D0sySsa`l>E4 zpGQxRm9-kUJ#|&<0!Ttd5peIoJ@8jruojtvjw~#u$%1nmi;LO_UpgHF+|nZl5c7X2 zY+;fm(f<3arF*?%@tEIg_^z||={n-YllN)X(_=@#=K6KG$#R{;zH8wWj{WV4Qov8<`zUf8k|WTJ%dY?4%dIEV=0>5!|fCd&p=p%Bh+*nex|| ziFGEA*6Ja~c!NV3&`6Jvttj|kfxf8&{DL)f{u&j7rVJLaynrOBi=o)5}es;`Boov23ub7xiV2JQ<3FMG3su*>bA&Z~J~t-k{?$K}vKucr^a zKoLY>dBZQXU?S;8kC`!Y>F*!?B^D|?Pu)jMW_MhMQZy}Pq(UEH+OJ5!p~tL57A)!? zD&`L@z8Lr+W~>varDo>}ILCEqY#ZW!B%gl@2#`dsv?nBNSv=>p`2?PrMU6hg zRg1oQwV7()cAG3t_qg~#^5pr{fOSguw1!SX>u)+4-G2YdFxjSdAxJfFJvxZX^*uTd z^J3j&$^_)+gMxGM{%0A{3_1 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 kWCD#p(tCGfWS>lS9d$v-?VBy+C Date: Tue, 4 Apr 2017 23:45:03 +0800 Subject: [PATCH 059/203] 4.4 --- .../\345\215\232\345\256\242\345\234\260\345\235\200.txt" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/group24/330657387/\345\215\232\345\256\242\345\234\260\345\235\200.txt" "b/group24/330657387/\345\215\232\345\256\242\345\234\260\345\235\200.txt" index 76ae770288..79237635d2 100644 --- "a/group24/330657387/\345\215\232\345\256\242\345\234\260\345\235\200.txt" +++ "b/group24/330657387/\345\215\232\345\256\242\345\234\260\345\235\200.txt" @@ -1,6 +1,6 @@ ��һ�ܲ���http://www.cnblogs.com/sargeles/p/6605493.html �ڶ��ܲ���http://www.cnblogs.com/sargeles/p/6605945.html -�����ܲ��� +�����ܲ���http://www.cnblogs.com/sargeles/p/6667002.html �����ܲ��� �����ܲ��� �����ܲ��� From a4afcfe0fcaf7bd3bdfaa855ae465d33bd55c88c Mon Sep 17 00:00:00 2001 From: HaoSong Date: Wed, 5 Apr 2017 11:44:26 +0800 Subject: [PATCH 060/203] 4.5 --- .../week01/data_structure/LinkedList.java | 54 +++++++----------- .../week01/data_structure/LinkedListTest.java | 29 ++++------ .../main/week03/download/DownloadThread.java | 7 ++- .../main/week03/download/FileDownloader.java | 2 +- .../week03/download/impl/ConnectionImpl.java | 11 ++-- .../download/impl/ConnectionManagerImpl.java | 1 + .../src/main/week03/download/test.jpg | Bin 234626 -> 234626 bytes 7 files changed, 47 insertions(+), 57 deletions(-) diff --git a/group24/330657387/src/main/week01/data_structure/LinkedList.java b/group24/330657387/src/main/week01/data_structure/LinkedList.java index aafe3654ca..3e4053e1da 100644 --- a/group24/330657387/src/main/week01/data_structure/LinkedList.java +++ b/group24/330657387/src/main/week01/data_structure/LinkedList.java @@ -194,7 +194,7 @@ public void removeFirstHalf() { */ public void remove(int i, int length) { rangeCheck(i); - rangeCheck(i + length - 1); + rangeCheck(i + length - 1);//或者当length超出长度,直接认为删除i后面的所有部分。 if (i == 0) { head = getNode(length); size -= length; @@ -216,8 +216,13 @@ public int[] getElements(LinkedList list) throws Exception { if (list == null) { throw new Exception("传入链表为空?"); } + int[] res = new int[list.size]; for (int i = 0; i < list.size; i++) { + //这个list里的值不一定合法的。可以跳过那些不合法的值。 + if(i > size - 1){ + continue; + } res[i] = Integer.parseInt(get( Integer.parseInt(list.get(i).toString()) - 1).toString()); } @@ -298,6 +303,7 @@ public void removeRange(int min, int max) throws Exception { lastRemove = iter.position - 1; } } + //移动指针的时候,注意不要留下指空的指针。不然相关node会无法被gc if(hasmin && firstRemove == 0){ head = getNode(lastRemove); size -= lastRemove-firstRemove+1; @@ -318,44 +324,28 @@ public void removeRange(int min, int max) throws Exception { * @param list */ public LinkedList intersection(LinkedList list) { - if(0 == list.size){ - return this; - } - if(0 == size){ - return list; + if(0 == list.size || 0 == size){ + return new LinkedList(); } + LinkedList res = new LinkedList(); - Node a = head, b = list.head; - while(null != a && null != b){ - if(a.equals(b)){ - res.add(a.data); - a = a.next; - b = b.next; - continue; + Node node1 = this.head; + Node node2 = list.head; + while(node1 != null && node2 != null){ + if((int)node1.data<(int)node2.data){ + node1 = node1.next; + }else if((int)node1.data>(int)node2.data){ + node2 = node2.next; + }else{ + res.add(node1.data); + node1 = node1.next; + node2 = node2.next; } - if(Integer.parseInt(a.data.toString()) > Integer.parseInt(b.data.toString())){ - res.add(b.data); - b = b.next; - continue; - } - if(Integer.parseInt(a.data.toString()) < Integer.parseInt(b.data.toString())){ - res.add(a.data); - a = a.next; - continue; - } - } - while(null != a){ - res.add(a.data); - a = a.next; - } - while(null != b){ - res.add(b.data); - b = b.next; } return res; } - public String ToString() { + public String toString() { LinkedListIterator iter = this.iterator(); StringBuilder sb = new StringBuilder(); while (iter.hasNext()) { diff --git a/group24/330657387/src/main/week01/data_structure/LinkedListTest.java b/group24/330657387/src/main/week01/data_structure/LinkedListTest.java index 671cc20cd2..c0aa471f79 100644 --- a/group24/330657387/src/main/week01/data_structure/LinkedListTest.java +++ b/group24/330657387/src/main/week01/data_structure/LinkedListTest.java @@ -71,14 +71,9 @@ public void testIterator() { public void testReverse() { LinkedList l = lists[2]; l.reverse(); - LinkedListIterator iter = l.iterator(); - StringBuilder sb = new StringBuilder(); - while (iter.hasNext()) { - sb.append(iter.next()); - } // assertEquals("", sb.toString()); - // assertEquals("A", sb.toString()); - assertEquals("EDCBA", sb.toString()); + // assertEquals("A", l.toString()); + assertEquals("E->D->C->B->A->null", l.toString()); } @@ -105,7 +100,7 @@ public void testRemoveByIndex() { try{ LinkedList l = lists[2]; l.remove(0, 1); - System.out.println(l.ToString()); + System.out.println(l.toString()); }catch(Exception e){ assertEquals(IndexOutOfBoundsException.class, e.getClass()); } @@ -155,7 +150,7 @@ public void testSubtract() { l.add(66); try{ list.subtract(l); - System.out.println(list.ToString()); + System.out.println(list.toString()); }catch(Exception e){ assertEquals(e.getMessage(), "传入链表为空?"); } @@ -171,7 +166,7 @@ public void testRemoveDuplicateValues() { list.removeDuplicateValues(); - System.out.println(list.ToString()); + System.out.println(list.toString()); } @Test @@ -185,11 +180,11 @@ public void testRemoveRange() throws Exception { list.add(77); list.add(88); list.add(99); - System.out.println(list.ToString()); + System.out.println(list.toString()); try{ list.removeRange(50, 80); - System.out.println(list.ToString()); + System.out.println(list.toString()); }catch(Exception e){ assertEquals(e.getMessage(), "输入有问题!"); } @@ -208,11 +203,11 @@ public void testIntersection() { // list.add(99); LinkedList l = new LinkedList(); - l.add(10); -// l.add(30); -// l.add(40); -// l.add(60); + l.add(11); + l.add(33); +// l.add(44); +// l.add(66); - System.out.println(list.intersection(l).ToString()); + System.out.println(list.intersection(l).toString()); } } diff --git a/group24/330657387/src/main/week03/download/DownloadThread.java b/group24/330657387/src/main/week03/download/DownloadThread.java index f18bbf234c..37602d1c25 100644 --- a/group24/330657387/src/main/week03/download/DownloadThread.java +++ b/group24/330657387/src/main/week03/download/DownloadThread.java @@ -1,5 +1,6 @@ package main.week03.download; +import java.io.File; import java.io.RandomAccessFile; import java.util.concurrent.CyclicBarrier; @@ -33,7 +34,7 @@ public void run() { + "]"); byte[] data = conn.read(startPos, endPos); - //设置文件的读取权限 + //设置文件的读取权限,每个线程都独立有这个实例,这样,多线程读写同一文件就没问题。 RandomAccessFile file = new RandomAccessFile(localFile, "rw"); file.seek(startPos); @@ -47,9 +48,9 @@ public void run() { barrier.await(); // 等待别的线程完成 } catch (Exception e) { + //如果线程出错了,无法await,怎么处理? e.printStackTrace(); - - } + } finally{}//这块里应该写close的 } } diff --git a/group24/330657387/src/main/week03/download/FileDownloader.java b/group24/330657387/src/main/week03/download/FileDownloader.java index 54d6c260ad..165dc4dfb2 100644 --- a/group24/330657387/src/main/week03/download/FileDownloader.java +++ b/group24/330657387/src/main/week03/download/FileDownloader.java @@ -58,7 +58,7 @@ public void run() { int length = conn.getContentLength(); - //确保文件里有足够的空间? + //确保文件里有足够的空间,就先创建空文件。 createPlaceHolderFile(this.filePath, length); //每个线程的读取区间 diff --git a/group24/330657387/src/main/week03/download/impl/ConnectionImpl.java b/group24/330657387/src/main/week03/download/impl/ConnectionImpl.java index e725ff15a1..e42087d663 100644 --- a/group24/330657387/src/main/week03/download/impl/ConnectionImpl.java +++ b/group24/330657387/src/main/week03/download/impl/ConnectionImpl.java @@ -12,7 +12,8 @@ import main.week03.download.api.Connection; import main.week03.download.api.ConnectionException; -public class ConnectionImpl implements Connection { +//包级可见,是保护措施 +class ConnectionImpl implements Connection { URL url; static final int BUFFER_SIZE = 1024; @@ -29,13 +30,15 @@ public ConnectionImpl(String _url) throws ConnectionException { @Override public byte[] read(int startPos, int endPos) throws IOException { int totalLen = endPos - startPos + 1; - + //是URLConnection的子类,负责http协议的链接 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos); - InputStream inputStream = conn.getInputStream(); + //客户端可以在请求里放置参数,设置接收数据区间 + //代替了is.skip(),但是is.skip里有read,所以是边读边移动下标的,和本程序意图相违背。 + conn.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos); + byte[] buffer = new byte[BUFFER_SIZE]; //输出流 diff --git a/group24/330657387/src/main/week03/download/impl/ConnectionManagerImpl.java b/group24/330657387/src/main/week03/download/impl/ConnectionManagerImpl.java index 2253f4fa06..47d5dd22e1 100644 --- a/group24/330657387/src/main/week03/download/impl/ConnectionManagerImpl.java +++ b/group24/330657387/src/main/week03/download/impl/ConnectionManagerImpl.java @@ -4,6 +4,7 @@ import main.week03.download.api.ConnectionException; import main.week03.download.api.ConnectionManager; +//返回接口,是对实现的一种隐蔽 public class ConnectionManagerImpl implements ConnectionManager { @Override diff --git a/group24/330657387/src/main/week03/download/test.jpg b/group24/330657387/src/main/week03/download/test.jpg index 3a052212e5720984b62178e147bd71511578a149..a959a6ad2004f1c27cd2971968ec5abfca97133b 100644 GIT binary patch literal 234626 zcmeIuF%19!0K=fvzv;Qy1rjI>7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA G;4?7Jrx9Z09cJZ|Qayx!ykM{abb|Ow5ns*#`XfTB{efSRmL3*dq7g$nIt9 zt4||7e}~jBBhL`$cB@Qt4GKK}u67$Vb1eL1%ZzeYSO=ZPLDA!S|U* zES*(ik773^hJuBU;ff7|1C!%O+e(A*Xsqkqxq&{5iQUdKh8)IhS}Q+a&n=LBq(y6j zUWvKwiCl)Jue3F)06%3G3tYV**$gYn$9vpq>lbAE+RByGnu*rS%+^)|9S2g=ciGt) zXu6ovG`Dt}uSCj1b!U6uhvvX>P}q5#?OOMCj>i zBE>~ie;DUAzPbZ5>@}}JaNRC*20kd-qb}TJO0Tc85aaEItR`53tQH1pyIKZU=;2BqG38{ zGE$#DF-jW0CK9gut=tQjTNm67Sj+++vI7?jCGaN5#E7~Xno($*3feSr*P~5!L0mKO zrUGDnjATa80EGgnguFuP54v(kB3o<(=^1!nY9XaH7zo*)-OIvtLNiL>wITHz&~AXH zIg`CXMrUwAg}}jVtwosn%nY*PE(Q(gf#j$=J_t9f-5hJt!?+3}d2lzQ^hR)4_-+<* zsN@U90b~W(JWfD9`6^i(?^Kc4IW&gB&;}V$Jl^3d=r13zu1F#@8WTu|>s2xne>)1Q z!L!H)heMax)Eh$x81R;3O5#pN#E4>q0|7S6kYFmkkG zM&~M6W!~0C?BTaE;77y>u0mH~1=`y{)P>-j?&qj58w9U8DZUDd9gz5`w2e1{ahR-3 zDr2(*<*f!_3KJ18wn*PFOm!QXSh3J<&4bp*qMZ*#+@7hL+r&f^;g= zQpkIXVS;2ZqS13e(GwhF08}iNg)8sV=?{zuaiZ-}P5@A;Rjy!4#d2wRs0n3+*T+CuRsd1v=cG3r1A;whF8Aapqd_cfWKD(cM_Xevf^1@Zj%2m?RRqUF-K#6W)wQg#K?y~|q3e8Sll~&c# z^?V415+S-0sYr%7g_y~+7**fml`0hK8%}IcRB0a#rz6FxFZ-%5gBMNLM#mrTlbe~j z^|0TKM5QS7^a2pSjpS|EMWiXVP}T5Nn&-%Iu$xVrQR^e`7F+ zZ}0|hQ2^&4b0+Hi!Ij_2r{YhsY{km4DETE!!oq}$QMo}z5uj?a#n>Vs39uD{jRPc> zdC^TRlF*SnPJ$_UDr~Y(U5iQ<1UU-^g9C9PY1EmC3&Gfk4VJjuv3psduQ<^*QWzv4 zSK;VN$s{qB=yLHSZiWtc+Qs#dl(U4eR4ZQH>9XVaQDDIB`?|kVy;Dd?$Uk`ngJ<2` z+>pae7mv;e-v7=tXifk4*zq>mmy@Qiyr7nc#JaRwTFV@vsG zC#QtORLOx*0-@nppDE0x#-!L2iOG_bqh_Ea{LIRi!@Xs}(+sDdhAqOnMa_Hiw@++Y zE(%^Jx1V#vahfu(hU6dyvwzWiOTbMU35oa^3*xsUk zZj=jgAdG_a8A;m?#N3@FccoFjQZmB9rd7}xgDv!r^3~`p=5iajd24(V2{f5t=tUB~ zn@?x_L3S0a#n&rj+`8)3GK)a<5~;M1a#N_Zr=nYEb&g0oNRLd&sc!PtW41>(4hrmP zV5qa9bC5lOw$9Yi07V_@sHxc>g`j(eLj^2K4O5n)FI2OnOw8K5dSDT11wQAQrRCsU`N80cqRBc@zwF>9Ea6;E%alB)2s|kvDjcOF&q2l3)$jOjlH=VHY-EfO}|8idFyjMs=B9RQkv%oh& z3#g1OSBi*Uc)riA=sVgNLdV^X-&+HtmcS0X7d(GTotXykkJHo?wQh2GItKIX*t<8! zBQD`^HMng|%*%a+N{EzH2#fUBj|xJ}kxQFDyY7Xi- zPEeGh$S%)FQjsqsIYuLPFhn5(lkin2G2^7=ap79Cb?*OW%M_dG^F=twUxYe6;l{hv zbHQP(TKe{;)eMKwp<#F9>f2KEq!*iw9ek-!lUJiK7?oWh{_LjGLII??14b(M0fK_@ z;Yt01kol?pxtB05IULEb);lygw5I7+rwX(mVeu&u@Xo>YLsNrMG*c+$UU*WDnlq79 zj`S~Kof;{UVZI`Tthhhr$Bqu!>I8{FC8R*YS!!W&m3c-oSE=V5qy=;)P@N}n1O`gW z&X1j@m?~s-6l#2^CaBsz-ALak9F1s5Fdz4RahRED1nDgbot%eSkSJ=HL2??YI$&mY z5ji28|8r<@AOt3Vjp2Y%j1_o&gP|e5r|2EQHtPc8Mnfrq|JDKtTS0zKp_gX)6@n^A z6Hx?3{xHJwV^VO#K&Xomd*;w~?T zCOB0>D)ko?C%};GP@_(M|*>{TYfa%D&fvJxZ_B3`N~HzZdw+Z0;8T}V#P!g_1U7vrpL9LYa2+q z1PF<1G`ksUNVe(wH26ATVF7JB18zi@q&viMwMO@2c(nH? z!@_y`t2jdX6m2gAB`-rpqI@7z^AHC3!lzHTOHr52g?ebm3TVhcS*vJyLkMOrLtnm? z;_QopYdgL{t!!)7>?Y5>SUl|C>rc3|F(DreSV`RsFaqZ?1-Zxmf*qT&PaXOpQ)xx} zfMXEPT6VZQU93YK*(RoqA&ITFpHc5=jr}m$#XlXiXmw-_Y}kvpJS4j~?Ofx2YBCa; zsliyZN1V4uUj7<2wuw$p=BKvh znWy`kry)J?TxJ+qohK5wdub5i;JPc);)S~%;XyGTXQyql8~ALQ2G!bDz5g8FIv#y0 z3(7@WL@lx%Bodgq0jBQ1YpbV3=v<2(!VEHTQ@#0FZ|B!T}@5*&7zZf&E`cP z=|~Pv*msoM>v0iL7}bl!cNRSQc=a=nLFm|BXd@(-Ku^T~?RbQA;jK#mRfG^hqgAREDMU&~u=C-QB}x_4Q8UCO z$Z%>#z^8B}r{3KPQWhh13<+R!uSdn_*ajPR$*9Ln9((z_B!3PKG?I#op;Grx#3^PW z9~#&XX-_Bvo=gv=1fO2p0Cd%;k;R*RVzo2ii52y(kpL=^EIbI+_LNBItfS)Cq^4Ki zO37HB{OT;`Su~c|Hei)$(4P&RiqvA8iHJz)1${$^J0Wbe5Kp3NLv(d5!8a;fHLd>B z*y~emewH@U2m{jz^JH9167?K(2odJ>^b*I0{5*qgU7-L@2Gc0TrF8TSoQr;Oei#31J5Pf~Dj z(ab2 zwo7*wWZ1T7qY`TP;iSVo@xndH0C?8VG%^vrKrbnWG}Ht9jaUbWi;cDLM3Q1Km(_E% zmu8n@3sS%z7!QLJb`k~b;738%^atk&x+uCOj-Y{aMzY&Zt$ulwTxxVD&7cVfoC*qK zH*17`JrOW;)p;?XTcz|x}@++?+WuAfKsdVy(sv0h8B{+Pln)2~6=Cl1&*1KCto-ATe8S<5YNVwp` zl#1_dIJM|ji2e9OnEZ4?7&CZF12(1z(uM`eWBIIYDae8ak^ln9V!Mr>SD^l}DvD(C zDzULNZ`=p28t5yPIyTo}zbHEHRPE#;=&6`;Y9!hE!S3NQ+{$Le8=~I9r~^?obBR=X_(n2>gKqMGZ%5akB9VGOVfS zSOu;L`g-19Hzrn%m@J`P;cHIGPTKw4%5=hug6bgW+s@w$IZ8Wn>_jgq*a2#IG^vEa zeHH9<8bQ3FL+Rmd#|!fQCJOV?y2T0_nDk>gbG9|Qk<}DATEhIvJ1X(;@4HYnh<|oS z$ph313)~8!+~~`y(x!9(z%FVX#?KLNb~%WAndXS)v($Lr#ZopQ3;< zP)kt;4=V0;t|Wc3TS4eQmlJVCj{RaM9_;8>md+1I=iaH&A3%+{L?i9t9V^QKJTC-( z#T*7+!=hm29*dJ8+eqP#qjpL1%fQc z_Dmhi;nV^2kXw6{j`>)7@rZ=kLtED#(p**+G<~Jq5aj2%`(F204*}*y;Q2m=Lfeir-6jOmh0DQ z_nUl>wujChM@)Js$Ai0Xt}758M=-A9czsihH`0v@6U*S05K@$^<|76bBRsY$wY~T* z8v~7v!D82YfjhL&{ffOKzCHAwt9d(zK3B{izo(G%(zZ7Y+OIB=2NVW?6aJH@f1Z}0 z5H4ZuFid-d?u|EhF+Zp&NfN^BMLxAWs6V&N?+S(tco-pWyD+|I+wBJN4qyNx$lFQ$ z&;6gH60g6Q?3N93SPcwLEAUI67C<{valJpocA=bm9;-a}ukQx64m@r5k@>rDzh^V; z`mpZ*XQ|329$zd2A{Pk1Po4wNK_v@0jhNuY9ueb7Ybx=O<<7rooF0Jo!e2*c0?EqY*=e@IB|i9SBH*E#LJcVXrjsDSFPQY@ZvcOxB%=FNZ?O7lz7tA( zFr3mSK<&5&=K7$DE6!X8wc@xk{X#jGE)e{Mn8?dEFW`Vi zSX8r?leq&t9FXWnV%!ikn$aZwp4T#kG~|X(VCFU725F*r0Xs7fT8UXQ;1idW1}v$) zzYaN3puGnY3zzDS%4^Uv6pon2V4V)ngc8B!ScH_jCc+ickcNF$AE2}TqFiWANG6*` zBVk{%ow=TSB8Gn8`_DwJSkkY>@!uCJ1jz(KP+|d``tnWXkUcOGKw7T5@m+!H0}6OK z$|$Tr35`4~mD@l$7e(w5e}rtQbQMlaSxy(cm^n5X(u6;SAE$|h&q&SpSUR310GnP^ zQGhO)!e$TV{{d2Hg2KUNYP+ZTZX_Nnp#j3iYx4YFS&lEHp^Kz0u0jS|8&6aP%c+Xj zZ!hyH*g8$OF{HHonI=9FfH_AV9IzMLhxn8sHp~v3Erh{K$CW!1AJ1g~$D4Dp&GZ|r z?RMm?L?q)r+XWp!r+yxTwovLt^tU_3jAsqxO2ehqQVlxBl5|K#aQtw5f_lP4>gL0N z9`Z=}A;sGoeZ}t05#>v=0YMp_xN$+7t!8K-lIG$MTs-D^?~>FfSnW%BgKrr{d9CF|#gZePJV8CC+W(NJ z0lDZd4>W_%RR;j`h$3VNlc-j?4sakqLb7m(EF2!4{6GD0h%|4#WZ@1atfzMRY)69_ ze*hAv>6Jp^tPR#_(3lAptZAlMm$+kQy}a-am#6WzxTrmw1`wZlL$&~znqR~RZ0<5jBEGrDhe2)gfz18^Q(QAHwQExoM*|SBb>@H za-nQblc8|U{hm^k_^smGoLreGbj;UGhoSJRz+K#RaU`!|C<#keWBx znV`o+&RVvC2X{MqPnR7O=`iSlg;a+`?7F`pu14NYiir*9Ek6NC5N!g)phlrX@6xdE z@Zq7z;L073PA>_c%YdD6*P<_ZASB$!&iu$g87t)3aUoYO5*KEI+%efQIB74rS0Jk-Uzue;9Mv+2IN|=6Is2S7TA0V zHSsIAzkp>4{Zn;Sp|uIF?kdv#)%d&SG{)z&`DwvuORLrg@`wR;K-6$R{^Ee7w-+$s8GT z{vr{_U%!+i<@HsCu6QBy3zE&l?|XP-I8P~?A#+FVKqUwgY?6yRXTfmRy6vxTB){w$ z4_nuf56z@=_h~mDZw=LF6Dkov)yRu>prTLBgy40=WIZrJXuTPqdMF=QyyxtK9!wKf z1GJX18U5Aqt^8-WKy|qpTyrKk8>^WRbjNPHR3t-YyKrj_3Rwf-l^TYfsvp;53xASm zmMph~LebnzsKhNV#L&1mo$vwK@B&YoWVK>9nCdsDTJ@*6@|2f8)~~kjI*E0Bm|8CF zCBDch*gY4;N33o-dHEqphuBzT{TM9`{ymG$UwJ+(JOJgXj`qD292cNGGc;d5wDUQi z*_u+6%Nq8++>g)=b>FxrB=jcN5_?<^lz=B1v~9KD-Ho^g92;<&cteA1ujnu$2XS#vJXnSII z)?wh?7ruW&sEhsr`$wPNlZ`f$Ng@o#T%8k?4w`dCD_TR}QEt$ndRt2sb8^{Gix%TU3 z)Uy!FxkHhte^q{EKnN46qUsag5O1KVdo$zA`wpb`DhNdXIA$`6a)t-Vkmuu4EIYRq znjN&|ATB?A@--*N)fma9}xZN7lv>6`r(E3e`&r zUJm6DoulF_X24+Cz<{|e-wPv=fYmPNv$BqWp-yF3vbDIh+P}|jxAWN&^c6Yp{ky2h z5qN6!>Lz0a!9#GSEJEdpC&e)BPbEFT%sG+KjZ!{&>BJR@{t7lyMv1qks3y!Gfz30X z8sfH*%(*@+Y9*iY_6+>#@j@R>@qFEBY!Ov>`qPUYD;SU+P*!GFG5xUF6i!`8(XnNT zT}8ShlRRfJuXu!l3EDrQpyS<7Mavy5cM?jBlP%}S?ah}ibH<)|&86U<0;etO& zuRBdp)Z@^);dqlSH%n#h(eG&7a1U4v4D%vgf_L5}e0ifUhA`m6TMOUNj@{8ZbmLiZ ziyB{!&Cvz2IQ*YySCV3Hs52jnbdI&r1(G6E2q2Bp$NC(|K=C8RSpY-{Mm>+MKNDaL zAE)}e&}{YC5gu8I*>-4mfl7A?_L0V$w@;jIH5}z0n~17{awr98J{NjZ6wi z=Og9rqUr!4b-xR-xF`UZ(LPs@yDIY&DYQQkG-mBKK`lz`GMU`WCxw|$Dhr?F7f6*C zNEPQuRhMAs)tczPG?fK%U7T=TWO8k;x^A|+8eq~&2IM(Hj}7S$u~88A8tR=gP3=t{*0TxXwO?L2KLvNrnUWLNV`NV0JHAtRZc#lDToT%{JitjkTfxPI^?xqwI_BgbAHOC||+F zNl+IGvwDroBOy8W6N(?9i*VP*He_5Zm;5?OIHJQ=VVk3-slsUGCKVkC7-4JV@|=&f zlNq`sb5|wzVk|X>SNcRTV4RJ;N^03`9KP{+fbua&d~Up0X;8U`01uT_#ua<(oA9FC zkN7Z7+GaXwNA>7%d>Ptush#d0`t&oDt~KoIcn8fz!tn1r^ED>#=<4s6YGN^1h892q z!pAg~zMWVX&TdY!V5m@ci3l8TED6r)Zsq-OcP$oQt^OSn86Se-1Ex(l`^89~zCWHB zIP{tSFr^4|jd8TzrAbC$+29+Y>9&@@>nJM?o6W_ymv&}aG+*y5QnZb{jB<6dL%h=U zOtD(2!cXxizKl}u)B6QiK`9V7#~B_GvYbLFLWWof&H)a`bJZgi-*)oXbQ78uzT{~8 zbKvkN%Sumn;Zqsp#M?O>5nTZZ+jwq~4%7EsW%l$fZh@{U#S%xMw~9C8$fhhx^LMmt z5h4DjOk-$YxN_L_%Luz++v9y;1^kf&!n%;VLyU&?nu{~12Ad5<$2(D`S#A`U9v*pe zyEW__W>>P+A73fo_Mv^^1`HPk4QGWlmn@i0a5**CxHXrA(NmvR_`NUi)JU`C6juQ5 z%-`3e1!Pdxs{!A>ziTSm|CF35g z!8Mg(|3)nxy2s-pFDT166T}F6@Y{J3v7|7iC>bPuf^Aj--@(D1`bm*x#?BA*K5pqD zZi(q@9PGj2tK_35p8tpN3h{gK`dGI@0MsQ9Wn|rInwdM^5WzlS97>a+^cusrHsN!? z8@l%O+2gKC^R)RW+b}(E6?%B?$&%nPjC>Q}sN$=}^X5nO#LW_=(oYIGk);&}JJ8Ch zx2#=9b(-@}wvX$c?RD~ioAehu(P#5NInpE|`VBYx)4bDqEpGkMwfHq_e@{+x^Zn|5 zZqlI@mk^i@$gf|*1E+ZvR>iJ8M&WDzd>*(}&cMrt)%@E3V_rBX-&_8*wq$Js>$yn*h23YM{06#Xdt`DaI-8x~H5a7NdBCg1-NUfY_DqmhN zSW-{J2a8UJN6BpL=>)RORSz)CTyz8mHh01-o%eAzn%ea>{DM~Gg=bz3)HzSkY1#q= zpl)_}!os(1k3n~`ZHB&(t|+Zw*TvS6(!DcHPJGMISVt0s(ToYysPXsdo4C;biI-Xn z^Bw2=x8ZI-mDNc!dc;0)4a{qgI=N8om|@lnf_9$YX$BopTHlyz39ztHx^m6Z1T}BH z`BT?`b7Q#z!E)#(QsLJluYuEDd!RVA#?Q2@0>Jh$_ls56GclmTQDucI zDXomNH3clrhr#?{5caDJIXkcKhsq*mFuo$aU8J%qSiN?1;NZYRfT1hT)>29Cip~-H zYXk7BH*w0j6GYjb)TY7%uSMxc7%$V;tnl~jF7E3^Og%cy{%n+QS$Rl2FRsi=6X{)J zqG5w3$fHxHCk9op0h4~z8)==Q+C698(;hvI=A-K|t-aEoE?9N@zlH_3V7{OG>J1614P|fX zcHy`Ok!?SJeLKtl_I6jc{`Y;nWf|Z9;dG$7mU-oM;+-WRtM~BG3+KAbtBvS7I#r9H z?TA|oU!Z<5O4O_cWLV}K>?Jvoop1jzW~H~Ce7(4yDs9x=XuU2N!*RvB`Zt|+-NaN> zyT#=(+Q3B<-nUJ_cxx>Xa0Vj+%@ioz7qlyaV=qWq8VF@eZ~2RLl7MyQb+OYiTSL&v zXT|QNC2+bI`PtX5FPY^TN~ep_cvi;L!q!@A3BgwZ3IPh=pQz4}NiT_OVa**xa`NaxV$DsVDLW5+~-|LNfg_a$}EIxtU zWXP^Pm=Vk$;u^$0B*AfY75C8}zeqPMv*aQi*R8gcg}87@i&Tj)v-N5Yl#QN=MlA-q zTWSM5$3ARNJd`{ug5cI)#!xdnUxmQ*K~rT#kReGr`mHZn>*FuilWS+4u6&++QOY4X zRoH-=UAEH{z1-9^D+wUEfy7>wwj5h}LS{$Xe><==vY#tD1;$UZw1?753i5HNkHaVk zc3%CkTuNM5P8s-#Db&vU2iAf+W%FnEax8>xnBvwsq0!n!K4GDpL_lVAYdof%a&42p%Eq;eO{pcDtnvY(w zv2r;+z3%F{rvig86(l%3Kf6%>c0jhnIC*;D>$#Tla`5gYlbHkyoio2H^o;6z*#+qt z;>fF1|KdpVBQpKxsFH#He=+yP9Aq)_&js2oUh}#TtI^?(CTH_A5ajG5H%+q8NX;t2 zr&H>`4*l#|5gI)%RDLt1=hTEoqU=f-W;&cv*Dsw*epIL7?U-Kpia6W+CLbOMqT<9) z){_#5eu@@8;>x$jOF!kq+l`{hLFGGzn6)b~fZ4D5p*PfoF3@k#H@tRA@?qG#mABw< z1fz;nd0j*bB5-qxPG=5%`wxWSOhxU}RFOSN7P=KX^QjWHKEsNf{|!u@94U^YePlI4 zw-wMww&G?spWsdpS@wZ#m3b-->r5eZbF=EF6K&;NR}1VcWTjC$8FD!@1h#UH2xi>3 zQOt`}r@X_}FzD+`#b5YZn*9epLgH=3Vv?OL1>J{RBBOqLyag<17LJ@A!q5&tp(6&; zHmy>;wS2`A3-Tn?-GG9+ptJc|)d7I-kuH?Q=!NEq#`~7;o3?l#g?>+=$xKSF8)Op%87}0`feEhpMM}Pu^woec}TftWB=+-$u zT6DTd1*zM)ghs=8jv#t^r;GU_8XPagt0Qfl`ZT{BbAN)-OG5;={W<%^n@g7YN0TRn zg?r1vT~QU!+Y5;-UPjCx=Y(sc@SiZa2w3QZqLcx?=1D;i$xBbHVz;W81U0V=4imoe z7t3wvH8Iz<%sKfyy{^u}&Z2RS-T%Us{%4~1!9VtR=5{|O7StU#$cj%zI&^w_uchDn z+~Y6^U=7ChyTe^OwHD=Im7EcI8pi9W5s>j{O`paM{{(4$vme3sc8@*u(m(REa^}Hi zyT7mx6e;ht-I6$ z218}9K-D3+jTgH1^RhOBs%bJArAK>bh_ytzdsV!LLuL;~rzoV9m&D%u@p64{cjG(# z*PX?vGW9+Io)uqcqPWDUL45pfYUjaSy^;FfA4>+R;jGqQvk_*b5lAkW42Zo2e zMs0E*iT=~@9?oJSFZ(6ZUd#3xoh|Qx`~cAZwEV!56)7Dh#F`RqTN(eS^f$VQpO`g% z$W`&Pn-|>tV*Ya>jqfveL2rk9^+E|}m2XN@@N5M~_9+zDh<1mxxaq=~G7G)*!(}3^ zb7WC+;sir2E=h@61$^gya06vtSEDh8ssr+_zk1~M3<-}@rW!q`=()#hIz7o3hD$ap z_c!%QuLdtM%5A2?Jw4bu5QSsbJ6Tj0`nqQ~ZFa|lq#F;eM0NaLaM`!U&_~0VtTWQ@BK~_n=rznyg64~)%`=>0#l|QCQ){!9?z_$7w*8D2f zURL55o*9A&vU?BF8tthPHAcF5kBY&{P_Y}bE)MdRrlHJoI09XXGlwW8>>zM@N=>qN<`Nh| z{71Q@y!aD6stsqXHJn#d4VOnt)$#NE6GE?bov^l9jk~Tj|5hPnVi%Uk!?Ln|h|o*mz}U4vKGGiHi;U(IS3+sY^;fi`4rce3*|a@@~it{|6wR$>naE zIk?Bi9PEVKc%L2b)uw)%2&kvX#r}fbuMK~k`SX|H^NP@a8T1>McQS6`6S092AzB(| zOmC;fh^*JEnIEs$YiZ7iBbmvYL#fjt_WSqy$oQ*sa}jQjtSQJL7J`%M;dOVy|HI)gX=2L&m<@3uB>2(NEH2tD#D{KeEm7 z9ZDN3jNiE_G1jjFIAVUm{%@}`GA|=2^g8)(Fb$A7|6^bNSMtwK31s2Qd8<$TUzX_& zUIqDhWdOgWE{x@?35wqTIsN(M@NcV;2?`AA0glt~aKeMWUvF zd%b`MYZKSC84@5WM{`_E$&*e9Cl6^l)M|ipH}m@cTs~2C*_bQEQh0f3#LUx;JVjes z`W-JQ z{og_VPZ?cWySWnLYkagtO#yP#F#A`W(>?bEMs8*3)E+Oc2}|v?+ijI!bg7pGG@asF zqAyuD6+h!w)Fz+PexrV(p#T4>@c+aXMseUuh${F+W!ji?O0>=Es0M+^YpfJAe^tXv zRAoQ`=(18|Ba>!Z3orNd&BnHXk={B6JPLuX_b11iT==UC$H%=Os_Zt7|Gxt0F}E0T zi+$>gq4rnPMQ(l6=h+esH`xsR)Hwr1bD7>YFO#PNN@Fy0NtWAe&OevCV4PffUsECd z|HT_NAW||jJzk1jVJ`C?c|yy27dth!(Xeh_F-Ae37U% zt95o#uAQupx|#qZg?+LS6)sfagSOTgxfuI~cQy9^9>xFN;bM|zF5WWs=1sBCcTkPH zTz7+|_2HEgI$vpUp#)m7>UCVxZn^>VfKT{t9RH;k)Da`@O<~CpAekwO1Up8xbJ+Yl zD#s6DWFLneXyns+&t!0Lus3;sb9`fz1Q;=M4SuTd+85}wmTg$6gJs3W z)24xzY*qgLKAQ zr0i*a9*tL}n$I7w|9kU_f?|a}pB0`m|G3Gw%=32%27MB4WMp^1Q#QHu&_?!Z5pNHK zk&}~&n!0G@4n~i&vB3;Qx7#f_R}T!1CLJ7s4nn0yBZ!XTIs$AKLfTp~p-iA%=YKtG(ym`$q0PkLQ2e741p8 zb6<*+f6DHev*l%cxIIps{rbC{#j9_7y`A{}a+Sb}s4$*=Q{Sa3s6AoJjU$t%ONtH~ z7Z+Dz^&330!NSbg_rLo#2X}_(tLeY3tY7{VgBUfui(28i7%6IAOfOy=#nUAQ3UQLj z{Sf3;ehK*f7DD9DwRt()%hVB}0hmU2n#Ocen_g{WyeG*l`UQL>Sn;qWX6C}06!#mK z*VMGM=|MiV*m7k}{`jhzYi@21Oq=NF=-Ayg5$+Wuvc*LnF8ZOreaOhh#vAi}Zf>sO z_V&FYtF17;Vw2+aPcI3tAxqY3_7oE>_w+)I&P?+|<%#faQ?Z#K$ZFWyD`vd#_B_`si%f}rlRZk$RY-ZZk6$@r_ zq6=Ba*3@-xu(G3aWN9RNEm}@z;l7CAn39v)ZNT4k&cZfnCG=;gd=Qe)F`1ewJ>&J< z5sEb>U-RjoxU>9$+|~Y!=lpa3v%yXj7!<8d+jZ9xr@_1~y!=qs_uZ-Gmhi3Io83#x z#Xo;n-unj9#A!RR1yphw4E)MH@#>g-Rf^KXs-J&p1~Os(V~2=moB{#|G?3>&i$ zMLQ|^J2ZPP`hK$M9L5Lx#evJVCWul|L0L}0D`Rbf%W*dB`$J74eXHY^e&k`)W~2NhJK9>1n+`U{7SIfdFQ56; z`AwL3g@>-!Uh%D*((~6Bz7P0L<{lxw9W%8Zb7R-OQtco!pD)#&z01Xedf6s&w2(kBbmru%!Ko845th79Os=H z`5{f21#PK$UnzYS?sd}9RzMiON+?}d%lmv;BG&UT@74K~&LiZdT*?2!bx{|(-1qX@ zhvaHAXBBH(q}9pk;2mu|#)Iw~No#`eX-B=N1Ktl9myn}cM3D!sD}{bFYD?HdljG*H zJ3>)6>8r`}wtqNcUrA#2or{Iakt|KY?IQ}J7M*i1DZPB@bYLovjEOlrJynoXvh;$6 z-+xQPJ&xJzG4}bIKl<%R@dJSdATu193{#XMZAJL4S{{`@u$L2E_T-eA&uD*e|3kq3 z#{ePX2(bKSOBKR={Nm?uk$w?X9Y6W)C-8jiY{^}@AfHi^x^QxmS;5F?`_FOW#-2VO zRn}To^5VT}06cm@Ti^ckY7El9B>&y(!9jO6&JV-{FFXz!IQ)qIb8wb(*lHUeVlgjJ2w|?H z{dO|_)Z@olRh9E^nJQQ^20xUBKa6@64Wa+cpEYq}=zZ0Y2p2>AcA9;yErUeJ%d~G+W z_s%F88j)`IqT3TJLc%|Xw?`b=N?l|TM!WbBmz$arvrWofhK6g1Nf25cn23w1B?1d`*;d!$nx+}(a-i6hQEvG3l^!Oie{PtyCefrQ9^osvA3@Ky5V zp`vOaUKq#yBqdY8o7}>(Vq8sK9qws6cMf3tU-XWTk1LcUi?D%=jIK_+f+lm`ht%3V zypT~)3R1edx_h$>Iy6q`B+Hm z)Yb7MYjzL=(1W+gQW+&HG#Dg9J}1)RyXi}}`^>G#ih4cl$jl5ok z!TmKG`x|h-74T1c|B3FocN=vh?dHh@M}>cB5lSena`ml$Nwn$b1pOWt7D{0x^GH=i zJ{Rs|wd=)f%2tPn%}iY=>M2BZ&F{(?xQ+_OQS;Cet8b3@F&f`f(es^!zOV%3AMPb>Quej&va-0}vIPydMDntm~6Y;H)v_WFpvmKH{vI^lg( zWgrs&OgeVf|KGg;F!;|o63(^)@<9`+arPEKe7WZPs(pN7%_3u z^)+?2HE6x`6e^z`(fgWR3^Gy&Sb@Cr(f zZ@Nc4E`UJ#E|$YV0Uv+;{vV>=I;zbs*d8Ws zthko~#oe{IQ{3HMLjrtx@BQ8N{rjwyoIGb{&dlDk=fnn`)5xn3>nDZa`K*pB*$6Ib zG@ZLpx3y(`DP@?6+XtW)@TmNO#^zu-_}()YrIqK$9EemmV77ZvE1cH})S~+KGA5hE zBzsESA)@|Y+tZ)`=e7>sr+-`TjZHO_VCl|}-Fz;falwoc<7#dBG(zDPy!g zo6{Djk+4)8amwFPRPK^J0_JX@17?rPuTrg~UnFV;j`m(MyfQ5o7dBHc6{{YRB)Gh` z4q){9C&(be8t1z`^DC^P*jcIax4zTyJ*@Nr&0m$}sc=@96W7?Sd5@}9KVO(JYe<6f zr#If9T(1lrBBhOsDCO#g5U3DO**`o+5F3d>d60S-(tS#vL_t`TU{*=2sS3_7WSodX zdw_R@Dgo3`T=yqaB?;$B4cgE?JUlj#srKB~dkwVye$HIdWbFxUeKZM1P|NUT>#+WC z-odK#isWg}z4S4XzV_E!os`z&mD*LOl~(w{F?#*0K=IpXlc2las}atfS*)E_zknO- zoXcQ2N9DNc%4KPl`sdTdycbMx{l%V(irmOy?rba7)yaG7 zm4|6zH~*_F+a}=vBBqU%?HrgYIDz$Q(Qh!ct<`qOQ`i4f;Lw)=^Uj`7qk6qR!Dp&4 zoOsQ68r{2f2y{^4j{1cosMn|WPwA#k-vNdXjP&D18(oR`kGOz-63J<=XN1zy)ooNS zm=6y%^(44m8zoee)+D)k1TA=4^p zbZo;3t@qhng{`t7`nhL1M`=}4qly&TpFp_Jy&r%@Jyd%E4HZAK(IJbG51E9+E~Qzt z^!a)__3e81GY4;+IUdLNBa@=*Lr7e~s~_9eLb#K31Z$epI>P0MwiGW)zOz3doi&8DS6&qUlBRn7-pQ$~3%Y-J zI5aerhyUZp4~gC}K1u;{X>Q1>eD)TFKEHs#6$}4jfYVD!xdIItej>TN2@y$FG}IXN z$B#IUF2<%8%&a1OtIIE__2=X-flAlk9tb0|t-#VR?+`hi*&hzSolh)p=IQp9e%;KA zJ9`gBs1%C?|!x-VB zpp+s?;oIS?fBZnrOvllIdhXv*5)(gN8+otaeQ;STn=c>N_W5uH(S%QzKh|?+wD?#J zL?kCIv9+Mb%nJQ`gqKc}KEaHKOO+Kl*@%nYX{x==Kfvm@xeB zA{Bi3Rh^cVqY(@H zwbiQamkaRQy?Efh3T4)^5ul`lE~dSC@1A(I&|d5$n#9;Bx-4|H)v`8ba&4*4`3Qv~ zhytr2KF@ts-oA(bNKak(4+5CJP_4u-yvRQ*VKvvdeQfQEH}DO2IE~dVCAO)V7OymU zSRP*B5))exn3$ZHAb!Ce$(=N|mj7QIWs(MuFO8@H?({!JaVIdsq(|w#1bWafC&4m1^zO*FdZRN1XaqG{S6N-AwhQJBemmC}dyl^;bs)Cb?f86ElHt_w+ zH-d?U#%BhUJD<9Y7NmUwAF8f)(JObY{oaA2<`nuk9*nf>|KwrX>>yO8LpkF$r}o4_ z2KxH+1Y-$Y^Yin^$Hz4?Kn_~5uPB&wd`u?It*)bk30)5hLq|v7-riP!>zA-!hlTyP zAA%z)DoO;OY7Ond_y>`^!ohFZVrpRqWtvdlL2dTWYs6A18qybmf|_r^NV)2hBOZOB zFLn6Ymk%s;bct;0CUjJ%&*j35SYA`mw1ns!%dpp_c+r(U!s)CAHCEz*E7j=n@4-j+ z1yK4VbM0Tz#cqxZ&!TeH9acP$-#QI0dFpp%DD9YzFhpD#^b4w+fY{pK0Hj6#dWN@Q3MEg8q zCq)^F0ug=#ZhkA?H;1zT7NpaY_+b}NBh|GH8-D-wKsGN~$VWJvPKZ{*`wSIM7bl~r zaJmzi&uhWEYoT=Yv!jHK)}wIR-r z-#8m*;5_?UV~!P&mjP@*ceWd?jf(6(0px=T|9`RvgP#7*r) zTIL4oBhF9MEhVm)yd~Ek&sadc2-U2`wsk5Av&+=2e0;zc?s+h z|CXYQf{z;S?6RCAm6bVCB(u=P0oi%^jv0i0>3{>-+t~xXxTDX z9DwM81kp&hDYh+l@|k}z$@eO*MoQG5hYYkSnu4oUaE!zakhz^k)h5K{b`L9t8lTCgFRPt_aU8p&8HaS#M6+s~ zug1%5j*o2<{z?xIzXf&4p4|N)bqV+yJXgu=Ul@Fr-%)Vr^;ZqtQGBZQ-}y$*#GA1L zH2*QltPJ*+hPO1iP6P#s-74!1zHcVTc;BYEl9;Sd5yWGqW-}12Il!FxvHl^&>+xd#%$)ktZy%c`p=9cVvv-<7f zzOVb(>$}txiQF`WMcZS2%5}=`-!=`rXBS-`8j`)Ale{n)7ubyNMQM@>@`DN0zzy@s z4&tZBvskJrXu@!S+Go+sXGGE*5c|I>M)ph@r0RC1|HEsyl33r47HLOo^lS^Ysuau$ zCmWWR4+zl-FgL%ow65jR^PUE)Ve$EU=mGgC;$2J%}d9B<0di* z-Z$#|6GFAsT>8~u<2E8BQ8lq)Ey5yDgRb%iyKbhx%y0LE9IPC-s!d$x_bvKUoKNuG zSX7iWGw=Gm1xKZEgybEx5L?9C{sWF!o$aY8tM0EShlhvX-Q9@femnVm8LE`|2GA@5``86LWjJWiPd+gx{i-I#MsQ~6F7c@c{ClqfSr|~0@Bntq;4tUhozhEDL4=@Z+pyY8!9N{4`a2x?YWX9aqL2dro32?2_d|I@^X7J*Thh{< zhBO~u+wE^wFQdJaDayM}!19;C^Js4AmMi#u#esx7LA#Pk3p$1I zRRZO?(!%!PGsah_lAVR3e3@7pReDKbT2yE|Qxjvys<3gDJfjF^ZP5&F)1j9rrvxvS zzj;7V7|6XpWtt8%84#~6WT-dL>8yw@2k#LaF+r1fOiKDog=C7i>>g!qA{ zw=W7Ur1Q?+x3DAO2N3t{J%;4pEw1mag=PLlpB@ny=T@_+1Ft~>I;sD{fopG3-9RVp zGX)x>CH?xv#4@!d>*pu_&)w6LiK)={9w1xq9GSe-6WUIX&3@|Z<;?SN3tO6DNTvAc zAgwqR{+LzHS*Yn~&z+~{mCG%hW3j02j#fMu{V$D3U+VLYP+l?GugV!GO!s#WT%S&?AX|_a zIlPsb;M*3)6@y~D1Jmt5-`vlooyOLCBY&(~CNUOt?}n9hs*W>*nDBZ{OL}cE=Mu z3lp!l^M$b6)rPCi89k&bps~q*qBXJN9sDxvHmKpSHhy4VZK1j9X+J9*=w)&@ueKiV ziVz;V4yXkjWbHKwXur0^2ray2Mm&G|7Xx~CxBMP6Z{RC)GU?g{kVetrqPs00O=25F zdxHGlwhz>J6H$s-L^T(%ad9 zXNe}0)?eG_#!J^E>T0srU9mR}BVnrh2gd@93dXB}@y?Y1EO=j0{px8F*rGJ4NQH%y zW4&y4QC?YH$?3oKM8{*JOwU!XwV$J=B(snf8j>u1o%y+?UoMDe=c(UfP_0^3Oa*Hu zYuPlMhQ|I=_=7FdZejLmAYv}EY%>*si+ptR3eOd_cyex}svnWBxkabXkAE3!;HTdl zp6$XbHh&$NM8~}fOv|0*TQR&&aqkO9e_ibL?<}V|Z>?0aUH{XC^n*_L!x`0$*l=os!!|XjfD)cLv(H)elO*y8$?-n_RiHcPb@d?O;RrFE>?7 zt!<7sS>65I*yCOGSir+hS|No$ZOhH!T}Xt6Y8P_?g`p7~fnIHPsM!`6)JzGZR04nb z%vH_ouMAfI+-+f_0bx;=W<5Ld3u?;H4^-8;kKn|58e@KZs`1{O#nHIXp3W ztd~4(3;c9bT;ai(0d;fc@<$9(4;tw1AYE4%-MBF&K&S5>I|*YRyQN=0T``|2DZ%H} zK8+9tp2_nAyL7KIy~UIO=ck{3A-mI+c0mh-%A%~n?M<<5WVJNAAlaEfdnMTT`1sAu zP5*D3Bw|yZ$EJATr0%6?Kr@%aeBdL}^EQ_7i^)FoiUJ)tPJX*AmQlnmz4^j;^F%vh z5*83RmYtU0k-hLP%RS`(u}5ty_hzwXQ7^f?Y?TA>D+BbGE747AJg$5f0!-F;mn&2Z z`ET<;pQ^4d4w8~$Wa_zzogFn++O-LekWce|muD=+{!i_@aLHBawp;PYYSGOM@zE2J zG+eP5F}I8oj?eUI95N875`7%evo5M15Nw<{jH>cw zrKWgQv5c#vm6E`$;wkL_yM0C_uf5ko(2J#|Z3}F5>|E31|n*%1veh*(oH4WB}#$W6PWFb>awjC;Otp+dpIe zOOC9y&BvZ}7PpmgoZ+i0S8^%QpEWcz%CKJ!ow1dL(M!t~q8GQLVb^i8vk#4oaB^^j zLf;mZmyZo=1eKZX%%`GHu=3AH;$U@vG{z22ee15v)u<@AKRK@U2Z}{5^My(Bg_ZiG z9e+GL^v~PuDxFu%8Wizw6AV;0<&meCAl19>xxF(DEGy1q021Q@ zg#r55Di~BSM#=K8BeB1@f%|(2u1bJ9X|MPZA}yJsy0T-eE?as|I-^Q@(8`6pP~b8- zuJ>Z5Ko_tltWyrgD1IY(reRw5W%22;oc1x4l=^btQnM=XR} zp7uyytPC`ai(z>5H}9klMm$j%+xJRgG7W7BmZ_tuhN~=k5qDRKq@nTV;{iy&cp>S+ zaq%$0E}MYcfXC_fw#M6$!*U(LPf-(aF1c>p}P6#q~o7Fhb3cquhDivq<%&vEdx@J1ax)E(-bGPohgimB&l+Q^KZ%}&HEE!kYTB-U+;RdT?ha2!q@OGSIFE10JN9o_ zxtF}KS~#{(m;dJSHyo9_E*3OOQ85xt^}%t`j#j=x#&Yi^JWxfbj<0p}+( z9@VpD>2Ox(e)1vW0Lq91kj&l+{oc`h^%M^W?tU)YHA~Xz5O+{Bi7}@C0#Z>-}JTk;Y3WNVIKDiAJp6`Xu_(FQ=-I z@T#7V=u**Lo&}9JNS@F%w{tBxH9q<8SMl0YAXR} zy|;9T^2R5>-ARfhIw>(r-3TMx6)t%DldkRC*wuX%)vud{;4fG%Qh4?(!3ud3IM|@q zxAThl)atS@g80ZfY>?$X-&nd-QS;d1rg;Y)w{Onkg7swPi9kwJFZquK)0H8Q=zI0F z_NUG&+L8!WAJ?V);Xm=oT*3ke%4>okgQvser-vuwHX36yxVPtaPlWK7OvHlI50!mK zwad!0DZj9Ujaw(&o<57rKqowTguCyS0|3hx1*%97NRFk_AMQ%Hg*nc+j- zWzLToqe3s^JJa z4t@hkcW}>QM3t&>%hGr@|A0SNdEf&7qV1UPK0CCop{Z^FJN#Yvy*yNqlTg(!oMRQa z_e7pJ8}8iUjUplFOqR&>M(+w0+z=asfP~9y=K#f!C#iAWzu2I08v&|llq+C^!U@3c zjW$?0!2(A6O}}Ce?uE2x{~dNaBOY_1R*?~^I1t!HIA*ERj;5ljiobXFXHmpgGfItw z`Hh37U#dJR%M`0T6=r5-18=>%_Om3x=Zco16;NXhg5egHF=#&M>{VzXa=N zHZ&RA1LYVu7dUXX%YzOV|Nl3zxq2H6RM6z!KqION0h8{ze_wa5KqHU^JUXVgn6C4= zl}D(~!>3`%CO!{y1G!DTqZlYjS*`PMI#yzoef8@EVsQ2Z&hap=@BjYDJ+lLbHkX3~ zzIrOZ@t$$2s+$R1bu{uTQc`;7h{?tFIqB;H-M*N#gy8URGS}g4DrLFtux_mJJ+ol+ zcMBa6@AUb<8ORrA&E`z}&mNn2OwBU8G|HA4l)a>aM7X9+DE*K5uWT-b%ivt7y%Ed# z6x9cANtdeyI1~3w;fg zfHHFg2M0e`Q{7PfJ7xde4WC}+37k{GqG7s$KL~4wdVT&wx{Hv z1Bzpq+YtsfEbDlKYuMBQ!i&HhJ+w5!Jo7!ZlZAOQJO22Yl*0X9F;>Xra+%IXW6Es; zwSdU>8taCnEwksTbQ}Bi9)(}E*O64q@lX`!;*`{4Qj^)?%5|Do`C^Uzv9-zn?ZKDz z4a@E%$t=b~he!XXnG7uHrvoCxjt(fE;cy2dzTw;#3en0|&n}VnAT?_nuSqH219N?= zKo5(04jRb?WX7pU;RNOVIBI#l60hJieMkJJm4#m?#bOpdiI1`$FXu0(8$nP}=E&+8 za@s+zx6vOpXCbO=FD(E#m@ab+j@^qW^sQ@YLki;(u&Q z3?pY(#5fRN_qswBgd@AYMW?m<3bES0)0jMOX^{$-A?zSn@mvvF(UG=}jCDI5Uwq-B z2Aun|LrZ5}Rvh>%*^Fb{Ty|={z!T+JSHbB&+bNvF;jX8~6x|{g)-0U2M<2cZ;6^zz zVrf#^@ZPz*Bm!sIT>e(MqOPhLo)Tpq&0;NXQlC*4!|kZWH(c-VAaF&wJs{vXHjpY9 zIM2+LJ+TK6xj%jJLLZMiYi!rEnT9~o+1c68&refR)6VXoK`CB!XS=i4GpV+>zmC{( zKBBh5fqUqt!a;b*v+~b(=;B8mLaR9;>BR#JgO-DtH@0dW3%{4CGtw}G-z^ipnq^;F z!*7`A6N1lMg-=&G;11PQ{((Wo_3GlCe2Qyt zRA2bo)zvol@TIS%qjRpa{%3qSnHEl&-dYnBRW+a((F-sXTxS3($fu=jtgvGJ-imnP)!@L;!88%6F}Am*;{8n}8~r6!FwtyB1*UY#EoiAX&EN);B;*Eb zX@;(z;2&q84s)%}!49m6wI*c#xlZ3^unui@&80}T0XBL+V^KysdDKb(>LlWvOZgp6 zw^Xj7u@u50bB!fjUNKHGWpXx0F7iB{{8Gbty$Mui978SYx<6TPe}7+BC)7|}sbA_6 zhCVCmQX8U<7WPg+;4DiTo`|^!{h14h>LtO)$NPyruAW_99_vo>yQoOieQ$hfOk&gG zqqD^Ei;0^v3N;LTkvp3tcS@eGHo<1%$n?d4XYul*cu=7l%DRjyn5+1UQv8H#ywzkG zZ$}Gsr-G$t3r*@)dX6@c^VkG7nnZvS7jBk!Wm__N6MG`!JMCYaH8uPzxvH}(#*;fh zy>)+0ee^XZ!|`9Bv{>xy?6vxw`y6PxBG@4H-#uGE>HGO|VlX`gr0+YfypO=&N_5ZW zWe1`9y1Jy~WM)Rj?VX+bkDh2&m^F!ZqQx=x>mfA`+{QWOFcFN99iS23;{L8ff>>Oa z%ehP8xMQYgVQMt+70){ww(4RfoOc@8h2%E%l?VNhY0im{uYs2TAQaNZ9bH}xdn6~I zH#lj}&hRL=28L1IO?=$S%F4@q>0p*)cb~LX{>aPA8pR;j4vw<%jm>v~4z3yCl^OR7 zD%;xH%E_UoR)XzcG;|Rw60Jccz=`UHYxgFPU~MOb_k zp?Tfc&~9$7rMmGx>bB<*m|u;SV&0+LfY$8^_d(35b}sRaff{Q4g$nY_FsdX5OSL%V z@B~=*)agTRi1HzHsWhSH817APF&5yhY5B_-OF4+2yWrN3{#cj=Fk>^khzOKd425 z!sT4OgUOv7`-;L;FFw{SIr*4$nDf#m*kA}_XPRW0vj9CqxkF)P!yuK(T{DS{ksqH% z3qk76c2DXqFUcmuy$vj;!O$;2$LinuOq>&}Yh&3YTuzvS1`d;Di8EEF#{qSBkOpQ zcRcWy+g9lS=RW4kI?jy7$I|`Nq~t{B`JWPq)ypNP`T>JVxfQ(`e(cf`CC_G7CTJa?v0Cca|<=co)wV)cqqh& zX?!Sqs*kGG)y)NVYC~@U7~F5xrj$Vw4t?%EPH8?a!@@GokPWCDLSq1mDTpOAbl34* z%wvfCV9GFnb#*JWd8H|y*=Or&^vxSu-p zzv}J1#%)vIK${PRoFR@Zp0}@kxgh+P`%W63YNgG}&qGGO%7^)c#aYjP5&@Ie=a!F6^ zL!)Sab&u497%4Z$^Qwo->p`zvMVp^H#XE&_%db1FFfDX7U{+26mQCnMDbzhF)ni0> z#^pQ4>;fFBldEF=egpFBc{(Eqo`+cz4O&rNVT(ZgB|=5g^5lN%FBSBHEMLL*i?C2- zAhzHv+9a41oC9gefpBwwOrT|xWKxH00b4&~%3*XtU?@T9Z|gU2-nhB(|L0uab2_+# zybLf{;%-Ojz~o4uW9dN5a#M%qo)Dm9-tdJ8(!`7m$|IdEt5reTbnEKWRRN9hS8|HqjxG z=Y3hjZ^vvL9gS+%y16}%eBq6=(wWuTy+8>E1cOvDflZeg&FhQr)!YYXE6f;+H31)z zU2NCXgXMr9&e1@mF6V|FojgL}m1l;*5I}syzPlS~c5AGy7Y06SoYMv0vIObgP7dT7 zj2AAdXX<`QpB+0P{=7BAwwkw8=p>N?@-hO`kXmH#iqA+YhTta##<)slFc&Q^#)yi4 zzxxjY>=yCgiVQXU2NP`<>mW=sgDmrqu7i(6(dmY)fq+XQa{{Z)ynoHc~_t85bhldPzDqB_ez6zHt2 zt)=J!^IcJZ-On^+0n=A=D5Na&=`%2bkS^TUxY4zss0bD7U=Wz@6CRX-kL9dH8p#VJ z6%pO_%51YZ%(};K*%@tSCy35d3Dn~k7yeFYa&p8_lzmW%7ZltLft5D0sySsa`l>E4 zpGQxRm9-kUJ#|&<0!Ttd5peIoJ@8jruojtvjw~#u$%1nmi;LO_UpgHF+|nZl5c7X2 zY+;fm(f<3arF*?%@tEIg_^z||={n-YllN)X(_=@#=K6KG$#R{;zH8wWj{WV4Qov8<`zUf8k|WTJ%dY?4%dIEV=0>5!|fCd&p=p%Bh+*nex|| ziFGEA*6Ja~c!NV3&`6Jvttj|kfxf8&{DL)f{u&j7rVJLaynrOBi=o)5}es;`Boov23ub7xiV2JQ<3FMG3su*>bA&Z~J~t-k{?$K}vKucr^a zKoLY>dBZQXU?S;8kC`!Y>F*!?B^D|?Pu)jMW_MhMQZy}Pq(UEH+OJ5!p~tL57A)!? zD&`L@z8Lr+W~>varDo>}ILCEqY#ZW!B%gl@2#`dsv?nBNSv=>p`2?PrMU6hg zRg1oQwV7()cAG3t_qg~#^5pr{fOSguw1!SX>u)+4-G2YdFxjSdAxJfFJvxZX^*uTd z^J3j&$^_)+gMxGM{%0A{3_1 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 kWCD#p(tCGfWS>lS9d$v-?VBy+C Date: Wed, 5 Apr 2017 16:21:39 +0800 Subject: [PATCH 061/203] =?UTF-8?q?Signed-off-by:=20JVM=E4=BD=9C=E4=B8=9A?= =?UTF-8?q?=E6=8F=90=E4=BA=A4=20<996108220@qq.com>?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jvm/loader/ClassFileLoader.java | 70 +++++++++ .../jvm/test/ClassFileloaderTest.java | 93 ++++++++++++ .../com/coderising/jvm/test/EmployeeV1.java | 28 ++++ .../coding/basic/linklist/LRUPageFrame.java | 139 ++++++++++++++++++ .../basic/linklist/LRUPageFrameTest.java | 31 ++++ 5 files changed, 361 insertions(+) create mode 100644 group11/996108220/src/com/coderising/jvm/loader/ClassFileLoader.java create mode 100644 group11/996108220/src/com/coderising/jvm/test/ClassFileloaderTest.java create mode 100644 group11/996108220/src/com/coderising/jvm/test/EmployeeV1.java create mode 100644 group11/996108220/src/com/coding/basic/linklist/LRUPageFrame.java create mode 100644 group11/996108220/src/com/coding/basic/linklist/LRUPageFrameTest.java diff --git a/group11/996108220/src/com/coderising/jvm/loader/ClassFileLoader.java b/group11/996108220/src/com/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..7bde3f4288 --- /dev/null +++ b/group11/996108220/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,70 @@ +package com.coderising.jvm.loader; + + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + + + +public class ClassFileLoader { + + private List clzPaths = new ArrayList(); + + public byte[] readBinaryCode(String className) { + StringBuffer fileName=new StringBuffer(clzPaths.get(0)); + String nameString[]=className.split("\\."); + fileName.append("\\"); + fileName.append(nameString[nameString.length-1]); + fileName.append(".class"); + ArrayList list=new ArrayList(); + try { + InputStream in=new FileInputStream(fileName.toString()); + int length=-1; + byte[] buffer=new byte[1024]; + while ((length=in.read(buffer))!=-1) { + int size=list.size(); + for (int i = size; i < size+length; i++) { + list.add(buffer[i-size]); + } + } + + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + byte[] byteCodes=new byte[list.size()]; + for (int i = 0; i < byteCodes.length; i++) { + byteCodes[i]=list.get(i); + } + + return byteCodes; + } + + + public void addClassPath(String path) { + clzPaths.add(path); + + } + + + + public String getClassPath(){ + String string=""; + for (int i = 0; i < clzPaths.size(); i++) { + string=i==0?string+clzPaths.get(i):string+";"+clzPaths.get(i); + } + return string; + } + + + + + +} diff --git a/group11/996108220/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group11/996108220/src/com/coderising/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..8fdc5db819 --- /dev/null +++ b/group11/996108220/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,93 @@ +package com.coderising.jvm.test; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.coderising.jvm.loader.ClassFileLoader; + + + + + +public class ClassFileloaderTest { + + + static String path1 = "F:\\mycoding2017\\group11\\996108220\\bin\\com\\coderising\\jvm\\test"; + + static String path2 = "C:\\temp"; + + + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testClassPath(){ + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + loader.addClassPath(path2); + + String clzPath = loader.getClassPath(); + + Assert.assertEquals(path1+";"+path2,clzPath); + + } + + @Test + public void testClassFileLength() { + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + + String className = "com.coderising.jvm.test.EmployeeV1"; + + byte[] byteCodes = loader.readBinaryCode(className); + + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + Assert.assertEquals(1056, byteCodes.length); + + } + + + @Test + public void testMagicNumber(){ + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "com.coderising.jvm.test.EmployeeV1"; + byte[] byteCodes = loader.readBinaryCode(className); + byte[] codes = new byte[]{byteCodes[0],byteCodes[1],byteCodes[2],byteCodes[3]}; + + + String acctualValue = this.byteToHexString(codes); + + Assert.assertEquals("cafebabe", acctualValue); + } + + + + + + + private String byteToHexString(byte[] codes ){ + StringBuffer buffer = new StringBuffer(); + for(int i=0;i Date: Thu, 6 Apr 2017 15:39:13 +0800 Subject: [PATCH 062/203] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../zavier/week04/coderising/jvm/loader/ClassFileLoader.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/group01/765324639/src/zavier/week04/coderising/jvm/loader/ClassFileLoader.java b/group01/765324639/src/zavier/week04/coderising/jvm/loader/ClassFileLoader.java index 92a3fcfe02..24cd184053 100644 --- a/group01/765324639/src/zavier/week04/coderising/jvm/loader/ClassFileLoader.java +++ b/group01/765324639/src/zavier/week04/coderising/jvm/loader/ClassFileLoader.java @@ -54,10 +54,13 @@ private byte[] readFileToByteArray(File classFile) { } private String convertClassNameToFilePath(String fillClassName) { - return fillClassName.replace(".", "\\") + ".class"; + return fillClassName.replace(".", File.separator) + ".class"; } public void addClassPath(String path) { + if (clzPaths.contains(path)) { + return; + } clzPaths.add(path); } From 53b7a15c2ed95d417e1590791f12debc5dbc4ae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=A0=E8=AF=B4=E4=B8=AD=E7=9A=84=E5=B0=8F=E9=BB=91?= Date: Thu, 6 Apr 2017 15:55:58 +0800 Subject: [PATCH 063/203] Create stack --- group27/383117348/src/com/coding/basic/stack | 1 + 1 file changed, 1 insertion(+) create mode 100644 group27/383117348/src/com/coding/basic/stack diff --git a/group27/383117348/src/com/coding/basic/stack b/group27/383117348/src/com/coding/basic/stack new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/group27/383117348/src/com/coding/basic/stack @@ -0,0 +1 @@ + From 60055e76536bb2c2c16e2bd0535af5392cfddaf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BC=A0=E8=AF=B4=E4=B8=AD=E7=9A=84=E5=B0=8F=E9=BB=91?= Date: Thu, 6 Apr 2017 15:56:17 +0800 Subject: [PATCH 064/203] Delete stack --- group27/383117348/src/com/coding/basic/stack | 1 - 1 file changed, 1 deletion(-) delete mode 100644 group27/383117348/src/com/coding/basic/stack diff --git a/group27/383117348/src/com/coding/basic/stack b/group27/383117348/src/com/coding/basic/stack deleted file mode 100644 index 8b13789179..0000000000 --- a/group27/383117348/src/com/coding/basic/stack +++ /dev/null @@ -1 +0,0 @@ - From 5ca816918c0e98cb5c5c2500e21bf50303d1060a Mon Sep 17 00:00:00 2001 From: zheng <765324639@qq.com> Date: Thu, 6 Apr 2017 18:27:25 +0800 Subject: [PATCH 065/203] =?UTF-8?q?=E8=B0=83=E6=95=B4=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E7=BB=93=E6=9E=84=EF=BC=8C=E8=BD=AC=E4=B8=BAmaven=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/datastructure}/BinaryTreeNode.java | 2 +- .../java/datastructure}/Iterator.java | 2 +- .../java/datastructure}/List.java | 2 +- .../java/datastructure}/Queue.java | 4 ++- .../java/datastructure/array}/ArrayList.java | 5 ++- .../java/datastructure}/array/ArrayUtil.java | 5 ++- .../linkedlist}/LRUPageFrame.java | 2 +- .../datastructure/linkedlist}/LinkedList.java | 5 ++- .../java/datastructure/stack}/Stack.java | 4 ++- .../java}/download/DownloadThread.java | 7 ++-- .../java}/download/FileDownloader.java | 33 +++++++++++++------ .../java}/download/api/Connection.java | 2 +- .../download/api/ConnectionException.java | 2 +- .../java}/download/api/ConnectionManager.java | 2 +- .../java}/download/api/DownloadListener.java | 2 +- .../java}/download/impl/ConnectionImpl.java | 6 ++-- .../download/impl/ConnectionManagerImpl.java | 14 ++++++++ .../java}/litestruts/LoginAction.java | 2 +- .../java}/litestruts/Struts.java | 2 +- .../java}/litestruts/View.java | 2 +- .../java/minijvm}/loader/ClassFileLoader.java | 2 +- .../java/minijvm/loader}/EmployeeV1.java | 2 +- .../src/main/java/minijvm/loader/MyTest.java | 10 ++++++ .../datastructure}/BinaryTreeNodeTest.java | 4 +-- .../java/datastructure}/QueueTest.java | 4 +-- .../datastructure/array}/ArrayListTest.java | 5 ++- .../datastructure}/array/ArrayUtilTest.java | 2 +- .../linkedlist}/LRUPageFrameTest.java | 3 +- .../linkedlist}/LinkedListTest.java | 4 +-- .../java/datastructure/stack}/StackTest.java | 4 +-- .../java}/download/FileDownloaderTest.java | 13 ++++---- .../java}/litestruts/StrutsTest.java | 2 +- .../minijvm/loader}/ClassFileloaderTest.java | 8 ++--- .../src/zavier/week01/test/AllTests.java | 12 ------- .../week02/coderising/litestruts/struts.xml | 11 ------- .../download/impl/ConnectionManagerImpl.java | 14 -------- 36 files changed, 100 insertions(+), 105 deletions(-) rename group01/765324639/src/{zavier/week01/basic => main/java/datastructure}/BinaryTreeNode.java (93%) rename group01/765324639/src/{zavier/week01/basic => main/java/datastructure}/Iterator.java (70%) rename group01/765324639/src/{zavier/week01/basic => main/java/datastructure}/List.java (82%) rename group01/765324639/src/{zavier/week01/basic => main/java/datastructure}/Queue.java (81%) rename group01/765324639/src/{zavier/week01/basic => main/java/datastructure/array}/ArrayList.java (91%) rename group01/765324639/src/{zavier/week02/coderising => main/java/datastructure}/array/ArrayUtil.java (95%) rename group01/765324639/src/{zavier/week04/coderising/linklist => main/java/datastructure/linkedlist}/LRUPageFrame.java (94%) rename group01/765324639/src/{zavier/week01/basic => main/java/datastructure/linkedlist}/LinkedList.java (95%) rename group01/765324639/src/{zavier/week01/basic => main/java/datastructure/stack}/Stack.java (87%) rename group01/765324639/src/{zavier/week03/coderising => main/java}/download/DownloadThread.java (84%) rename group01/765324639/src/{zavier/week03/coderising => main/java}/download/FileDownloader.java (72%) rename group01/765324639/src/{zavier/week03/coderising => main/java}/download/api/Connection.java (87%) rename group01/765324639/src/{zavier/week03/coderising => main/java}/download/api/ConnectionException.java (52%) rename group01/765324639/src/{zavier/week03/coderising => main/java}/download/api/ConnectionManager.java (78%) rename group01/765324639/src/{zavier/week03/coderising => main/java}/download/api/DownloadListener.java (58%) rename group01/765324639/src/{zavier/week03/coderising => main/java}/download/impl/ConnectionImpl.java (88%) create mode 100644 group01/765324639/src/main/java/download/impl/ConnectionManagerImpl.java rename group01/765324639/src/{zavier/week02/coderising => main/java}/litestruts/LoginAction.java (90%) rename group01/765324639/src/{zavier/week02/coderising => main/java}/litestruts/Struts.java (96%) rename group01/765324639/src/{zavier/week02/coderising => main/java}/litestruts/View.java (85%) rename group01/765324639/src/{zavier/week04/coderising/jvm => main/java/minijvm}/loader/ClassFileLoader.java (94%) rename group01/765324639/src/{zavier/week04/coderising/jvm/test => main/java/minijvm/loader}/EmployeeV1.java (87%) create mode 100644 group01/765324639/src/main/java/minijvm/loader/MyTest.java rename group01/765324639/src/{zavier/week01/test => test/java/datastructure}/BinaryTreeNodeTest.java (90%) rename group01/765324639/src/{zavier/week01/test => test/java/datastructure}/QueueTest.java (89%) rename group01/765324639/src/{zavier/week01/test => test/java/datastructure/array}/ArrayListTest.java (91%) rename group01/765324639/src/{zavier/week02/coderising => test/java/datastructure}/array/ArrayUtilTest.java (99%) rename group01/765324639/src/{zavier/week04/coderising/linklist => test/java/datastructure/linkedlist}/LRUPageFrameTest.java (91%) rename group01/765324639/src/{zavier/week01/test => test/java/datastructure/linkedlist}/LinkedListTest.java (95%) rename group01/765324639/src/{zavier/week01/test => test/java/datastructure/stack}/StackTest.java (90%) rename group01/765324639/src/{zavier/week03/coderising => test/java}/download/FileDownloaderTest.java (77%) rename group01/765324639/src/{zavier/week02/coderising => test/java}/litestruts/StrutsTest.java (92%) rename group01/765324639/src/{zavier/week04/coderising/jvm/test => test/java/minijvm/loader}/ClassFileloaderTest.java (87%) delete mode 100644 group01/765324639/src/zavier/week01/test/AllTests.java delete mode 100644 group01/765324639/src/zavier/week02/coderising/litestruts/struts.xml delete mode 100644 group01/765324639/src/zavier/week03/coderising/download/impl/ConnectionManagerImpl.java diff --git a/group01/765324639/src/zavier/week01/basic/BinaryTreeNode.java b/group01/765324639/src/main/java/datastructure/BinaryTreeNode.java similarity index 93% rename from group01/765324639/src/zavier/week01/basic/BinaryTreeNode.java rename to group01/765324639/src/main/java/datastructure/BinaryTreeNode.java index 6ef26e8f9a..20d0734f11 100644 --- a/group01/765324639/src/zavier/week01/basic/BinaryTreeNode.java +++ b/group01/765324639/src/main/java/datastructure/BinaryTreeNode.java @@ -1,4 +1,4 @@ -package zavier.week01.basic; +package datastructure; public class BinaryTreeNode { diff --git a/group01/765324639/src/zavier/week01/basic/Iterator.java b/group01/765324639/src/main/java/datastructure/Iterator.java similarity index 70% rename from group01/765324639/src/zavier/week01/basic/Iterator.java rename to group01/765324639/src/main/java/datastructure/Iterator.java index 664983e0fd..ae54040424 100644 --- a/group01/765324639/src/zavier/week01/basic/Iterator.java +++ b/group01/765324639/src/main/java/datastructure/Iterator.java @@ -1,4 +1,4 @@ -package zavier.week01.basic; +package datastructure; public interface Iterator { public boolean hasNext(); diff --git a/group01/765324639/src/zavier/week01/basic/List.java b/group01/765324639/src/main/java/datastructure/List.java similarity index 82% rename from group01/765324639/src/zavier/week01/basic/List.java rename to group01/765324639/src/main/java/datastructure/List.java index 4f2d49bd73..507cca34a8 100644 --- a/group01/765324639/src/zavier/week01/basic/List.java +++ b/group01/765324639/src/main/java/datastructure/List.java @@ -1,4 +1,4 @@ -package zavier.week01.basic; +package datastructure; public interface List { public void add(Object o); diff --git a/group01/765324639/src/zavier/week01/basic/Queue.java b/group01/765324639/src/main/java/datastructure/Queue.java similarity index 81% rename from group01/765324639/src/zavier/week01/basic/Queue.java rename to group01/765324639/src/main/java/datastructure/Queue.java index 5a212d46c1..d4cfec525e 100644 --- a/group01/765324639/src/zavier/week01/basic/Queue.java +++ b/group01/765324639/src/main/java/datastructure/Queue.java @@ -1,4 +1,6 @@ -package zavier.week01.basic; +package datastructure; + +import datastructure.linkedlist.LinkedList; public class Queue { diff --git a/group01/765324639/src/zavier/week01/basic/ArrayList.java b/group01/765324639/src/main/java/datastructure/array/ArrayList.java similarity index 91% rename from group01/765324639/src/zavier/week01/basic/ArrayList.java rename to group01/765324639/src/main/java/datastructure/array/ArrayList.java index 38e5739fb8..a4b4182226 100644 --- a/group01/765324639/src/zavier/week01/basic/ArrayList.java +++ b/group01/765324639/src/main/java/datastructure/array/ArrayList.java @@ -1,7 +1,10 @@ -package zavier.week01.basic; +package datastructure.array; import java.util.Arrays; +import datastructure.Iterator; +import datastructure.List; + public class ArrayList implements List { private int size = 0; diff --git a/group01/765324639/src/zavier/week02/coderising/array/ArrayUtil.java b/group01/765324639/src/main/java/datastructure/array/ArrayUtil.java similarity index 95% rename from group01/765324639/src/zavier/week02/coderising/array/ArrayUtil.java rename to group01/765324639/src/main/java/datastructure/array/ArrayUtil.java index 96bff301c7..74040ccbe0 100644 --- a/group01/765324639/src/zavier/week02/coderising/array/ArrayUtil.java +++ b/group01/765324639/src/main/java/datastructure/array/ArrayUtil.java @@ -1,7 +1,6 @@ -package zavier.week02.coderising.array; +package datastructure.array; -import zavier.week01.basic.ArrayList; -import zavier.week01.basic.List; +import datastructure.List; public class ArrayUtil { diff --git a/group01/765324639/src/zavier/week04/coderising/linklist/LRUPageFrame.java b/group01/765324639/src/main/java/datastructure/linkedlist/LRUPageFrame.java similarity index 94% rename from group01/765324639/src/zavier/week04/coderising/linklist/LRUPageFrame.java rename to group01/765324639/src/main/java/datastructure/linkedlist/LRUPageFrame.java index eb82d94d5e..cc4771562d 100644 --- a/group01/765324639/src/zavier/week04/coderising/linklist/LRUPageFrame.java +++ b/group01/765324639/src/main/java/datastructure/linkedlist/LRUPageFrame.java @@ -1,4 +1,4 @@ -package zavier.week04.coderising.linklist; +package datastructure.linkedlist; /** * 用双向链表实现LRU算法 diff --git a/group01/765324639/src/zavier/week01/basic/LinkedList.java b/group01/765324639/src/main/java/datastructure/linkedlist/LinkedList.java similarity index 95% rename from group01/765324639/src/zavier/week01/basic/LinkedList.java rename to group01/765324639/src/main/java/datastructure/linkedlist/LinkedList.java index 6e15220b34..acdb3320d9 100644 --- a/group01/765324639/src/zavier/week01/basic/LinkedList.java +++ b/group01/765324639/src/main/java/datastructure/linkedlist/LinkedList.java @@ -1,7 +1,10 @@ -package zavier.week01.basic; +package datastructure.linkedlist; import java.util.NoSuchElementException; +import datastructure.Iterator; +import datastructure.List; + public class LinkedList implements List { private Node head; diff --git a/group01/765324639/src/zavier/week01/basic/Stack.java b/group01/765324639/src/main/java/datastructure/stack/Stack.java similarity index 87% rename from group01/765324639/src/zavier/week01/basic/Stack.java rename to group01/765324639/src/main/java/datastructure/stack/Stack.java index ebe4afb19f..a5ac46c3f5 100644 --- a/group01/765324639/src/zavier/week01/basic/Stack.java +++ b/group01/765324639/src/main/java/datastructure/stack/Stack.java @@ -1,7 +1,9 @@ -package zavier.week01.basic; +package datastructure.stack; import java.util.EmptyStackException; +import datastructure.array.ArrayList; + public class Stack { private ArrayList elementData = new ArrayList(); diff --git a/group01/765324639/src/zavier/week03/coderising/download/DownloadThread.java b/group01/765324639/src/main/java/download/DownloadThread.java similarity index 84% rename from group01/765324639/src/zavier/week03/coderising/download/DownloadThread.java rename to group01/765324639/src/main/java/download/DownloadThread.java index f94c97b8b1..cba16f40f6 100644 --- a/group01/765324639/src/zavier/week03/coderising/download/DownloadThread.java +++ b/group01/765324639/src/main/java/download/DownloadThread.java @@ -1,9 +1,9 @@ -package zavier.week03.coderising.download; +package download; import java.io.IOException; import java.io.RandomAccessFile; -import zavier.week03.coderising.download.api.Connection; +import download.api.Connection; public class DownloadThread extends Thread { @@ -22,6 +22,7 @@ public DownloadThread(Connection conn, int startPos, int endPos) { @Override public void run() { + System.out.println("开始下载:" + startPos + "~" + endPos); byte[] data = new byte[endPos - startPos]; try { data = conn.read(startPos, endPos); @@ -30,7 +31,7 @@ public void run() { } writeToFile(data); } - + private void writeToFile(byte[] data) { RandomAccessFile file; try { diff --git a/group01/765324639/src/zavier/week03/coderising/download/FileDownloader.java b/group01/765324639/src/main/java/download/FileDownloader.java similarity index 72% rename from group01/765324639/src/zavier/week03/coderising/download/FileDownloader.java rename to group01/765324639/src/main/java/download/FileDownloader.java index ff2db12f50..91f972db71 100644 --- a/group01/765324639/src/zavier/week03/coderising/download/FileDownloader.java +++ b/group01/765324639/src/main/java/download/FileDownloader.java @@ -1,9 +1,12 @@ -package zavier.week03.coderising.download; +package download; -import zavier.week03.coderising.download.api.Connection; -import zavier.week03.coderising.download.api.ConnectionException; -import zavier.week03.coderising.download.api.ConnectionManager; -import zavier.week03.coderising.download.api.DownloadListener; +import java.io.IOException; +import java.io.RandomAccessFile; + +import download.api.Connection; +import download.api.ConnectionException; +import download.api.ConnectionManager; +import download.api.DownloadListener; public class FileDownloader { @@ -40,14 +43,15 @@ public void execute() { conn = cm.open(this.url); int length = conn.getContentLength(); + createPlaceHolderFile("download20170311.jpg", length); - DownloadThread downloadThread1 = new DownloadThread(conn, 0, length / 3); + DownloadThread downloadThread1 = new DownloadThread(cm.open(this.url), 0, length / 3); downloadThread1.start(); DownloadThread downloadThread2 = - new DownloadThread(conn, length / 3 + 1, length / 3 * 2); + new DownloadThread(cm.open(this.url), length / 3 + 1, length / 3 * 2); downloadThread2.start(); DownloadThread downloadThread3 = - new DownloadThread(conn, length / 3 * 2 + 1, length - 1); + new DownloadThread(cm.open(this.url), length / 3 * 2 + 1, length - 1); downloadThread3.start(); try { downloadThread1.join(); @@ -60,22 +64,31 @@ public void execute() { } catch (ConnectionException e) { e.printStackTrace(); + } catch (IOException e1) { + e1.printStackTrace(); } finally { if (conn != null) { conn.close(); } } + } + + private void createPlaceHolderFile(String fileName, int contentLen) throws IOException { + + RandomAccessFile file = new RandomAccessFile(fileName, "rw"); + for (int i = 0; i < contentLen; i++) { + file.write(0); + } + file.close(); } public void setListener(DownloadListener listener) { this.listener = listener; } - - public void setConnectionManager(ConnectionManager ucm) { this.cm = ucm; } diff --git a/group01/765324639/src/zavier/week03/coderising/download/api/Connection.java b/group01/765324639/src/main/java/download/api/Connection.java similarity index 87% rename from group01/765324639/src/zavier/week03/coderising/download/api/Connection.java rename to group01/765324639/src/main/java/download/api/Connection.java index 4763202fab..c0c2a33285 100644 --- a/group01/765324639/src/zavier/week03/coderising/download/api/Connection.java +++ b/group01/765324639/src/main/java/download/api/Connection.java @@ -1,4 +1,4 @@ -package zavier.week03.coderising.download.api; +package download.api; import java.io.IOException; diff --git a/group01/765324639/src/zavier/week03/coderising/download/api/ConnectionException.java b/group01/765324639/src/main/java/download/api/ConnectionException.java similarity index 52% rename from group01/765324639/src/zavier/week03/coderising/download/api/ConnectionException.java rename to group01/765324639/src/main/java/download/api/ConnectionException.java index 5df32804de..9daefa720f 100644 --- a/group01/765324639/src/zavier/week03/coderising/download/api/ConnectionException.java +++ b/group01/765324639/src/main/java/download/api/ConnectionException.java @@ -1,4 +1,4 @@ -package zavier.week03.coderising.download.api; +package download.api; public class ConnectionException extends Exception { diff --git a/group01/765324639/src/zavier/week03/coderising/download/api/ConnectionManager.java b/group01/765324639/src/main/java/download/api/ConnectionManager.java similarity index 78% rename from group01/765324639/src/zavier/week03/coderising/download/api/ConnectionManager.java rename to group01/765324639/src/main/java/download/api/ConnectionManager.java index 81f5f34f72..c74bf0d41f 100644 --- a/group01/765324639/src/zavier/week03/coderising/download/api/ConnectionManager.java +++ b/group01/765324639/src/main/java/download/api/ConnectionManager.java @@ -1,4 +1,4 @@ -package zavier.week03.coderising.download.api; +package download.api; public interface ConnectionManager { /** diff --git a/group01/765324639/src/zavier/week03/coderising/download/api/DownloadListener.java b/group01/765324639/src/main/java/download/api/DownloadListener.java similarity index 58% rename from group01/765324639/src/zavier/week03/coderising/download/api/DownloadListener.java rename to group01/765324639/src/main/java/download/api/DownloadListener.java index f72ecd263d..f3730b32a1 100644 --- a/group01/765324639/src/zavier/week03/coderising/download/api/DownloadListener.java +++ b/group01/765324639/src/main/java/download/api/DownloadListener.java @@ -1,4 +1,4 @@ -package zavier.week03.coderising.download.api; +package download.api; public interface DownloadListener { public void notifyFinished(); diff --git a/group01/765324639/src/zavier/week03/coderising/download/impl/ConnectionImpl.java b/group01/765324639/src/main/java/download/impl/ConnectionImpl.java similarity index 88% rename from group01/765324639/src/zavier/week03/coderising/download/impl/ConnectionImpl.java rename to group01/765324639/src/main/java/download/impl/ConnectionImpl.java index b297beef54..634fd6f1df 100644 --- a/group01/765324639/src/zavier/week03/coderising/download/impl/ConnectionImpl.java +++ b/group01/765324639/src/main/java/download/impl/ConnectionImpl.java @@ -1,4 +1,4 @@ -package zavier.week03.coderising.download.impl; +package download.impl; import java.io.IOException; import java.io.InputStream; @@ -6,7 +6,7 @@ import java.net.MalformedURLException; import java.net.URL; -import zavier.week03.coderising.download.api.Connection; +import download.api.Connection; public class ConnectionImpl implements Connection { @@ -57,8 +57,6 @@ public int getContentLength() { @Override public void close() { - conn.disconnect(); - conn = null; } } diff --git a/group01/765324639/src/main/java/download/impl/ConnectionManagerImpl.java b/group01/765324639/src/main/java/download/impl/ConnectionManagerImpl.java new file mode 100644 index 0000000000..9663736f21 --- /dev/null +++ b/group01/765324639/src/main/java/download/impl/ConnectionManagerImpl.java @@ -0,0 +1,14 @@ +package download.impl; + +import download.api.Connection; +import download.api.ConnectionException; +import download.api.ConnectionManager; + +public class ConnectionManagerImpl implements ConnectionManager { + + @Override + public Connection open(String url) throws ConnectionException { + return new ConnectionImpl(url); + } + +} diff --git a/group01/765324639/src/zavier/week02/coderising/litestruts/LoginAction.java b/group01/765324639/src/main/java/litestruts/LoginAction.java similarity index 90% rename from group01/765324639/src/zavier/week02/coderising/litestruts/LoginAction.java rename to group01/765324639/src/main/java/litestruts/LoginAction.java index 617b5f115b..87ae0c4fcf 100644 --- a/group01/765324639/src/zavier/week02/coderising/litestruts/LoginAction.java +++ b/group01/765324639/src/main/java/litestruts/LoginAction.java @@ -1,4 +1,4 @@ -package zavier.week02.coderising.litestruts; +package litestruts; /** * 这是一个用来展示登录的业务类, 其中的用户名和密码都是硬编码的。 diff --git a/group01/765324639/src/zavier/week02/coderising/litestruts/Struts.java b/group01/765324639/src/main/java/litestruts/Struts.java similarity index 96% rename from group01/765324639/src/zavier/week02/coderising/litestruts/Struts.java rename to group01/765324639/src/main/java/litestruts/Struts.java index d30beaafb3..5230e424e2 100644 --- a/group01/765324639/src/zavier/week02/coderising/litestruts/Struts.java +++ b/group01/765324639/src/main/java/litestruts/Struts.java @@ -1,4 +1,4 @@ -package zavier.week02.coderising.litestruts; +package litestruts; import java.io.InputStream; import java.lang.reflect.Method; diff --git a/group01/765324639/src/zavier/week02/coderising/litestruts/View.java b/group01/765324639/src/main/java/litestruts/View.java similarity index 85% rename from group01/765324639/src/zavier/week02/coderising/litestruts/View.java rename to group01/765324639/src/main/java/litestruts/View.java index f164c4bfc5..4a553757d0 100644 --- a/group01/765324639/src/zavier/week02/coderising/litestruts/View.java +++ b/group01/765324639/src/main/java/litestruts/View.java @@ -1,4 +1,4 @@ -package zavier.week02.coderising.litestruts; +package litestruts; import java.util.Map; diff --git a/group01/765324639/src/zavier/week04/coderising/jvm/loader/ClassFileLoader.java b/group01/765324639/src/main/java/minijvm/loader/ClassFileLoader.java similarity index 94% rename from group01/765324639/src/zavier/week04/coderising/jvm/loader/ClassFileLoader.java rename to group01/765324639/src/main/java/minijvm/loader/ClassFileLoader.java index 24cd184053..d814a7f5f9 100644 --- a/group01/765324639/src/zavier/week04/coderising/jvm/loader/ClassFileLoader.java +++ b/group01/765324639/src/main/java/minijvm/loader/ClassFileLoader.java @@ -1,4 +1,4 @@ -package zavier.week04.coderising.jvm.loader; +package minijvm.loader; import java.io.ByteArrayOutputStream; import java.io.File; diff --git a/group01/765324639/src/zavier/week04/coderising/jvm/test/EmployeeV1.java b/group01/765324639/src/main/java/minijvm/loader/EmployeeV1.java similarity index 87% rename from group01/765324639/src/zavier/week04/coderising/jvm/test/EmployeeV1.java rename to group01/765324639/src/main/java/minijvm/loader/EmployeeV1.java index 57c7517767..2c07ee7fb7 100644 --- a/group01/765324639/src/zavier/week04/coderising/jvm/test/EmployeeV1.java +++ b/group01/765324639/src/main/java/minijvm/loader/EmployeeV1.java @@ -1,4 +1,4 @@ -package zavier.week04.coderising.jvm.test; +package minijvm.loader; public class EmployeeV1 { diff --git a/group01/765324639/src/main/java/minijvm/loader/MyTest.java b/group01/765324639/src/main/java/minijvm/loader/MyTest.java new file mode 100644 index 0000000000..1aa536bdf1 --- /dev/null +++ b/group01/765324639/src/main/java/minijvm/loader/MyTest.java @@ -0,0 +1,10 @@ +package minijvm.loader; + +import java.io.File; + +public class MyTest { + + public static void main(String[] args) { + System.out.println(new File(".").getAbsolutePath()); + } +} diff --git a/group01/765324639/src/zavier/week01/test/BinaryTreeNodeTest.java b/group01/765324639/src/test/java/datastructure/BinaryTreeNodeTest.java similarity index 90% rename from group01/765324639/src/zavier/week01/test/BinaryTreeNodeTest.java rename to group01/765324639/src/test/java/datastructure/BinaryTreeNodeTest.java index 30a096a350..37e8076d70 100644 --- a/group01/765324639/src/zavier/week01/test/BinaryTreeNodeTest.java +++ b/group01/765324639/src/test/java/datastructure/BinaryTreeNodeTest.java @@ -1,10 +1,8 @@ -package zavier.week01.test; +package datastructure; import org.junit.Assert; import org.junit.Test; -import zavier.week01.basic.BinaryTreeNode; - public class BinaryTreeNodeTest { private BinaryTreeNode root = new BinaryTreeNode(5); diff --git a/group01/765324639/src/zavier/week01/test/QueueTest.java b/group01/765324639/src/test/java/datastructure/QueueTest.java similarity index 89% rename from group01/765324639/src/zavier/week01/test/QueueTest.java rename to group01/765324639/src/test/java/datastructure/QueueTest.java index 99d6466c8a..b24f75ed53 100644 --- a/group01/765324639/src/zavier/week01/test/QueueTest.java +++ b/group01/765324639/src/test/java/datastructure/QueueTest.java @@ -1,11 +1,9 @@ -package zavier.week01.test; +package datastructure; import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import zavier.week01.basic.Queue; - public class QueueTest { private Queue queue = new Queue(); diff --git a/group01/765324639/src/zavier/week01/test/ArrayListTest.java b/group01/765324639/src/test/java/datastructure/array/ArrayListTest.java similarity index 91% rename from group01/765324639/src/zavier/week01/test/ArrayListTest.java rename to group01/765324639/src/test/java/datastructure/array/ArrayListTest.java index 6a475500df..145868352b 100644 --- a/group01/765324639/src/zavier/week01/test/ArrayListTest.java +++ b/group01/765324639/src/test/java/datastructure/array/ArrayListTest.java @@ -1,11 +1,10 @@ -package zavier.week01.test; +package datastructure.array; import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import zavier.week01.basic.ArrayList; -import zavier.week01.basic.Iterator; +import datastructure.Iterator; public class ArrayListTest { diff --git a/group01/765324639/src/zavier/week02/coderising/array/ArrayUtilTest.java b/group01/765324639/src/test/java/datastructure/array/ArrayUtilTest.java similarity index 99% rename from group01/765324639/src/zavier/week02/coderising/array/ArrayUtilTest.java rename to group01/765324639/src/test/java/datastructure/array/ArrayUtilTest.java index d0e6fa11d8..9ac7196cee 100644 --- a/group01/765324639/src/zavier/week02/coderising/array/ArrayUtilTest.java +++ b/group01/765324639/src/test/java/datastructure/array/ArrayUtilTest.java @@ -1,4 +1,4 @@ -package zavier.week02.coderising.array; +package datastructure.array; import org.junit.Assert; import org.junit.Before; diff --git a/group01/765324639/src/zavier/week04/coderising/linklist/LRUPageFrameTest.java b/group01/765324639/src/test/java/datastructure/linkedlist/LRUPageFrameTest.java similarity index 91% rename from group01/765324639/src/zavier/week04/coderising/linklist/LRUPageFrameTest.java rename to group01/765324639/src/test/java/datastructure/linkedlist/LRUPageFrameTest.java index 9b69297e21..b08c317c15 100644 --- a/group01/765324639/src/zavier/week04/coderising/linklist/LRUPageFrameTest.java +++ b/group01/765324639/src/test/java/datastructure/linkedlist/LRUPageFrameTest.java @@ -1,9 +1,8 @@ -package zavier.week04.coderising.linklist; +package datastructure.linkedlist; import org.junit.Assert; import org.junit.Test; - public class LRUPageFrameTest { @Test diff --git a/group01/765324639/src/zavier/week01/test/LinkedListTest.java b/group01/765324639/src/test/java/datastructure/linkedlist/LinkedListTest.java similarity index 95% rename from group01/765324639/src/zavier/week01/test/LinkedListTest.java rename to group01/765324639/src/test/java/datastructure/linkedlist/LinkedListTest.java index ea1f077704..5bd6125755 100644 --- a/group01/765324639/src/zavier/week01/test/LinkedListTest.java +++ b/group01/765324639/src/test/java/datastructure/linkedlist/LinkedListTest.java @@ -1,11 +1,9 @@ -package zavier.week01.test; +package datastructure.linkedlist; import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import zavier.week01.basic.LinkedList; - public class LinkedListTest { diff --git a/group01/765324639/src/zavier/week01/test/StackTest.java b/group01/765324639/src/test/java/datastructure/stack/StackTest.java similarity index 90% rename from group01/765324639/src/zavier/week01/test/StackTest.java rename to group01/765324639/src/test/java/datastructure/stack/StackTest.java index 8138f97d3d..e5c39574b5 100644 --- a/group01/765324639/src/zavier/week01/test/StackTest.java +++ b/group01/765324639/src/test/java/datastructure/stack/StackTest.java @@ -1,4 +1,4 @@ -package zavier.week01.test; +package datastructure.stack; import java.util.EmptyStackException; @@ -6,8 +6,6 @@ import org.junit.Before; import org.junit.Test; -import zavier.week01.basic.Stack; - public class StackTest { diff --git a/group01/765324639/src/zavier/week03/coderising/download/FileDownloaderTest.java b/group01/765324639/src/test/java/download/FileDownloaderTest.java similarity index 77% rename from group01/765324639/src/zavier/week03/coderising/download/FileDownloaderTest.java rename to group01/765324639/src/test/java/download/FileDownloaderTest.java index bf67e8d494..885bf46a7c 100644 --- a/group01/765324639/src/zavier/week03/coderising/download/FileDownloaderTest.java +++ b/group01/765324639/src/test/java/download/FileDownloaderTest.java @@ -1,12 +1,12 @@ -package zavier.week03.coderising.download; +package download; import org.junit.After; import org.junit.Before; import org.junit.Test; -import zavier.week03.coderising.download.api.ConnectionManager; -import zavier.week03.coderising.download.api.DownloadListener; -import zavier.week03.coderising.download.impl.ConnectionManagerImpl; +import download.api.ConnectionManager; +import download.api.DownloadListener; +import download.impl.ConnectionManagerImpl; public class FileDownloaderTest { boolean downloadFinished = false; @@ -20,7 +20,8 @@ public void tearDown() throws Exception {} @Test public void testDownload() { - String url = "http://121.42.185.101/forum/test.jpg"; +// String url = "http://121.42.185.101/forum/test.jpg"; // 此图片较大 + String url = "http://121.42.185.101/forum/weixin.jpg"; // 此图片较小 FileDownloader downloader = new FileDownloader(url); @@ -55,8 +56,6 @@ public void run() { } System.out.println("下载完成!"); - - } } diff --git a/group01/765324639/src/zavier/week02/coderising/litestruts/StrutsTest.java b/group01/765324639/src/test/java/litestruts/StrutsTest.java similarity index 92% rename from group01/765324639/src/zavier/week02/coderising/litestruts/StrutsTest.java rename to group01/765324639/src/test/java/litestruts/StrutsTest.java index ba800c2fdc..45616a42cd 100644 --- a/group01/765324639/src/zavier/week02/coderising/litestruts/StrutsTest.java +++ b/group01/765324639/src/test/java/litestruts/StrutsTest.java @@ -1,4 +1,4 @@ -package zavier.week02.coderising.litestruts; +package litestruts; import java.util.HashMap; import java.util.Map; diff --git a/group01/765324639/src/zavier/week04/coderising/jvm/test/ClassFileloaderTest.java b/group01/765324639/src/test/java/minijvm/loader/ClassFileloaderTest.java similarity index 87% rename from group01/765324639/src/zavier/week04/coderising/jvm/test/ClassFileloaderTest.java rename to group01/765324639/src/test/java/minijvm/loader/ClassFileloaderTest.java index 66855937f4..f0a3f220bd 100644 --- a/group01/765324639/src/zavier/week04/coderising/jvm/test/ClassFileloaderTest.java +++ b/group01/765324639/src/test/java/minijvm/loader/ClassFileloaderTest.java @@ -1,4 +1,4 @@ -package zavier.week04.coderising.jvm.test; +package minijvm.loader; import java.io.File; @@ -7,14 +7,12 @@ import org.junit.Before; import org.junit.Test; -import zavier.week04.coderising.jvm.loader.ClassFileLoader; - public class ClassFileloaderTest { - static String path1 = new File(".", "bin").getAbsolutePath(); + static String path1 = new File(".", "target\\classes").getAbsolutePath(); static String path2 = "C:\\temp"; static String className = EmployeeV1.class.getName(); @@ -47,7 +45,7 @@ public void testClassFileLength() throws ClassNotFoundException { byte[] byteCodes = loader.readBinaryCode(className); // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 - Assert.assertEquals(1076, byteCodes.length); + Assert.assertEquals(1038, byteCodes.length); } diff --git a/group01/765324639/src/zavier/week01/test/AllTests.java b/group01/765324639/src/zavier/week01/test/AllTests.java deleted file mode 100644 index c1755f6803..0000000000 --- a/group01/765324639/src/zavier/week01/test/AllTests.java +++ /dev/null @@ -1,12 +0,0 @@ -package zavier.week01.test; - -import org.junit.runner.RunWith; -import org.junit.runners.Suite; -import org.junit.runners.Suite.SuiteClasses; - -@RunWith(Suite.class) -@SuiteClasses({ArrayListTest.class, LinkedListTest.class, QueueTest.class, StackTest.class, - BinaryTreeNodeTest.class}) -public class AllTests { - -} diff --git a/group01/765324639/src/zavier/week02/coderising/litestruts/struts.xml b/group01/765324639/src/zavier/week02/coderising/litestruts/struts.xml deleted file mode 100644 index ffe9110788..0000000000 --- a/group01/765324639/src/zavier/week02/coderising/litestruts/struts.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - /jsp/homepage.jsp - /jsp/showLogin.jsp - - - /jsp/welcome.jsp - /jsp/error.jsp - - \ No newline at end of file diff --git a/group01/765324639/src/zavier/week03/coderising/download/impl/ConnectionManagerImpl.java b/group01/765324639/src/zavier/week03/coderising/download/impl/ConnectionManagerImpl.java deleted file mode 100644 index d6828e7ae8..0000000000 --- a/group01/765324639/src/zavier/week03/coderising/download/impl/ConnectionManagerImpl.java +++ /dev/null @@ -1,14 +0,0 @@ -package zavier.week03.coderising.download.impl; - -import zavier.week03.coderising.download.api.Connection; -import zavier.week03.coderising.download.api.ConnectionException; -import zavier.week03.coderising.download.api.ConnectionManager; - -public class ConnectionManagerImpl implements ConnectionManager { - - @Override - public Connection open(String url) throws ConnectionException { - return new ConnectionImpl(url); - } - -} From 3b95c1ea52db3a303a1a71fcf16c778884faa73a Mon Sep 17 00:00:00 2001 From: DonaldY <448641125@qq.com> Date: Thu, 6 Apr 2017 19:46:56 +0800 Subject: [PATCH 066/203] StackUtils finished --- .../src/com/donaldy/basic/StackUtil.java | 109 ++++++++++++++++++ .../donaldy/jvm/loader/ClassFileLoader.java | 2 +- .../src/com/donaldy/jvm/test/EmployeeV1.java | 2 - .../src/com/donaldy/test/StackUtilTest.java | 65 +++++++++++ 4 files changed, 175 insertions(+), 3 deletions(-) create mode 100644 group24/448641125/src/com/donaldy/basic/StackUtil.java create mode 100644 group24/448641125/src/com/donaldy/test/StackUtilTest.java diff --git a/group24/448641125/src/com/donaldy/basic/StackUtil.java b/group24/448641125/src/com/donaldy/basic/StackUtil.java new file mode 100644 index 0000000000..a950fa77e4 --- /dev/null +++ b/group24/448641125/src/com/donaldy/basic/StackUtil.java @@ -0,0 +1,109 @@ +package com.donaldy.basic; + +import java.util.*; + +public class StackUtil { + + + /** + * 假设栈中的元素是Integer, 从栈顶到栈底是 : 5,4,3,2,1 调用该方法后, 元素次序变为: 1,2,3,4,5 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + */ + public static void reverse(Stack s) { + Stack stack = new Stack(); + while (!s.isEmpty()) { + Object element = s.pop(); + stack.push(element); + } + + while (!stack.isEmpty()) { + Object element = stack.pop(); + s.push(element); + } + } + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s,Object o) { + //若stack的值为唯一的。 + Stack stack = new Stack(); + while (!s.isEmpty()) { + Object element = s.pop(); + if (o == element) { + break; + } + stack.push(element); + } + + while (!stack.isEmpty()) { + Object element = stack.pop(); + s.push(element); + } + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * @param len + * @return + */ + public static Object[] getTop(Stack s,int len) { + if (len < 0 || len >= s.size()) + throw new IndexOutOfBoundsException("len : " + len); + Object [] arr = new Object[len]; + + for (int i = 0 ; i < len && !s.isEmpty(); ++i) { + arr[i] = s.pop(); + } + return arr; + } + /** + * 字符串s 可能包含这些字符: ( ) [ ] { }, a,b,c... x,yz + * 使用堆栈检查字符串s中的括号是不是成对出现的。 + * 例如s = "([e{d}f])" , 则该字符串中的括号是成对出现, 该方法返回true + * 如果 s = "([b{x]y})", 则该字符串中的括号不是成对出现的, 该方法返回false; + * @param s + * @return + */ + public static boolean isValidPairs(String s){ + char [] arr = s.toCharArray(); + Stack stack = new Stack(); + for (int i = 0; i < s.length(); ++i) { + if (arr[i] == '(' ) + stack.push(')'); + if ( arr[i] == '{' ) + stack.push('}'); + if ( arr[i] == '[') + stack.push(']'); + + if (arr[i] == ')' ) { + if (')' != (char)stack.peek()) + break; + stack.pop(); + } + + if (arr[i] == '}' ) { + if ('}' != (char)stack.peek()) + break; + stack.pop(); + } + + if (arr[i] == ']' ) { + if (']' != (char)stack.peek()) + break; + stack.pop(); + } + + } + + if (stack.isEmpty()) + return true; + + return false; + } + + +} diff --git a/group24/448641125/src/com/donaldy/jvm/loader/ClassFileLoader.java b/group24/448641125/src/com/donaldy/jvm/loader/ClassFileLoader.java index c4a64b26d6..96d55334d1 100644 --- a/group24/448641125/src/com/donaldy/jvm/loader/ClassFileLoader.java +++ b/group24/448641125/src/com/donaldy/jvm/loader/ClassFileLoader.java @@ -20,7 +20,7 @@ public byte[] readBinaryCode(String className) { for (String clzPath : clzPaths) { File file = new File(clzPath + className.replace(".", "\\") + ".class"); - + if (!file.exists()) continue; diff --git a/group24/448641125/src/com/donaldy/jvm/test/EmployeeV1.java b/group24/448641125/src/com/donaldy/jvm/test/EmployeeV1.java index b4b35ce835..41c3d22871 100644 --- a/group24/448641125/src/com/donaldy/jvm/test/EmployeeV1.java +++ b/group24/448641125/src/com/donaldy/jvm/test/EmployeeV1.java @@ -2,7 +2,6 @@ public class EmployeeV1 { - private String name; private int age; @@ -23,6 +22,5 @@ public void sayHello() { public static void main(String[] args){ EmployeeV1 p = new EmployeeV1("Andy",29); p.sayHello(); - } } \ No newline at end of file diff --git a/group24/448641125/src/com/donaldy/test/StackUtilTest.java b/group24/448641125/src/com/donaldy/test/StackUtilTest.java new file mode 100644 index 0000000000..2bfe6101eb --- /dev/null +++ b/group24/448641125/src/com/donaldy/test/StackUtilTest.java @@ -0,0 +1,65 @@ +package com.donaldy.test; + +import com.donaldy.basic.Stack; +import com.donaldy.basic.StackUtil; +import org.junit.Assert; +import org.junit.Test; + +/** + * Created by DonaldY on 2017/4/6. + */ +public class StackUtilTest { + + @Test + public void testReverse() { + Stack stack = new Stack(); + Integer [] intArr = {5, 4, 3, 2, 1}; + for (int i = 4; i >= 0 ; --i) + stack.push(intArr[i]); + StackUtil.reverse(stack); + for (int i = 0 ; i < 5; ++i) { + Assert.assertEquals((int)stack.pop(), (int)intArr[i]); + } + } + + @Test + public void testRemove() { + Stack stack = new Stack(); + Integer [] intArr = {5, 4, 3, 2, 1}; + for (int i = 4; i >= 0 ; --i) + stack.push(intArr[i]); + + StackUtil.remove(stack, 2); + for (int i = 0; i < 5; ++i) { + if (i == 3) + continue; + System.out.println("stack: " + stack.peek() + " i : " + (int) intArr[i]); + Assert.assertEquals((int)stack.pop(), (int)intArr[i]); + } + } + + @Test + public void testGetTop() { + Stack stack = new Stack(); + Integer [] intArr = {5, 4, 3, 2, 1}; + for (int i = 4; i >= 0 ; --i) + stack.push(intArr[i]); + + int len = 3; + Object [] arr = StackUtil.getTop(stack, len); + + for (int i = 0 ; i < arr.length ; ++i) { + Assert.assertEquals((int)arr[i], (int)intArr[i]); + } + } + + @Test + public void testIsValidPairs() { + + String str1 = "([e{d}f])"; + Assert.assertEquals(true, StackUtil.isValidPairs(str1)); + + String str2 = "([b{x]y})"; + Assert.assertEquals(false, StackUtil.isValidPairs(str2)); + } +} From aa80caaa218f80059e779750587ca88cb1d0bbff Mon Sep 17 00:00:00 2001 From: ZhaoHongxin Date: Thu, 6 Apr 2017 22:32:33 +0800 Subject: [PATCH 067/203] load work --- .../com/coderising/jvm/clz/AccessFlag.java | 25 +++++ .../src/com/coderising/jvm/clz/ClassFile.java | 75 +++++++++++++ .../com/coderising/jvm/clz/ClassIndex.java | 19 ++++ .../coderising/jvm/constant/ClassInfo.java | 24 ++++ .../coderising/jvm/constant/ConstantInfo.java | 29 +++++ .../coderising/jvm/constant/ConstantPool.java | 29 +++++ .../coderising/jvm/constant/FieldRefInfo.java | 54 +++++++++ .../jvm/constant/MethodRefInfo.java | 55 +++++++++ .../jvm/constant/NameAndTypeInfo.java | 45 ++++++++ .../jvm/constant/NullConstantInfo.java | 13 +++ .../coderising/jvm/constant/StringInfo.java | 26 +++++ .../com/coderising/jvm/constant/UTF8Info.java | 32 ++++++ .../jvm/loader/ByteCodeIterator.java | 5 + .../jvm/loader/ClassFileLoader.java | 55 +++++++-- .../jvm/loader/ClassFileParser.java | 41 +++++++ .../jvm/test/ClassFileloaderTest.java | 105 +++++++++++++++++- .../src/com/coderising/jvm/util/Util.java | 24 ++++ 17 files changed, 647 insertions(+), 9 deletions(-) create mode 100644 group05/1094051862/mini-jvm/src/com/coderising/jvm/clz/AccessFlag.java create mode 100644 group05/1094051862/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java create mode 100644 group05/1094051862/mini-jvm/src/com/coderising/jvm/clz/ClassIndex.java create mode 100644 group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/ClassInfo.java create mode 100644 group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/ConstantInfo.java create mode 100644 group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/ConstantPool.java create mode 100644 group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/FieldRefInfo.java create mode 100644 group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/MethodRefInfo.java create mode 100644 group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/NameAndTypeInfo.java create mode 100644 group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/NullConstantInfo.java create mode 100644 group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/StringInfo.java create mode 100644 group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/UTF8Info.java create mode 100644 group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java create mode 100644 group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java create mode 100644 group05/1094051862/mini-jvm/src/com/coderising/jvm/util/Util.java diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/clz/AccessFlag.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..cdb8f8859a --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/clz/AccessFlag.java @@ -0,0 +1,25 @@ +package com.coderising.jvm.clz; + +public class AccessFlag { + private int flagValue; + + public AccessFlag(int value) { + this.flagValue = value; + } + + public int getFlagValue() { + return flagValue; + } + + public void setFlagValue(int flag) { + this.flagValue = flag; + } + + public boolean isPublicClass(){ + return (this.flagValue & 0x0001) != 0; + } + public boolean isFinalClass(){ + return (this.flagValue & 0x0010) != 0; + } + +} \ No newline at end of file diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..1b5a8b95a6 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java @@ -0,0 +1,75 @@ +package com.coderising.jvm.clz; + +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantPool; + +public class ClassFile { + + private int minorVersion; + private int majorVersion; + + private AccessFlag accessFlag; + private ClassIndex clzIndex; + private ConstantPool pool; + + + public ClassIndex getClzIndex() { + return clzIndex; + } + public AccessFlag getAccessFlag() { + return accessFlag; + } + public void setAccessFlag(AccessFlag accessFlag) { + this.accessFlag = accessFlag; + } + + + + public ConstantPool getConstantPool() { + return pool; + } + public int getMinorVersion() { + return minorVersion; + } + public void setMinorVersion(int minorVersion) { + this.minorVersion = minorVersion; + } + public int getMajorVersion() { + return majorVersion; + } + public void setMajorVersion(int majorVersion) { + this.majorVersion = majorVersion; + } + public void setConstPool(ConstantPool pool) { + this.pool = pool; + + } + public void setClassIndex(ClassIndex clzIndex) { + this.clzIndex = clzIndex; + } + + + + + public void print(){ + + if(this.accessFlag.isPublicClass()){ + System.out.println("Access flag : public "); + } + System.out.println("Class Name:"+ getClassName()); + + System.out.println("Super Class Name:"+ getSuperClassName()); + + + } + + private String getClassName(){ + int thisClassIndex = this.clzIndex.getThisClassIndex(); + ClassInfo thisClass = (ClassInfo)this.getConstantPool().getConstantInfo(thisClassIndex); + return thisClass.getClassName(); + } + private String getSuperClassName(){ + ClassInfo superClass = (ClassInfo)this.getConstantPool().getConstantInfo(this.clzIndex.getSuperClassIndex()); + return superClass.getClassName(); + } +} diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/clz/ClassIndex.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..df22981441 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/clz/ClassIndex.java @@ -0,0 +1,19 @@ +package com.coderising.jvm.clz; + +public class ClassIndex { + private int thisClassIndex; + private int superClassIndex; + + public int getThisClassIndex() { + return thisClassIndex; + } + public void setThisClassIndex(int thisClassIndex) { + this.thisClassIndex = thisClassIndex; + } + public int getSuperClassIndex() { + return superClassIndex; + } + public void setSuperClassIndex(int superClassIndex) { + this.superClassIndex = superClassIndex; + } +} \ No newline at end of file diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/ClassInfo.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..e12b3e164e --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/ClassInfo.java @@ -0,0 +1,24 @@ +package com.coderising.jvm.constant; + +public class ClassInfo extends ConstantInfo { + private int type = ConstantInfo.CLASS_INFO; + private int utf8Index ; + public ClassInfo(ConstantPool pool) { + super(pool); + } + public int getUtf8Index() { + return utf8Index; + } + public void setUtf8Index(int utf8Index) { + this.utf8Index = utf8Index; + } + public int getType() { + return type; + } + + public String getClassName() { + int index = getUtf8Index(); + UTF8Info utf8Info = (UTF8Info)constantPool.getConstantInfo(index); + return utf8Info.getValue(); + } +} diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/ConstantInfo.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..c8035ae876 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/ConstantInfo.java @@ -0,0 +1,29 @@ +package com.coderising.jvm.constant; + +public abstract class ConstantInfo { + public static final int UTF8_INFO = 1; + public static final int FLOAT_INFO = 4; + public static final int CLASS_INFO = 7; + public static final int STRING_INFO = 8; + public static final int FIELD_INFO = 9; + public static final int METHOD_INFO = 10; + public static final int NAME_AND_TYPE_INFO = 12; + protected ConstantPool constantPool; + + public ConstantInfo(){ + + } + + public ConstantInfo(ConstantPool pool) { + this.constantPool = pool; + } + public abstract int getType(); + + public ConstantPool getConstantPool() { + return constantPool; + } + public ConstantInfo getConstantInfo(int index){ + return this.constantPool.getConstantInfo(index); + } + +} diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/ConstantPool.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..0e940b78d0 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/ConstantPool.java @@ -0,0 +1,29 @@ +package com.coderising.jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List constantInfos = new ArrayList(); + + + public ConstantPool(){ + + } + public void addConstantInfo(ConstantInfo info){ + + this.constantInfos.add(info); + + } + + public ConstantInfo getConstantInfo(int index){ + return this.constantInfos.get(index); + } + public String getUTF8String(int index){ + return ((UTF8Info)this.constantInfos.get(index)).getValue(); + } + public Object getSize() { + return this.constantInfos.size() -1; + } +} diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/FieldRefInfo.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..7ff9d5fb77 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/FieldRefInfo.java @@ -0,0 +1,54 @@ +package com.coderising.jvm.constant; + +public class FieldRefInfo extends ConstantInfo{ + private int type = ConstantInfo.FIELD_INFO; + private int classInfoIndex; + private int nameAndTypeIndex; + + public FieldRefInfo(ConstantPool pool) { + super(pool); + } + public int getType() { + return type; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String toString(){ + + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + + return getClassName() +" : "+ typeInfo.getName() + ":" + typeInfo.getTypeInfo() +"]"; + } + + public String getClassName(){ + + ClassInfo classInfo = (ClassInfo) this.getConstantInfo(this.getClassInfoIndex()); + + UTF8Info utf8Info = (UTF8Info)this.getConstantInfo(classInfo.getUtf8Index()); + + return utf8Info.getValue(); + + } + + public String getFieldName(){ + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getFieldType(){ + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } +} diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/MethodRefInfo.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..0feffa65b5 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/MethodRefInfo.java @@ -0,0 +1,55 @@ +package com.coderising.jvm.constant; + +public class MethodRefInfo extends ConstantInfo { + + private int type = ConstantInfo.METHOD_INFO; + + private int classInfoIndex; + private int nameAndTypeIndex; + + public MethodRefInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String toString(){ + + return getClassName() +" : "+ this.getMethodName() + " : " + this.getParamAndReturnType() ; + } + public String getClassName(){ + ConstantPool pool = this.getConstantPool(); + ClassInfo clzInfo = (ClassInfo)pool.getConstantInfo(this.getClassInfoIndex()); + return clzInfo.getClassName(); + } + + public String getMethodName(){ + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo)pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getParamAndReturnType(){ + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo)pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } + + + +} diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/NameAndTypeInfo.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..dcac7f97c4 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,45 @@ +package com.coderising.jvm.constant; + +public class NameAndTypeInfo extends ConstantInfo{ + public int type = ConstantInfo.NAME_AND_TYPE_INFO; + + private int index1; + private int index2; + + public NameAndTypeInfo(ConstantPool pool) { + super(pool); + } + + public int getIndex1() { + return index1; + } + public void setIndex1(int index1) { + this.index1 = index1; + } + public int getIndex2() { + return index2; + } + public void setIndex2(int index2) { + this.index2 = index2; + } + public int getType() { + return type; + } + + + public String getName(){ + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info1 = (UTF8Info)pool.getConstantInfo(index1); + return utf8Info1.getValue(); + } + + public String getTypeInfo(){ + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info2 = (UTF8Info)pool.getConstantInfo(index2); + return utf8Info2.getValue(); + } + + public String toString(){ + return "(" + getName() + "," + getTypeInfo()+")"; + } +} diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/NullConstantInfo.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..fa90d110fe --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/NullConstantInfo.java @@ -0,0 +1,13 @@ +package com.coderising.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo(){ + + } + @Override + public int getType() { + return -1; + } + +} diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/StringInfo.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..d01065fd53 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/StringInfo.java @@ -0,0 +1,26 @@ +package com.coderising.jvm.constant; + +public class StringInfo extends ConstantInfo{ + private int type = ConstantInfo.STRING_INFO; + private int index; + public StringInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } + + + public String toString(){ + return this.getConstantPool().getUTF8String(index); + } + +} diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/UTF8Info.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..b7407d146f --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/UTF8Info.java @@ -0,0 +1,32 @@ +package com.coderising.jvm.constant; + +public class UTF8Info extends ConstantInfo{ + private int type = ConstantInfo.UTF8_INFO; + private int length ; + private String value; + public UTF8Info(ConstantPool pool) { + super(pool); + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getType() { + return type; + } + @Override + public String toString() { + return "UTF8Info [type=" + type + ", length=" + length + ", value=" + value +")]"; + } + public String getValue() { + return value; + } + public void setValue(String value) { + this.value = value; + } + + + +} diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..2dff6746da --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,5 @@ +package com.coderising.jvm.loader; + +public class ByteCodeIterator { + +} diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java index 25b8bacf1f..b9c66be7e7 100644 --- a/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -10,11 +10,30 @@ import java.util.ArrayList; import java.util.List; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; + +import com.coderising.jvm.clz.ClassFile; + + public class ClassFileLoader { private List clzPaths = new ArrayList(); - public byte[] readBinaryCode(String className) throws ClassNotFoundException, IOException { + public byte[] readBinaryCode(String className) { + + className = className.replace('.', File.separatorChar) + ".class"; + + for (String path : this.clzPaths) { + + String clzFileName = path + File.separatorChar +className; + byte[] codes = loadClassFile(clzFileName); + if (codes != null) { + return codes; + } + } + return null; + /* if (clzPaths.size() == 0) { throw new ClassNotFoundException(className); } @@ -46,31 +65,41 @@ public byte[] readBinaryCode(String className) throws ClassNotFoundException, IO } finally { is.close(); bos.close(); - } + } */ } - private String getActualPath(String className) { + private byte[] loadClassFile(String clzFileName) { + File f = new File(clzFileName); + try { + return IOUtils.toByteArray(new FileInputStream(f)); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + /*private String getActualPath(String className) { String fileName = className.substring(className.lastIndexOf(".") + 1) + ".class"; String dirPath = className.substring(0, className.lastIndexOf(".")).replace(".", "\\"); return clzPaths.get(clzPaths.size() - 1) + "\\" + dirPath + "\\" + fileName; //classPath 取最近添加的一个 - } + }*/ public void addClassPath(String path) { - if (path == null) { + if (this.clzPaths.contains(path)) { return; } - clzPaths.add(path); + this.clzPaths.add(path); } public String getClassPath() { - if (clzPaths.size() == 0) { + /*if (clzPaths.size() == 0) { return ""; } @@ -81,8 +110,18 @@ public String getClassPath() { buffer.append(";"); } - return buffer.substring(0, buffer.length() - 1);// 去除最后一个分号 + return buffer.substring(0, buffer.length() - 1);*/// 去除最后一个分号 + return StringUtils.join(clzPaths, ";"); } + + public ClassFile loadClass(String className) { + + byte[] codes = this.readBinaryCode(className); + ClassFileParser parser = new ClassFileParser(); + return parser.parse(codes); + + } + } diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..bc18b7916c --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java @@ -0,0 +1,41 @@ +package com.coderising.jvm.loader; + +import java.io.UnsupportedEncodingException; + +import com.coderising.jvm.clz.AccessFlag; +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.clz.ClassIndex; +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.FieldRefInfo; +import com.coderising.jvm.constant.MethodRefInfo; +import com.coderising.jvm.constant.NameAndTypeInfo; +import com.coderising.jvm.constant.NullConstantInfo; +import com.coderising.jvm.constant.StringInfo; +import com.coderising.jvm.constant.UTF8Info; + +public class ClassFileParser { + + public ClassFile parse(byte[] codes) { + + return null; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + + return null; + } + + private ClassIndex parseClassInfex(ByteCodeIterator iter) { + + return null; + + } + + private ConstantPool parseConstantPool(ByteCodeIterator iter) { + + return null; + } + + +} diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java index 392c4a479a..b33d202b69 100644 --- a/group05/1094051862/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -7,6 +7,7 @@ import org.junit.Before; import org.junit.Test; +import com.coderising.jvm.clz.ClassFile; import com.coderising.jvm.loader.ClassFileLoader; @@ -15,11 +16,20 @@ public class ClassFileloaderTest { + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; static String path1 = "E:\\practise\\group05\\1094051862\\mini-jvm\\bin"; static String path2 = "C:\\temp"; - + static ClassFile clzFile = null; + static { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "com.coderising.jvm.test.EmployeeV1"; + + clzFile = loader.loadClass(className); + clzFile.print(); + } @Before public void setUp() throws Exception { @@ -90,5 +100,98 @@ private String byteToHexString(byte[] codes ){ } return buffer.toString(); } + + /** + * ---------------------------------------------------------------------- + */ + + + @Test + public void testVersion(){ + + Assert.assertEquals(0, clzFile.getMinorVersion()); + Assert.assertEquals(52, clzFile.getMajorVersion()); + + } + + @Test + public void testConstantPool(){ + + + ConstantPool pool = clzFile.getConstantPool(); + + Assert.assertEquals(53, pool.getSize()); + + { + ClassInfo clzInfo = (ClassInfo) pool.getConstantInfo(1); + Assert.assertEquals(2, clzInfo.getUtf8Index()); + + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(2); + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, utf8Info.getValue()); + } + { + ClassInfo clzInfo = (ClassInfo) pool.getConstantInfo(3); + Assert.assertEquals(4, clzInfo.getUtf8Index()); + + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(4); + Assert.assertEquals("java/lang/Object", utf8Info.getValue()); + } + { + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(5); + Assert.assertEquals("name", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(6); + Assert.assertEquals("Ljava/lang/String;", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(7); + Assert.assertEquals("age", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(8); + Assert.assertEquals("I", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(9); + Assert.assertEquals("", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(10); + Assert.assertEquals("(Ljava/lang/String;I)V", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(11); + Assert.assertEquals("Code", utf8Info.getValue()); + } + + { + MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(12); + Assert.assertEquals(3, methodRef.getClassInfoIndex()); + Assert.assertEquals(13, methodRef.getNameAndTypeIndex()); + } + + { + NameAndTypeInfo nameAndType = (NameAndTypeInfo) pool.getConstantInfo(13); + Assert.assertEquals(9, nameAndType.getIndex1()); + Assert.assertEquals(14, nameAndType.getIndex2()); + } + //抽查几个吧 + { + MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(45); + Assert.assertEquals(1, methodRef.getClassInfoIndex()); + Assert.assertEquals(46, methodRef.getNameAndTypeIndex()); + } + + { + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(53); + Assert.assertEquals("EmployeeV1.java", utf8Info.getValue()); + } + } + @Test + public void testClassIndex(){ + + ClassIndex clzIndex = clzFile.getClzIndex(); + ClassInfo thisClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getThisClassIndex()); + ClassInfo superClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getSuperClassIndex()); + + + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); + Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); + } } diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/util/Util.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/util/Util.java new file mode 100644 index 0000000000..176f70d002 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/util/Util.java @@ -0,0 +1,24 @@ +package com.coderising.jvm.util; + +public class Util { + public static int byteToInt(byte[] codes){ + String s1 = byteToHexString(codes); + return Integer.valueOf(s1, 16).intValue(); + } + + + + public static String byteToHexString(byte[] codes ){ + StringBuffer buffer = new StringBuffer(); + for(int i=0;i Date: Thu, 6 Apr 2017 22:42:34 +0800 Subject: [PATCH 068/203] load work --- group05/1094051862/mini-jvm/.classpath | 2 + .../src/com/coding/basic/stack/Stack.java | 24 ++++++++++ .../src/com/coding/basic/stack/StackUtil.java | 45 +++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 group05/1094051862/test01/src/com/coding/basic/stack/Stack.java create mode 100644 group05/1094051862/test01/src/com/coding/basic/stack/StackUtil.java diff --git a/group05/1094051862/mini-jvm/.classpath b/group05/1094051862/mini-jvm/.classpath index 9b2ed0d520..e16a825a8f 100644 --- a/group05/1094051862/mini-jvm/.classpath +++ b/group05/1094051862/mini-jvm/.classpath @@ -4,5 +4,7 @@ + + diff --git a/group05/1094051862/test01/src/com/coding/basic/stack/Stack.java b/group05/1094051862/test01/src/com/coding/basic/stack/Stack.java new file mode 100644 index 0000000000..4f4b9af52e --- /dev/null +++ b/group05/1094051862/test01/src/com/coding/basic/stack/Stack.java @@ -0,0 +1,24 @@ +package com.coding.basic.stack; + +import com.coding.basic.array.ArrayList; + +public class Stack { + private ArrayList elementData = new ArrayList(); + + public void push(Object o){ + } + + public Object pop(){ + return null; + } + + public Object peek(){ + return null; + } + public boolean isEmpty(){ + return false; + } + public int size(){ + return -1; + } +} diff --git a/group05/1094051862/test01/src/com/coding/basic/stack/StackUtil.java b/group05/1094051862/test01/src/com/coding/basic/stack/StackUtil.java new file mode 100644 index 0000000000..434d991447 --- /dev/null +++ b/group05/1094051862/test01/src/com/coding/basic/stack/StackUtil.java @@ -0,0 +1,45 @@ +package com.coding.basic.stack; + +public class StackUtil { + + + /** + * 假设栈中的元素是Integer, 从栈顶到栈底是 : 5,4,3,2,1 调用该方法后, 元素次序变为: 1,2,3,4,5 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + */ + public static void reverse(Stack s) { + + } + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s,Object o) { + + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * @param len + * @return + */ + public static Object[] getTop(Stack s,int len) { + return null; + } + /** + * 字符串s 可能包含这些字符: ( ) [ ] { }, a,b,c... x,yz + * 使用堆栈检查字符串s中的括号是不是成对出现的。 + * 例如s = "([e{d}f])" , 则该字符串中的括号是成对出现, 该方法返回true + * 如果 s = "([b{x]y})", 则该字符串中的括号不是成对出现的, 该方法返回false; + * @param s + * @return + */ + public static boolean isValidPairs(String s){ + return false; + } + + +} From f35a9acd1a1f2feeeea5b7d19ffbf777985b11b9 Mon Sep 17 00:00:00 2001 From: wdn <626451284@163.com> Date: Thu, 6 Apr 2017 23:30:38 +0800 Subject: [PATCH 069/203] =?UTF-8?q?=E5=AE=8C=E6=88=90StackUtil=E5=92=8C?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wdn/coding2017/basic/stack/StackUtil.java | 132 ++++++++++++++++++ .../wdn/coding2017/basic/StackUtilTest.java | 57 ++++++++ 2 files changed, 189 insertions(+) create mode 100644 group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/stack/StackUtil.java create mode 100644 group24/626451284/data-structure/src/main/test/com/github/wdn/coding2017/basic/StackUtilTest.java diff --git a/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/stack/StackUtil.java b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/stack/StackUtil.java new file mode 100644 index 0000000000..1e43329fcc --- /dev/null +++ b/group24/626451284/data-structure/src/main/java/com/github/wdn/coding2017/basic/stack/StackUtil.java @@ -0,0 +1,132 @@ +package com.github.wdn.coding2017.basic.stack; + +import com.github.wdn.coding2017.basic.Stack; + +public class StackUtil { + + + /** + * 假设栈中的元素是Integer, 从栈顶到栈底是 : 5,4,3,2,1 调用该方法后, 元素次序变为: 1,2,3,4,5 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + */ + public static void reverse(Stack s) { + Stack stack = new Stack(); + Stack stack1 = new Stack(); + while (!s.isEmpty()){ + stack.push(s.pop()); + } + while (!stack.isEmpty()){ + stack1.push(stack.pop()); + } + while (!stack1.isEmpty()){ + s.push(stack1.pop()); + } + } + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s,Object o) { + Stack stack = new Stack(); + while (!s.isEmpty()) { + Object popObject = s.pop(); + if(popObject.equals(o)){ + break; + } + stack.push(popObject); + } + while (!stack.isEmpty()){ + s.push(stack.pop()); + } + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * @param len + * @return + */ + public static Object[] getTop(Stack s,int len) { + if (len > s.size() || len < 0) { + throw new IndexOutOfBoundsException(); + } + Object[] result = new Object[len]; + Stack stack = new Stack(); + for (int i = 0; i < len; i++) { + Object o = s.pop(); + result[i]=o; + stack.push(o); + } + while (!stack.isEmpty()){ + s.push(stack.pop()); + } + return result; + } + /** + * 字符串s 可能包含这些字符: ( ) [ ] { }, a,b,c... x,yz + * 使用堆栈检查字符串s中的括号是不是成对出现的。 + * 例如s = "([e{d}f])" , 则该字符串中的括号是成对出现, 该方法返回true + * 如果 s = "([b{x]y})", 则该字符串中的括号不是成对出现的, 该方法返回false; + * @param s + * @return + */ + public static boolean isValidPairs(String s){ + if(s.length()<2){ + return false; + } + Stack s1 = new Stack(); + Stack s2 = new Stack(); + char[] chars = s.toCharArray(); + int charsLength = chars.length; + if(charsLength%2==1 && isBrackets(chars[charsLength / 2])){ + return false; + } + for (int i = 0; i < charsLength/2; i++) { + char c = chars[i]; + if (isBrackets(c)) { + s1.push(c); + } + } + for (int i = charsLength-1; i > charsLength/2; i--) { + char c = chars[i]; + if (isBrackets(c)) { + s2.push(c); + } + } + if (s1.size() != s2.size()) { + return false; + } + for (int i = 0; i < s1.size(); i++) { + if (!isPairing((Character) s1.pop(), (Character) s2.pop())) { + return false; + } + } + return true; + } + // parenthesis 圆括号 + // square brackets 方括号 + // braces 大括号 + // 这里用bracket表示统称 + private static boolean isBrackets(char c){ + if('['==c||']'==c|| + '('==c||')'==c|| + '{'==c||'}'==c){ + return true; + } + return false; + } + + private static boolean isPairing(char left, char right) { + if(left=='(' && right==')'){ + return true; + }else if(left=='[' && right==']'){ + return true; + }else if(left=='{' && right=='}'){ + return true; + }else { + return false; + } + } +} diff --git a/group24/626451284/data-structure/src/main/test/com/github/wdn/coding2017/basic/StackUtilTest.java b/group24/626451284/data-structure/src/main/test/com/github/wdn/coding2017/basic/StackUtilTest.java new file mode 100644 index 0000000000..7e56bbf345 --- /dev/null +++ b/group24/626451284/data-structure/src/main/test/com/github/wdn/coding2017/basic/StackUtilTest.java @@ -0,0 +1,57 @@ +package com.github.wdn.coding2017.basic; + +import com.github.wdn.coding2017.basic.stack.StackUtil; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; + +/** + * Created by Administrator on 2017/4/6 0006. + */ +public class StackUtilTest { + + @Test + public void testReverse(){ + Stack stack = new Stack(); + stack.push(1); + stack.push(2); + stack.push(3); + stack.push(4); + StackUtil.reverse(stack); + while (!stack.isEmpty()){ + System.out.println(stack.pop()); + } + } + @Test + public void testRemove(){ + Stack stack = new Stack(); + stack.push(1); + stack.push(2); + stack.push(3); + stack.push(4); + StackUtil.remove(stack,4); + while (!stack.isEmpty()){ + System.out.println(stack.pop()); + } + } + @Test + public void testGetTop(){ + Stack stack = new Stack(); + stack.push(1); + stack.push(2); + stack.push(3); + stack.push(4); + Object[] o = StackUtil.getTop(stack,0); + System.out.println(Arrays.toString(o)); + while (!stack.isEmpty()){ + System.out.println(stack.pop()); + } + } + @Test + public void testIsValidPairs(){ + Assert.assertEquals(true,StackUtil.isValidPairs("([e{d}f])")); + Assert.assertEquals(false,StackUtil.isValidPairs("([b{x]y})")); + Assert.assertEquals(false,StackUtil.isValidPairs("([({e}f])")); + } +} From 93ddb61908bdb60c3ebe594bb9dff12cfcdccbee Mon Sep 17 00:00:00 2001 From: johnChnia Date: Fri, 7 Apr 2017 01:52:00 +0800 Subject: [PATCH 070/203] =?UTF-8?q?=E5=8F=8C=E5=90=91=E9=93=BE=E8=A1=A8?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0LRU=E7=AE=97=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/johnChnia/coding2017/basic/Stack.java | 2 + .../basic/linklist/LRUPageFrame.java | 130 ++++++++++++++++++ .../basic/linklist/LRUPageFrameTest.java | 30 ++++ .../basic/{ => linklist}/LinkedList.java | 6 +- .../coding2017/basic/ArrayListTest.java | 1 - .../coding2017/basic/LinkedListTest.java | 2 +- 6 files changed, 167 insertions(+), 4 deletions(-) create mode 100644 group24/315863321/src/main/java/com/johnChnia/coding2017/basic/linklist/LRUPageFrame.java create mode 100644 group24/315863321/src/main/java/com/johnChnia/coding2017/basic/linklist/LRUPageFrameTest.java rename group24/315863321/src/main/java/com/johnChnia/coding2017/basic/{ => linklist}/LinkedList.java (98%) diff --git a/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/Stack.java b/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/Stack.java index f43ea52397..3ddab60493 100644 --- a/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/Stack.java +++ b/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/Stack.java @@ -1,5 +1,7 @@ package com.johnChnia.coding2017.basic; +import com.johnChnia.coding2017.basic.linklist.LinkedList; + import java.util.EmptyStackException; /** diff --git a/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/linklist/LRUPageFrame.java b/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/linklist/LRUPageFrame.java new file mode 100644 index 0000000000..c74a9a3202 --- /dev/null +++ b/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/linklist/LRUPageFrame.java @@ -0,0 +1,130 @@ +package com.johnChnia.coding2017.basic.linklist; + +/** + * Created by john on 2017/4/6. + */ +public class LRUPageFrame { + + private static class Node { + + Node prev; + Node next; + int pageNum; + + Node() { + } + } + + private int capacity; + + + private Node first;// 链表头 + private Node last;// 链表尾 + + + public LRUPageFrame(int capacity) { + + this.capacity = capacity; + + } + + /** + * 获取缓存中的对象 + * 1 2 3 + * + * @param pageNum 对象值 + */ + public void access(int pageNum) { + if (first == null) { + Node node = createNode(pageNum); + first = last = node; + capacity--; + } else if (getNode(pageNum) == null) { + if (capacity == 0) { + Node lastNode = first; + while (lastNode.next != null) { + lastNode = lastNode.next; + } + lastNode.prev.next = null; + last = lastNode.prev; + delete(lastNode); + capacity++; + } + Node node = createNode(pageNum); + node.next = first; + node.prev = null; + first.prev = node; + first = node; + capacity--; + + } else { + if (first.pageNum != pageNum) { + Node node = getNode(pageNum); + if (node.next != null) { + node.prev.next = node.next; + node.next.prev = node.prev; + } else { + node.prev.next = null; + node.next = first; + node.prev = null; + } + node.next = first; + node.prev = null; + first.prev = node; + first = node; + } + } + + } + + /** + * 删除节点 + */ + private void delete(Node node) { + node.pageNum = 0; + node.next = null; + node.prev = null; + } + + /** + * @param pageNum 页号 + * @return 节点 + */ + private Node createNode(int pageNum) { + Node node = new Node(); + node.pageNum = pageNum; + node.next = null; + node.prev = null; + return node; + } + + + /** + * @param pageNum 页号 + * @return 如果LRUPageFrame包含该pageNum就返回该节点,否则返回null + */ + private Node getNode(int pageNum) { + for (Node node = first; node != null; node = node.next) { + if (node.pageNum == pageNum) { + return node; + } + } + return null; + } + + + public String toString() { + StringBuilder buffer = new StringBuilder(); + Node node = first; + while (node != null) { + buffer.append(node.pageNum); + + node = node.next; + if (node != null) { + buffer.append(","); + } + } + return buffer.toString(); + } + +} diff --git a/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/linklist/LRUPageFrameTest.java b/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/linklist/LRUPageFrameTest.java new file mode 100644 index 0000000000..e71abd393d --- /dev/null +++ b/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/linklist/LRUPageFrameTest.java @@ -0,0 +1,30 @@ +package com.johnChnia.coding2017.basic.linklist; + +import org.junit.Assert; +import org.junit.Test; + + +public class LRUPageFrameTest { + + @Test + public void testAccess() { + LRUPageFrame frame = new LRUPageFrame(3); + frame.access(7); + frame.access(0); + frame.access(1); + Assert.assertEquals("1,0,7", frame.toString()); + frame.access(2); + Assert.assertEquals("2,1,0", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(3); + Assert.assertEquals("3,0,2", frame.toString()); + frame.access(0); + Assert.assertEquals("0,3,2", frame.toString()); + frame.access(4); + Assert.assertEquals("4,0,3", frame.toString()); + } + +} diff --git a/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/LinkedList.java b/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/linklist/LinkedList.java similarity index 98% rename from group24/315863321/src/main/java/com/johnChnia/coding2017/basic/LinkedList.java rename to group24/315863321/src/main/java/com/johnChnia/coding2017/basic/linklist/LinkedList.java index 01ba928128..10f7edd0a6 100644 --- a/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/LinkedList.java +++ b/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/linklist/LinkedList.java @@ -1,4 +1,6 @@ -package com.johnChnia.coding2017.basic; +package com.johnChnia.coding2017.basic.linklist; + +import com.johnChnia.coding2017.basic.List; import java.util.NoSuchElementException; @@ -345,7 +347,7 @@ public int[] getElements(LinkedList list) { valueNode = valueNode.next; indexOfArray++; } else { - mapNode = mapNode.next; + valueNode = valueNode.next; } indexOfList++; } diff --git a/group24/315863321/src/test/java/com/johnChnia/coding2017/basic/ArrayListTest.java b/group24/315863321/src/test/java/com/johnChnia/coding2017/basic/ArrayListTest.java index e0df250c37..4b8d986990 100644 --- a/group24/315863321/src/test/java/com/johnChnia/coding2017/basic/ArrayListTest.java +++ b/group24/315863321/src/test/java/com/johnChnia/coding2017/basic/ArrayListTest.java @@ -54,7 +54,6 @@ public void testRemoveElementByIndex() { arrayList4.add(i); } Object removed = arrayList4.remove(4); - System.out.println(arrayList4); assertThat(removed, equalTo(4)); assertThat(arrayList4.size(), equalTo(5)); } diff --git a/group24/315863321/src/test/java/com/johnChnia/coding2017/basic/LinkedListTest.java b/group24/315863321/src/test/java/com/johnChnia/coding2017/basic/LinkedListTest.java index 9a72c0d54a..941d524987 100644 --- a/group24/315863321/src/test/java/com/johnChnia/coding2017/basic/LinkedListTest.java +++ b/group24/315863321/src/test/java/com/johnChnia/coding2017/basic/LinkedListTest.java @@ -2,7 +2,7 @@ import org.junit.Before; import org.junit.Test; - +import com.johnChnia.coding2017.basic.linklist.LinkedList; import java.util.Arrays; import static org.hamcrest.CoreMatchers.containsString; From 2bd5947203bfbfca0f82f21359b6616de1dc3bd4 Mon Sep 17 00:00:00 2001 From: zhanglei <383117348@qq.com> Date: Fri, 7 Apr 2017 11:58:38 +0800 Subject: [PATCH 071/203] =?UTF-8?q?=E5=A4=87=E4=BB=BD=E8=87=AA=E5=B7=B1?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E7=9A=84ClassFileLoader?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jvm/loader/ClassFileLoader_backup.java | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 group27/383117348/src/com/coderising/jvm/loader/ClassFileLoader_backup.java diff --git a/group27/383117348/src/com/coderising/jvm/loader/ClassFileLoader_backup.java b/group27/383117348/src/com/coderising/jvm/loader/ClassFileLoader_backup.java new file mode 100644 index 0000000000..014def27d5 --- /dev/null +++ b/group27/383117348/src/com/coderising/jvm/loader/ClassFileLoader_backup.java @@ -0,0 +1,77 @@ +package com.coderising.jvm.loader; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class ClassFileLoader_backup { + + private List clzPaths = new ArrayList(); + + public byte[] readBinaryCode(String className) { + className = className.replace(".", "\\"); + File file = null; + for(String classPath : clzPaths){ + file = new File(classPath + "\\" + className + ".class"); + if(file.exists()){ + break; + } + } + if(!file.exists()){ + try { + throw new ClassNotFoundException(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + ByteArrayOutputStream bos = new ByteArrayOutputStream((int) file.length()); + BufferedInputStream in = null; + try { + in = new BufferedInputStream(new FileInputStream(file)); + int buf_size = 1024; + byte[] buffer = new byte[buf_size]; + int len = 0; + while (-1 != (len = in.read(buffer, 0, buf_size))) { + bos.write(buffer, 0, len); + } + return bos.toByteArray(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + in.close(); + } catch (IOException e) { + e.printStackTrace(); + } + try { + bos.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + return null; + } + + public void addClassPath(String path) { + if (path != null && path.length() > 0) { + if (!clzPaths.contains(path)) { + clzPaths.add(path); + } + } + } + + public String getClassPath() { + String paths = ""; + for (String s : clzPaths) { + paths += s + ";"; + } + paths = paths.substring(0, paths.length() - 1); + return paths; + } + +} From 45b2e97f1dcb36b7e9d2b1de8afec8bd9f26c98c Mon Sep 17 00:00:00 2001 From: zhanglei <383117348@qq.com> Date: Fri, 7 Apr 2017 12:02:45 +0800 Subject: [PATCH 072/203] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=83=A8=E5=88=86?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=9A=84=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group27/383117348/.classpath | 2 + .../jvm/loader/ClassFileLoader.java | 163 ++++++++++++------ .../coding/basic/{ => array}/ArrayList.java | 5 +- .../basic}/array/ArrayUtil.java | 2 +- .../com/coding/basic/{ => stack}/Stack.java | 4 +- 5 files changed, 123 insertions(+), 53 deletions(-) rename group27/383117348/src/com/coding/basic/{ => array}/ArrayList.java (92%) rename group27/383117348/src/com/{coderising => coding/basic}/array/ArrayUtil.java (95%) rename group27/383117348/src/com/coding/basic/{ => stack}/Stack.java (90%) diff --git a/group27/383117348/.classpath b/group27/383117348/.classpath index 840446d6d6..a96bb3c428 100644 --- a/group27/383117348/.classpath +++ b/group27/383117348/.classpath @@ -6,5 +6,7 @@ + + diff --git a/group27/383117348/src/com/coderising/jvm/loader/ClassFileLoader.java b/group27/383117348/src/com/coderising/jvm/loader/ClassFileLoader.java index 09051be9b6..9ff27b16cf 100644 --- a/group27/383117348/src/com/coderising/jvm/loader/ClassFileLoader.java +++ b/group27/383117348/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -8,70 +8,133 @@ import java.util.ArrayList; import java.util.List; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; + +import com.coderising.jvm.clz.ClassFile; + + + + + public class ClassFileLoader { private List clzPaths = new ArrayList(); - + public byte[] readBinaryCode(String className) { - className = className.replace(".", "\\"); - File file = null; - for(String classPath : clzPaths){ - file = new File(classPath + "\\" + className + ".class"); - if(file.exists()){ - break; - } + + className = className.replace('.', File.separatorChar) +".class"; + + for(String path : this.clzPaths){ + + String clzFileName = path + File.separatorChar + className; + byte[] codes = loadClassFile(clzFileName); + if(codes != null){ + return codes; + } + } + + return null; + + + + } + + private byte[] loadClassFile(String clzFileName) { + + File f = new File(clzFileName); + + try { + + return IOUtils.toByteArray(new FileInputStream(f)); + + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + + + public void addClassPath(String path) { + if(this.clzPaths.contains(path)){ + return; } - if(!file.exists()){ - try { - throw new ClassNotFoundException(); - } catch (ClassNotFoundException e) { - e.printStackTrace(); + + this.clzPaths.add(path); + + } + + + + public String getClassPath(){ + return StringUtils.join(this.clzPaths,";"); + } + + public ClassFile loadClass(String className) { + byte[] codes = this.readBinaryCode(className); + ClassFileParser parser = new ClassFileParser(); + return parser.parse(codes); + + } + + + + // ------------------------------backup------------------------ + public String getClassPath_V1(){ + + StringBuffer buffer = new StringBuffer(); + for(int i=0;i 0) { - if (!clzPaths.contains(path)) { - clzPaths.add(path); - } - } - } - public String getClassPath() { - String paths = ""; - for (String s : clzPaths) { - paths += s + ";"; - } - paths = paths.substring(0, paths.length() - 1); - return paths; - } + -} +} \ No newline at end of file diff --git a/group27/383117348/src/com/coding/basic/ArrayList.java b/group27/383117348/src/com/coding/basic/array/ArrayList.java similarity index 92% rename from group27/383117348/src/com/coding/basic/ArrayList.java rename to group27/383117348/src/com/coding/basic/array/ArrayList.java index 773d8f6c6b..c9bb3e8f62 100644 --- a/group27/383117348/src/com/coding/basic/ArrayList.java +++ b/group27/383117348/src/com/coding/basic/array/ArrayList.java @@ -1,9 +1,12 @@ -package com.coding.basic; +package com.coding.basic.array; import java.util.Arrays; import org.junit.Test; +import com.coding.basic.Iterator; +import com.coding.basic.List; + public class ArrayList implements List { private int size = 0; diff --git a/group27/383117348/src/com/coderising/array/ArrayUtil.java b/group27/383117348/src/com/coding/basic/array/ArrayUtil.java similarity index 95% rename from group27/383117348/src/com/coderising/array/ArrayUtil.java rename to group27/383117348/src/com/coding/basic/array/ArrayUtil.java index 61fd42254a..b8ba0beb4b 100644 --- a/group27/383117348/src/com/coderising/array/ArrayUtil.java +++ b/group27/383117348/src/com/coding/basic/array/ArrayUtil.java @@ -1,4 +1,4 @@ -package com.coderising.array; +package com.coding.basic.array; import java.util.ArrayList; import java.util.Arrays; diff --git a/group27/383117348/src/com/coding/basic/Stack.java b/group27/383117348/src/com/coding/basic/stack/Stack.java similarity index 90% rename from group27/383117348/src/com/coding/basic/Stack.java rename to group27/383117348/src/com/coding/basic/stack/Stack.java index 1b12b63b0f..47e9918d1a 100644 --- a/group27/383117348/src/com/coding/basic/Stack.java +++ b/group27/383117348/src/com/coding/basic/stack/Stack.java @@ -1,7 +1,9 @@ -package com.coding.basic; +package com.coding.basic.stack; import org.junit.Test; +import com.coding.basic.array.ArrayList; + public class Stack { private ArrayList elementData = new ArrayList(); From e38a8907f9291ca131b3f1ba12dd80227d57ccef Mon Sep 17 00:00:00 2001 From: johnChnia Date: Fri, 7 Apr 2017 14:40:47 +0800 Subject: [PATCH 073/203] =?UTF-8?q?=E4=BF=AE=E6=94=B9LRU-=E5=B0=BE?= =?UTF-8?q?=E6=8C=87=E9=92=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/johnChnia/coding2017/basic/linklist/LRUPageFrame.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/linklist/LRUPageFrame.java b/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/linklist/LRUPageFrame.java index c74a9a3202..cdc327fb30 100644 --- a/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/linklist/LRUPageFrame.java +++ b/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/linklist/LRUPageFrame.java @@ -30,7 +30,6 @@ public LRUPageFrame(int capacity) { /** * 获取缓存中的对象 - * 1 2 3 * * @param pageNum 对象值 */ @@ -65,8 +64,7 @@ public void access(int pageNum) { node.next.prev = node.prev; } else { node.prev.next = null; - node.next = first; - node.prev = null; + last = node.prev; } node.next = first; node.prev = null; From c3831d31f5fe4b335b69c33dba3cc1dc1959e5ef Mon Sep 17 00:00:00 2001 From: OnlyLYJ <382266293@qq.com> Date: Sat, 8 Apr 2017 06:30:36 +0800 Subject: [PATCH 074/203] ex 2 --- .../coding/basic/linklist/LRUPageFrame.java | 171 ++++++++++++++++++ .../basic/linklist/LRUPageFrameTest.java | 31 ++++ 2 files changed, 202 insertions(+) create mode 100644 group12/382266293/coding/basic/linklist/LRUPageFrame.java create mode 100644 group12/382266293/coding/basic/linklist/LRUPageFrameTest.java diff --git a/group12/382266293/coding/basic/linklist/LRUPageFrame.java b/group12/382266293/coding/basic/linklist/LRUPageFrame.java new file mode 100644 index 0000000000..dec3ecc464 --- /dev/null +++ b/group12/382266293/coding/basic/linklist/LRUPageFrame.java @@ -0,0 +1,171 @@ +package linklist; + +/** + * 用双向链表实现LRU算法 + * + * + */ +public class LRUPageFrame { + + private static class Node { + + Node prev; + Node next; + int pageNum; + + Node(int pageNum) { + this.pageNum = pageNum; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + pageNum; + return result; + } + + + @Override + public String toString() { + return "Node [pageNum=" + pageNum + "]"; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Node other = (Node) obj; + if (pageNum != other.pageNum) + return false; + return true; + } + + } + + private int capacity; + + + private Node first;// 链表头 + private Node last;// 链表尾 + + + public LRUPageFrame(int capacity) { + + this.capacity = capacity; + + } + + private int size; + + /** + * 获取缓存中对象 + * + * @param key + * @return + */ + public void access(int pageNum) { + if (size < this.capacity) { + addNode(pageNum); + return; + } + + Node p = findNode(pageNum); + if (null == p) { + p = new Node(pageNum); + p.next = first; + first.prev = p; + first = p; + moveLastPoint(); + return; + } + + if (p == first) { + return; + } + + if (p == last) { + p.next = first; + first.prev = p; + first = p; + moveLastPoint(); + return; + } + + movePtoFirst(p); + + } + + private void moveLastPoint() { + last = last.prev; + last.next = null; + } + + + + private void movePtoFirst(Node p) { + p.prev.next = p.next; + p.next.prev = p.prev; + first.prev = p; + p.next = first; + first = p; + } + + + + private void addNode(int pageNum) { + Node node = new Node(pageNum); + if (null == first) { + first = node; + size++; + return; + } + if (null == last) { + node.next = first; + first.prev = node; + first = node; + last = node.next; + size++; + return; + } + node.next = first; + first.prev = node; + first = node; + size++; + } + + + + private Node findNode(int pageNum) { + Node node = first; + while (null != node) { + if (node.pageNum != pageNum) { + node = node.next; + } else { + return node; + } + } + return null; + } + + + + public String toString(){ + StringBuilder buffer = new StringBuilder(); + Node node = first; + while(node != null){ + buffer.append(node.pageNum); + + node = node.next; + if(node != null){ + buffer.append(","); + } + } + return buffer.toString(); + } + +} diff --git a/group12/382266293/coding/basic/linklist/LRUPageFrameTest.java b/group12/382266293/coding/basic/linklist/LRUPageFrameTest.java new file mode 100644 index 0000000000..bea7586e15 --- /dev/null +++ b/group12/382266293/coding/basic/linklist/LRUPageFrameTest.java @@ -0,0 +1,31 @@ +package linklist; + +import org.junit.Assert; + +import org.junit.Test; + + +public class LRUPageFrameTest { + + @Test + public void testAccess() { + LRUPageFrame frame = new LRUPageFrame(3); + frame.access(7); + frame.access(0); + frame.access(1); + Assert.assertEquals("1,0,7", frame.toString()); + frame.access(2); + Assert.assertEquals("2,1,0", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(3); + Assert.assertEquals("3,0,2", frame.toString()); + frame.access(0); + Assert.assertEquals("0,3,2", frame.toString()); + frame.access(4); + Assert.assertEquals("4,0,3", frame.toString()); + } + +} From 0fd3c008a9709fcb429aaf14c4270083f2af2904 Mon Sep 17 00:00:00 2001 From: zheng <765324639@qq.com> Date: Sat, 8 Apr 2017 10:52:52 +0800 Subject: [PATCH 075/203] =?UTF-8?q?=E8=BD=AC=E4=B8=BAmaven=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=EF=BC=8C=E5=AE=8C=E6=88=90=E7=AC=AC5=E6=AC=A1?= =?UTF-8?q?=E4=BD=9C=E4=B8=9A=EF=BC=88jvm=EF=BC=8CStackUtil=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/datastructure/stack/Stack.java | 12 ++ .../java/datastructure/stack/StackUtil.java | 110 ++++++++++++++++ .../main/java/download/DownloadThread.java | 2 +- .../src/main/java/minijvm/clz/AccessFlag.java | 25 ++++ .../src/main/java/minijvm/clz/ClassFile.java | 75 +++++++++++ .../src/main/java/minijvm/clz/ClassIndex.java | 19 +++ .../main/java/minijvm/constant/ClassInfo.java | 25 ++++ .../java/minijvm/constant/ConstantInfo.java | 29 +++++ .../java/minijvm/constant/ConstantPool.java | 29 +++++ .../java/minijvm/constant/FieldRefInfo.java | 56 +++++++++ .../java/minijvm/constant/MethodRefInfo.java | 57 +++++++++ .../minijvm/constant/NameAndTypeInfo.java | 47 +++++++ .../minijvm/constant/NullConstantInfo.java | 13 ++ .../java/minijvm/constant/StringInfo.java | 28 +++++ .../main/java/minijvm/constant/UTF8Info.java | 33 +++++ .../java/minijvm/loader/ByteCodeIterator.java | 47 +++++++ .../java/minijvm/loader/ClassFileLoader.java | 11 +- .../java/minijvm/loader/ClassFileParser.java | 119 ++++++++++++++++++ .../src/main/java/minijvm/loader/MyTest.java | 10 -- .../src/main/java/minijvm/util/Util.java | 24 ++++ .../datastructure/stack/StackUtilTest.java | 58 +++++++++ .../java/download/FileDownloaderTest.java | 4 +- .../minijvm/loader/ClassFileloaderTest.java | 115 ++++++++++++++++- .../java/minijvm/loader/EmployeeV1.java | 1 - 24 files changed, 930 insertions(+), 19 deletions(-) create mode 100644 group01/765324639/src/main/java/datastructure/stack/StackUtil.java create mode 100644 group01/765324639/src/main/java/minijvm/clz/AccessFlag.java create mode 100644 group01/765324639/src/main/java/minijvm/clz/ClassFile.java create mode 100644 group01/765324639/src/main/java/minijvm/clz/ClassIndex.java create mode 100644 group01/765324639/src/main/java/minijvm/constant/ClassInfo.java create mode 100644 group01/765324639/src/main/java/minijvm/constant/ConstantInfo.java create mode 100644 group01/765324639/src/main/java/minijvm/constant/ConstantPool.java create mode 100644 group01/765324639/src/main/java/minijvm/constant/FieldRefInfo.java create mode 100644 group01/765324639/src/main/java/minijvm/constant/MethodRefInfo.java create mode 100644 group01/765324639/src/main/java/minijvm/constant/NameAndTypeInfo.java create mode 100644 group01/765324639/src/main/java/minijvm/constant/NullConstantInfo.java create mode 100644 group01/765324639/src/main/java/minijvm/constant/StringInfo.java create mode 100644 group01/765324639/src/main/java/minijvm/constant/UTF8Info.java create mode 100644 group01/765324639/src/main/java/minijvm/loader/ByteCodeIterator.java create mode 100644 group01/765324639/src/main/java/minijvm/loader/ClassFileParser.java delete mode 100644 group01/765324639/src/main/java/minijvm/loader/MyTest.java create mode 100644 group01/765324639/src/main/java/minijvm/util/Util.java create mode 100644 group01/765324639/src/test/java/datastructure/stack/StackUtilTest.java rename group01/765324639/src/{main => test}/java/minijvm/loader/EmployeeV1.java (94%) diff --git a/group01/765324639/src/main/java/datastructure/stack/Stack.java b/group01/765324639/src/main/java/datastructure/stack/Stack.java index a5ac46c3f5..52d4f818e8 100644 --- a/group01/765324639/src/main/java/datastructure/stack/Stack.java +++ b/group01/765324639/src/main/java/datastructure/stack/Stack.java @@ -32,4 +32,16 @@ public boolean isEmpty() { public int size() { return elementData.size(); } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + int i = 0; + for ( ; i < elementData.size() - 1; i++) { + builder.append(elementData.get(i) + ","); + } + builder.append(elementData.get(i)); + return builder.toString(); + } + } diff --git a/group01/765324639/src/main/java/datastructure/stack/StackUtil.java b/group01/765324639/src/main/java/datastructure/stack/StackUtil.java new file mode 100644 index 0000000000..b45f90337d --- /dev/null +++ b/group01/765324639/src/main/java/datastructure/stack/StackUtil.java @@ -0,0 +1,110 @@ +package datastructure.stack; + +public class StackUtil { + + + /** + * 假设栈中的元素是Integer, 从栈顶到栈底是 : 5,4,3,2,1 调用该方法后, 元素次序变为: 1,2,3,4,5 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + */ + public static void reverse(Stack s) { + if (s == null || s.isEmpty()) { + return; + } + + Stack temp1 = new Stack(); + while (!s.isEmpty()) { + temp1.push(s.pop()); + } + Stack temp2 = new Stack(); + while (!temp1.isEmpty()) { + temp2.push(temp1.pop()); + } + while (!temp2.isEmpty()) { + s.push(temp2.pop()); + } + } + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s,Object o) { + if (s == null || s.isEmpty()) { + return; + } + + Stack temp = new Stack(); + while (!s.isEmpty()) { + int num = (int) s.pop(); + if (num != (int)o) { + temp.push(num); + } + } + while (!temp.isEmpty()) { + s.push(temp.pop()); + } + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * @param len + * @return + */ + public static Object[] getTop(Stack s,int len) { + if (s == null || s.isEmpty() || len < 0) { + return null; + } + + Stack temp = new Stack(); + int i = 0; + Object[] obj = new Object[len]; + while(!s.isEmpty() && i < len) { + temp.push(s.peek()); + obj[i++] = s.pop(); + } + while (!temp.isEmpty()) { + s.push(temp.pop()); + } + return obj; + } + /** + * 字符串s 可能包含这些字符: ( ) [ ] { }, a,b,c... x,yz + * 使用堆栈检查字符串s中的括号是不是成对出现的。 + * 例如s = "([e{d}f])" , 则该字符串中的括号是成对出现, 该方法返回true + * 如果 s = "([b{x]y})", 则该字符串中的括号不是成对出现的, 该方法返回false; + * @param s + * @return + */ + public static boolean isValidPairs(String s) { + if (s == null) { + return false; + } + + Stack stack = new Stack(); + char[] charArray = s.toCharArray(); + for (int i = 0; i < charArray.length; i++) { + char c = charArray[i]; + if (c == '(' || c == '[' || c == '{') { + stack.push(c); + } else if (c == ')') { + if ('(' != (char)stack.pop()) { + return false; + } + } else if (c == ']') { + if ('[' != (char)stack.pop()) { + return false; + } + } else if (c == '}') { + if ('{' != (char)stack.pop()) { + return false; + } + } + } + return true; + } + + +} diff --git a/group01/765324639/src/main/java/download/DownloadThread.java b/group01/765324639/src/main/java/download/DownloadThread.java index cba16f40f6..88641b3741 100644 --- a/group01/765324639/src/main/java/download/DownloadThread.java +++ b/group01/765324639/src/main/java/download/DownloadThread.java @@ -22,7 +22,7 @@ public DownloadThread(Connection conn, int startPos, int endPos) { @Override public void run() { - System.out.println("开始下载:" + startPos + "~" + endPos); + System.out.println("start download:" + startPos + "~" + endPos); byte[] data = new byte[endPos - startPos]; try { data = conn.read(startPos, endPos); diff --git a/group01/765324639/src/main/java/minijvm/clz/AccessFlag.java b/group01/765324639/src/main/java/minijvm/clz/AccessFlag.java new file mode 100644 index 0000000000..7585a3c460 --- /dev/null +++ b/group01/765324639/src/main/java/minijvm/clz/AccessFlag.java @@ -0,0 +1,25 @@ +package minijvm.clz; + +public class AccessFlag { + private int flagValue; + + public AccessFlag(int value) { + this.flagValue = value; + } + + public int getFlagValue() { + return flagValue; + } + + public void setFlagValue(int flag) { + this.flagValue = flag; + } + + public boolean isPublicClass(){ + return (this.flagValue & 0x0001) != 0; + } + public boolean isFinalClass(){ + return (this.flagValue & 0x0010) != 0; + } + +} \ No newline at end of file diff --git a/group01/765324639/src/main/java/minijvm/clz/ClassFile.java b/group01/765324639/src/main/java/minijvm/clz/ClassFile.java new file mode 100644 index 0000000000..36eddeb46d --- /dev/null +++ b/group01/765324639/src/main/java/minijvm/clz/ClassFile.java @@ -0,0 +1,75 @@ +package minijvm.clz; + +import minijvm.constant.ClassInfo; +import minijvm.constant.ConstantPool; + +public class ClassFile { + + private int minorVersion; + private int majorVersion; + + private AccessFlag accessFlag; + private ClassIndex clzIndex; + private ConstantPool pool; + + + public ClassIndex getClzIndex() { + return clzIndex; + } + public AccessFlag getAccessFlag() { + return accessFlag; + } + public void setAccessFlag(AccessFlag accessFlag) { + this.accessFlag = accessFlag; + } + + + + public ConstantPool getConstantPool() { + return pool; + } + public int getMinorVersion() { + return minorVersion; + } + public void setMinorVersion(int minorVersion) { + this.minorVersion = minorVersion; + } + public int getMajorVersion() { + return majorVersion; + } + public void setMajorVersion(int majorVersion) { + this.majorVersion = majorVersion; + } + public void setConstPool(ConstantPool pool) { + this.pool = pool; + + } + public void setClassIndex(ClassIndex clzIndex) { + this.clzIndex = clzIndex; + } + + + + + public void print(){ + + if(this.accessFlag.isPublicClass()){ + System.out.println("Access flag : public "); + } + System.out.println("Class Name:"+ getClassName()); + + System.out.println("Super Class Name:"+ getSuperClassName()); + + + } + + private String getClassName(){ + int thisClassIndex = this.clzIndex.getThisClassIndex(); + ClassInfo thisClass = (ClassInfo)this.getConstantPool().getConstantInfo(thisClassIndex); + return thisClass.getClassName(); + } + private String getSuperClassName(){ + ClassInfo superClass = (ClassInfo)this.getConstantPool().getConstantInfo(this.clzIndex.getSuperClassIndex()); + return superClass.getClassName(); + } +} diff --git a/group01/765324639/src/main/java/minijvm/clz/ClassIndex.java b/group01/765324639/src/main/java/minijvm/clz/ClassIndex.java new file mode 100644 index 0000000000..4b25095924 --- /dev/null +++ b/group01/765324639/src/main/java/minijvm/clz/ClassIndex.java @@ -0,0 +1,19 @@ +package minijvm.clz; + +public class ClassIndex { + private int thisClassIndex; + private int superClassIndex; + + public int getThisClassIndex() { + return thisClassIndex; + } + public void setThisClassIndex(int thisClassIndex) { + this.thisClassIndex = thisClassIndex; + } + public int getSuperClassIndex() { + return superClassIndex; + } + public void setSuperClassIndex(int superClassIndex) { + this.superClassIndex = superClassIndex; + } +} \ No newline at end of file diff --git a/group01/765324639/src/main/java/minijvm/constant/ClassInfo.java b/group01/765324639/src/main/java/minijvm/constant/ClassInfo.java new file mode 100644 index 0000000000..c856052998 --- /dev/null +++ b/group01/765324639/src/main/java/minijvm/constant/ClassInfo.java @@ -0,0 +1,25 @@ +package minijvm.constant; + +public class ClassInfo extends ConstantInfo { + private int type = ConstantInfo.CLASS_INFO; + private int utf8Index ; + public ClassInfo(ConstantPool pool) { + super(pool); + } + public int getUtf8Index() { + return utf8Index; + } + public void setUtf8Index(int utf8Index) { + this.utf8Index = utf8Index; + } + @Override + public int getType() { + return type; + } + + public String getClassName() { + int index = getUtf8Index(); + UTF8Info utf8Info = (UTF8Info)constantPool.getConstantInfo(index); + return utf8Info.getValue(); + } +} diff --git a/group01/765324639/src/main/java/minijvm/constant/ConstantInfo.java b/group01/765324639/src/main/java/minijvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..5fa0be0189 --- /dev/null +++ b/group01/765324639/src/main/java/minijvm/constant/ConstantInfo.java @@ -0,0 +1,29 @@ +package minijvm.constant; + +public abstract class ConstantInfo { + public static final int UTF8_INFO = 1; + public static final int FLOAT_INFO = 4; + public static final int CLASS_INFO = 7; + public static final int STRING_INFO = 8; + public static final int FIELD_INFO = 9; + public static final int METHOD_INFO = 10; + public static final int NAME_AND_TYPE_INFO = 12; + protected ConstantPool constantPool; + + public ConstantInfo(){ + + } + + public ConstantInfo(ConstantPool pool) { + this.constantPool = pool; + } + public abstract int getType(); + + public ConstantPool getConstantPool() { + return constantPool; + } + public ConstantInfo getConstantInfo(int index){ + return this.constantPool.getConstantInfo(index); + } + +} diff --git a/group01/765324639/src/main/java/minijvm/constant/ConstantPool.java b/group01/765324639/src/main/java/minijvm/constant/ConstantPool.java new file mode 100644 index 0000000000..12746a1f3c --- /dev/null +++ b/group01/765324639/src/main/java/minijvm/constant/ConstantPool.java @@ -0,0 +1,29 @@ +package minijvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List constantInfos = new ArrayList(); + + + public ConstantPool(){ + + } + public void addConstantInfo(ConstantInfo info){ + + this.constantInfos.add(info); + + } + + public ConstantInfo getConstantInfo(int index){ + return this.constantInfos.get(index); + } + public String getUTF8String(int index){ + return ((UTF8Info)this.constantInfos.get(index)).getValue(); + } + public Object getSize() { + return this.constantInfos.size() -1; + } +} diff --git a/group01/765324639/src/main/java/minijvm/constant/FieldRefInfo.java b/group01/765324639/src/main/java/minijvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..ddcf2df456 --- /dev/null +++ b/group01/765324639/src/main/java/minijvm/constant/FieldRefInfo.java @@ -0,0 +1,56 @@ +package minijvm.constant; + +public class FieldRefInfo extends ConstantInfo{ + private int type = ConstantInfo.FIELD_INFO; + private int classInfoIndex; + private int nameAndTypeIndex; + + public FieldRefInfo(ConstantPool pool) { + super(pool); + } + @Override + public int getType() { + return type; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + @Override + public String toString(){ + + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + + return getClassName() +" : "+ typeInfo.getName() + ":" + typeInfo.getTypeInfo() +"]"; + } + + public String getClassName(){ + + ClassInfo classInfo = (ClassInfo) this.getConstantInfo(this.getClassInfoIndex()); + + UTF8Info utf8Info = (UTF8Info)this.getConstantInfo(classInfo.getUtf8Index()); + + return utf8Info.getValue(); + + } + + public String getFieldName(){ + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getFieldType(){ + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } +} diff --git a/group01/765324639/src/main/java/minijvm/constant/MethodRefInfo.java b/group01/765324639/src/main/java/minijvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..f4c2368228 --- /dev/null +++ b/group01/765324639/src/main/java/minijvm/constant/MethodRefInfo.java @@ -0,0 +1,57 @@ +package minijvm.constant; + +public class MethodRefInfo extends ConstantInfo { + + private int type = ConstantInfo.METHOD_INFO; + + private int classInfoIndex; + private int nameAndTypeIndex; + + public MethodRefInfo(ConstantPool pool) { + super(pool); + } + + @Override + public int getType() { + return type; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + @Override + public String toString(){ + + return getClassName() +" : "+ this.getMethodName() + " : " + this.getParamAndReturnType() ; + } + public String getClassName(){ + ConstantPool pool = this.getConstantPool(); + ClassInfo clzInfo = (ClassInfo)pool.getConstantInfo(this.getClassInfoIndex()); + return clzInfo.getClassName(); + } + + public String getMethodName(){ + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo)pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getParamAndReturnType(){ + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo)pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } + + + +} diff --git a/group01/765324639/src/main/java/minijvm/constant/NameAndTypeInfo.java b/group01/765324639/src/main/java/minijvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..de88422d82 --- /dev/null +++ b/group01/765324639/src/main/java/minijvm/constant/NameAndTypeInfo.java @@ -0,0 +1,47 @@ +package minijvm.constant; + +public class NameAndTypeInfo extends ConstantInfo{ + public int type = ConstantInfo.NAME_AND_TYPE_INFO; + + private int index1; + private int index2; + + public NameAndTypeInfo(ConstantPool pool) { + super(pool); + } + + public int getIndex1() { + return index1; + } + public void setIndex1(int index1) { + this.index1 = index1; + } + public int getIndex2() { + return index2; + } + public void setIndex2(int index2) { + this.index2 = index2; + } + @Override + public int getType() { + return type; + } + + + public String getName(){ + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info1 = (UTF8Info)pool.getConstantInfo(index1); + return utf8Info1.getValue(); + } + + public String getTypeInfo(){ + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info2 = (UTF8Info)pool.getConstantInfo(index2); + return utf8Info2.getValue(); + } + + @Override + public String toString(){ + return "(" + getName() + "," + getTypeInfo()+")"; + } +} diff --git a/group01/765324639/src/main/java/minijvm/constant/NullConstantInfo.java b/group01/765324639/src/main/java/minijvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..88eb702f4b --- /dev/null +++ b/group01/765324639/src/main/java/minijvm/constant/NullConstantInfo.java @@ -0,0 +1,13 @@ +package minijvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo(){ + + } + @Override + public int getType() { + return -1; + } + +} diff --git a/group01/765324639/src/main/java/minijvm/constant/StringInfo.java b/group01/765324639/src/main/java/minijvm/constant/StringInfo.java new file mode 100644 index 0000000000..915652a93c --- /dev/null +++ b/group01/765324639/src/main/java/minijvm/constant/StringInfo.java @@ -0,0 +1,28 @@ +package minijvm.constant; + +public class StringInfo extends ConstantInfo{ + private int type = ConstantInfo.STRING_INFO; + private int index; + public StringInfo(ConstantPool pool) { + super(pool); + } + + @Override + public int getType() { + return type; + } + + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } + + + @Override + public String toString(){ + return this.getConstantPool().getUTF8String(index); + } + +} diff --git a/group01/765324639/src/main/java/minijvm/constant/UTF8Info.java b/group01/765324639/src/main/java/minijvm/constant/UTF8Info.java new file mode 100644 index 0000000000..1af71e8e9c --- /dev/null +++ b/group01/765324639/src/main/java/minijvm/constant/UTF8Info.java @@ -0,0 +1,33 @@ +package minijvm.constant; + +public class UTF8Info extends ConstantInfo{ + private int type = ConstantInfo.UTF8_INFO; + private int length ; + private String value; + public UTF8Info(ConstantPool pool) { + super(pool); + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + @Override + public int getType() { + return type; + } + @Override + public String toString() { + return "UTF8Info [type=" + type + ", length=" + length + ", value=" + value +")]"; + } + public String getValue() { + return value; + } + public void setValue(String value) { + this.value = value; + } + + + +} diff --git a/group01/765324639/src/main/java/minijvm/loader/ByteCodeIterator.java b/group01/765324639/src/main/java/minijvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..24a4db6f27 --- /dev/null +++ b/group01/765324639/src/main/java/minijvm/loader/ByteCodeIterator.java @@ -0,0 +1,47 @@ +package minijvm.loader; + +import java.io.UnsupportedEncodingException; + +import minijvm.util.Util; + +public class ByteCodeIterator { + + private byte[] codes; + + private int pos = 0; + + public ByteCodeIterator (byte[] codes) { + this.codes = codes; + } + + public int nextU1ToInt() { + return Util.byteToInt(new byte[]{codes[pos++]}); + } + + public int nextU2ToInt() { + return Util.byteToInt(new byte[]{codes[pos++], codes[pos++]}); + } + + public String nextU4ToHexString() { + return Util.byteToHexString(new byte[]{codes[pos++], codes[pos++], codes[pos++], codes[pos++]}); + } + + public String nextLengthToString(int length) { + String dest = null; + try { + dest = new String(getBytes(length), "UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return dest; + } + + private byte[] getBytes(int length) { + byte[] b = new byte[length]; + for (int i = 0; i < length; i++) { + b[i] = codes[pos++]; + } + return b; + } + +} diff --git a/group01/765324639/src/main/java/minijvm/loader/ClassFileLoader.java b/group01/765324639/src/main/java/minijvm/loader/ClassFileLoader.java index d814a7f5f9..51bce28f2a 100644 --- a/group01/765324639/src/main/java/minijvm/loader/ClassFileLoader.java +++ b/group01/765324639/src/main/java/minijvm/loader/ClassFileLoader.java @@ -9,6 +9,8 @@ import java.util.ArrayList; import java.util.List; +import minijvm.clz.ClassFile; + public class ClassFileLoader { @@ -64,12 +66,15 @@ public void addClassPath(String path) { clzPaths.add(path); } - - public String getClassPath() { return String.join(";", clzPaths); } - + public ClassFile loadClass(String className) throws ClassNotFoundException { + byte[] codes = this.readBinaryCode(className); + ClassFileParser parser = new ClassFileParser(); + return parser.parse(codes); + + } } diff --git a/group01/765324639/src/main/java/minijvm/loader/ClassFileParser.java b/group01/765324639/src/main/java/minijvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..dc800a211f --- /dev/null +++ b/group01/765324639/src/main/java/minijvm/loader/ClassFileParser.java @@ -0,0 +1,119 @@ +package minijvm.loader; + +import minijvm.clz.AccessFlag; +import minijvm.clz.ClassFile; +import minijvm.clz.ClassIndex; +import minijvm.constant.ClassInfo; +import minijvm.constant.ConstantInfo; +import minijvm.constant.ConstantPool; +import minijvm.constant.FieldRefInfo; +import minijvm.constant.MethodRefInfo; +import minijvm.constant.NameAndTypeInfo; +import minijvm.constant.NullConstantInfo; +import minijvm.constant.StringInfo; +import minijvm.constant.UTF8Info; + +public class ClassFileParser { + + public ClassFile parse(byte[] codes) { + ByteCodeIterator iter = new ByteCodeIterator(codes); + ClassFile classFile = new ClassFile(); + + String magicNumber = iter.nextU4ToHexString(); + if (!"cafebabe".equalsIgnoreCase(magicNumber)) { + return null; + } + + classFile.setMinorVersion(iter.nextU2ToInt()); + classFile.setMajorVersion(iter.nextU2ToInt()); + + ConstantPool pool = parseConstantPool(iter); + classFile.setConstPool(pool); + + classFile.setAccessFlag(parseAccessFlag(iter)); + classFile.setClassIndex(parseClassIndex(iter)); + + return classFile; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + int flag = iter.nextU2ToInt(); + AccessFlag accessFlag = new AccessFlag(flag); + return accessFlag; + } + + private ClassIndex parseClassIndex(ByteCodeIterator iter) { + ClassIndex classIndex = new ClassIndex(); + int thisClassIndex = iter.nextU2ToInt(); + int superClassIndex = iter.nextU2ToInt(); + classIndex.setThisClassIndex(thisClassIndex); + classIndex.setSuperClassIndex(superClassIndex); + return classIndex; + + } + + private ConstantPool parseConstantPool(ByteCodeIterator iter) { + int size = iter.nextU2ToInt(); + System.out.println("ConstantPool size: " + size); + + ConstantPool pool = new ConstantPool(); + pool.addConstantInfo(new NullConstantInfo()); // 添加无效的第0项 + + for (int i = 1; i < size; i++) { + int tag = iter.nextU1ToInt(); + + if (tag == ConstantInfo.UTF8_INFO) { + UTF8Info utf8Info = new UTF8Info(pool); + int length = iter.nextU2ToInt(); + String value = iter.nextLengthToString(length); + utf8Info.setLength(length); + utf8Info.setValue(value); + + pool.addConstantInfo(utf8Info); + } else if (tag == ConstantInfo.CLASS_INFO) { + ClassInfo classInfo = new ClassInfo(pool); + int index = iter.nextU2ToInt(); + classInfo.setUtf8Index(index); + + pool.addConstantInfo(classInfo); + } else if (tag == ConstantInfo.STRING_INFO) { + StringInfo stringInfo = new StringInfo(pool); + int index = iter.nextU2ToInt(); + stringInfo.setIndex(index); + + pool.addConstantInfo(stringInfo); + } else if (tag == ConstantInfo.FIELD_INFO) { + FieldRefInfo fieldRefInfo = new FieldRefInfo(pool); + int classInfoIndex = iter.nextU2ToInt(); + int nameAndTypeIndex = iter.nextU2ToInt(); + fieldRefInfo.setClassInfoIndex(classInfoIndex); + fieldRefInfo.setNameAndTypeIndex(nameAndTypeIndex); + + pool.addConstantInfo(fieldRefInfo); + } else if (tag == ClassInfo.METHOD_INFO) { + MethodRefInfo methodRefInfo = new MethodRefInfo(pool); + int classInfoIndex = iter.nextU2ToInt(); + int nameAndTypeIndex = iter.nextU2ToInt(); + methodRefInfo.setClassInfoIndex(classInfoIndex); + methodRefInfo.setNameAndTypeIndex(nameAndTypeIndex); + + pool.addConstantInfo(methodRefInfo); + } else if (tag == ClassInfo.NAME_AND_TYPE_INFO) { + NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(pool); + int index1 = iter.nextU2ToInt(); + int index2 = iter.nextU2ToInt(); + nameAndTypeInfo.setIndex1(index1); + nameAndTypeInfo.setIndex2(index2); + + pool.addConstantInfo(nameAndTypeInfo); + } else { + throw new RuntimeException("这个类型的常量还没有实现"); + } + + } + + return pool; + } + + +} diff --git a/group01/765324639/src/main/java/minijvm/loader/MyTest.java b/group01/765324639/src/main/java/minijvm/loader/MyTest.java deleted file mode 100644 index 1aa536bdf1..0000000000 --- a/group01/765324639/src/main/java/minijvm/loader/MyTest.java +++ /dev/null @@ -1,10 +0,0 @@ -package minijvm.loader; - -import java.io.File; - -public class MyTest { - - public static void main(String[] args) { - System.out.println(new File(".").getAbsolutePath()); - } -} diff --git a/group01/765324639/src/main/java/minijvm/util/Util.java b/group01/765324639/src/main/java/minijvm/util/Util.java new file mode 100644 index 0000000000..e6370a4997 --- /dev/null +++ b/group01/765324639/src/main/java/minijvm/util/Util.java @@ -0,0 +1,24 @@ +package minijvm.util; + +public class Util { + public static int byteToInt(byte[] codes){ + String s1 = byteToHexString(codes); + return Integer.valueOf(s1, 16).intValue(); + } + + + + public static String byteToHexString(byte[] codes ){ + StringBuffer buffer = new StringBuffer(); + for(int i=0;i", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(10); + Assert.assertEquals("(Ljava/lang/String;I)V", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(11); + Assert.assertEquals("Code", utf8Info.getValue()); + } + + { + MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(12); + Assert.assertEquals(3, methodRef.getClassInfoIndex()); + Assert.assertEquals(13, methodRef.getNameAndTypeIndex()); + } + + { + NameAndTypeInfo nameAndType = (NameAndTypeInfo) pool.getConstantInfo(13); + Assert.assertEquals(9, nameAndType.getIndex1()); + Assert.assertEquals(14, nameAndType.getIndex2()); + } + //抽查几个吧 + { + MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(45); + Assert.assertEquals(1, methodRef.getClassInfoIndex()); + Assert.assertEquals(46, methodRef.getNameAndTypeIndex()); + } + + { + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(53); + Assert.assertEquals("EmployeeV1.java", utf8Info.getValue()); + } + } + @Test + public void testClassIndex(){ + + ClassIndex clzIndex = clzFile.getClzIndex(); + ClassInfo thisClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getThisClassIndex()); + ClassInfo superClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getSuperClassIndex()); + + + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); + Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); + } } diff --git a/group01/765324639/src/main/java/minijvm/loader/EmployeeV1.java b/group01/765324639/src/test/java/minijvm/loader/EmployeeV1.java similarity index 94% rename from group01/765324639/src/main/java/minijvm/loader/EmployeeV1.java rename to group01/765324639/src/test/java/minijvm/loader/EmployeeV1.java index 2c07ee7fb7..e501762cc4 100644 --- a/group01/765324639/src/main/java/minijvm/loader/EmployeeV1.java +++ b/group01/765324639/src/test/java/minijvm/loader/EmployeeV1.java @@ -2,7 +2,6 @@ public class EmployeeV1 { - private String name; private int age; From 4f15d263469d0f31d0d1564700f9b71ecca0f8bb Mon Sep 17 00:00:00 2001 From: zheng <765324639@qq.com> Date: Sat, 8 Apr 2017 11:11:47 +0800 Subject: [PATCH 076/203] =?UTF-8?q?=E8=B0=83=E6=95=B4.gitignore=E6=96=87?= =?UTF-8?q?=E4=BB=B6=EF=BC=8C=E4=BD=BF=E5=85=B6=E4=B8=8D=E5=BF=BD=E7=95=A5?= =?UTF-8?q?xml=E6=96=87=E4=BB=B6=EF=BC=8C=E5=B9=B6=E8=A1=A5=E4=B8=8A?= =?UTF-8?q?=E4=B9=8B=E5=89=8D=E6=9C=AA=E6=8F=90=E4=BA=A4=E4=B8=8A=E7=9A=84?= =?UTF-8?q?xml=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group01/765324639/pom.xml | 18 ++++++++++++++++++ .../src/main/java/litestruts/struts.xml | 11 +++++++++++ 2 files changed, 29 insertions(+) create mode 100644 group01/765324639/pom.xml create mode 100644 group01/765324639/src/main/java/litestruts/struts.xml diff --git a/group01/765324639/pom.xml b/group01/765324639/pom.xml new file mode 100644 index 0000000000..24816f0f3f --- /dev/null +++ b/group01/765324639/pom.xml @@ -0,0 +1,18 @@ + + 4.0.0 + com.zavier + 765324639Learning + 0.0.1-SNAPSHOT + + + junit + junit + 4.12 + + + dom4j + dom4j + 1.6.1 + + + \ No newline at end of file diff --git a/group01/765324639/src/main/java/litestruts/struts.xml b/group01/765324639/src/main/java/litestruts/struts.xml new file mode 100644 index 0000000000..a7eccffd9c --- /dev/null +++ b/group01/765324639/src/main/java/litestruts/struts.xml @@ -0,0 +1,11 @@ + + + + /jsp/homepage.jsp + /jsp/showLogin.jsp + + + /jsp/welcome.jsp + /jsp/error.jsp + + \ No newline at end of file From a2930e3e1916362e020b1afb3ea867ecf24c2701 Mon Sep 17 00:00:00 2001 From: OnlyLYJ <382266293@qq.com> Date: Sat, 8 Apr 2017 18:06:03 +0800 Subject: [PATCH 077/203] stack done --- .../basic/collection/concrete/ArrayList.java | 1 + .../coding/basic/linklist/LRUPageFrame.java | 3 + .../coding/basic/stack/StackUtil.java | 140 ++++++++++++++++++ .../coding/basic/stack/StackUtilTest.java | 85 +++++++++++ 4 files changed, 229 insertions(+) create mode 100644 group12/382266293/coding/basic/stack/StackUtil.java create mode 100644 group12/382266293/coding/basic/stack/StackUtilTest.java diff --git a/group12/382266293/coding/basic/collection/concrete/ArrayList.java b/group12/382266293/coding/basic/collection/concrete/ArrayList.java index 3eeca56fee..71accca366 100644 --- a/group12/382266293/coding/basic/collection/concrete/ArrayList.java +++ b/group12/382266293/coding/basic/collection/concrete/ArrayList.java @@ -70,6 +70,7 @@ public void addLast(E e) { } public E removeLast() { + checkIndex(size); return elements[--size]; } diff --git a/group12/382266293/coding/basic/linklist/LRUPageFrame.java b/group12/382266293/coding/basic/linklist/LRUPageFrame.java index dec3ecc464..df8de37c68 100644 --- a/group12/382266293/coding/basic/linklist/LRUPageFrame.java +++ b/group12/382266293/coding/basic/linklist/LRUPageFrame.java @@ -152,7 +152,10 @@ private Node findNode(int pageNum) { return null; } + public static void main(String[] args) { + + } public String toString(){ StringBuilder buffer = new StringBuilder(); diff --git a/group12/382266293/coding/basic/stack/StackUtil.java b/group12/382266293/coding/basic/stack/StackUtil.java new file mode 100644 index 0000000000..706bcd7033 --- /dev/null +++ b/group12/382266293/coding/basic/stack/StackUtil.java @@ -0,0 +1,140 @@ +package stack; + +import static org.junit.Assert.assertEquals; + +import java.util.Objects; +import java.util.Stack; + +public class StackUtil { + + /** + * 假设栈中的元素是Integer, 从栈顶到栈底是 : 5,4,3,2,1 调用该方法后, 元素次序变为: 1,2,3,4,5 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + */ + public static void reverse(Stack stack) { + if (stack.isEmpty()) { + return; + } + int i = getAndRemoveLastElement(stack); + reverse(stack); + stack.push(i); + } + + public static int getAndRemoveLastElement(Stack stack) { + int result = stack.pop(); + if (stack.isEmpty()) { + return result; + } else { + int last = getAndRemoveLastElement(stack); + stack.push(result); + return last; + } + } + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s, Object o) { + if (s.isEmpty()) { + return; + } + Stack s2 = new Stack(); + while (s.peek() != null) { + if (!Objects.equals(o, s.peek())) { + s2.push(s.pop()); + } else { + s.pop(); + break; + } + } + while (!s2.isEmpty()) { + s.push(s2.pop()); + } + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, + * 可以使用另外一个栈来辅助 + * + * @param len + * @return + */ + public static Object[] getTop(Stack s, int len) { + if (s.isEmpty()) { + return new Object[0]; + } + + int len1 = (s.size() < len) ? s.size() : len; + + Object[] result = new Object[len1]; + Stack s2 = new Stack(); + Object o = null; + for (int i = 0; i < len1; i++) { + o = s.pop(); + result[i] = o; + s2.push(o); + } + while (!s2.isEmpty()) { + s.push(s2.pop()); + } + + return result; + } + + /** + * 字符串s 可能包含这些字符: ( ) [ ] { }, a,b,c... x,yz 使用堆栈检查字符串s中的括号是不是成对出现的。 例如s = + * "([e{d}f])" , 则该字符串中的括号是成对出现, 该方法返回true 如果 s = "([b{x]y})", + * 则该字符串中的括号不是成对出现的, 该方法返回false; + * + * @param s + * @return + */ + public static boolean isValidPairs(String s) { + if (s.length() == 0) { + return false; + } + + Stack s2 = new Stack(); + for (int i = 0; i < s.length(); i++) { + char c1 = s.charAt(i); + if (c1 != ')' && c1 != ']' && c1 != '}') { + s2.push(c1); + } else { + char c2 = getOpChar(s2); + if (!isPair(c1, c2)) { + return false; + } + } + } + + return true; + } + + private static boolean isPair(char c1, char c2) { + if (c1 == ')' && c2 == '(') { + return true; + } + + if (c1 == ']' && c2 == '[') { + return true; + } + + if (c1 == '}' && c2 == '{') { + return true; + } + + return false; + } + + private static char getOpChar(Stack s2) { + char c2 = s2.pop(); + while (c2 != ')' && c2 != ']' && c2 != '}' && + c2 != '(' && c2 != '[' && c2 != '{' && !s2.isEmpty()) { + c2 = s2.pop(); + } + return c2; + } + +} diff --git a/group12/382266293/coding/basic/stack/StackUtilTest.java b/group12/382266293/coding/basic/stack/StackUtilTest.java new file mode 100644 index 0000000000..9180c4816e --- /dev/null +++ b/group12/382266293/coding/basic/stack/StackUtilTest.java @@ -0,0 +1,85 @@ +package stack; + +import static org.junit.Assert.*; + +import java.util.Arrays; +import java.util.Stack; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + + +public class StackUtilTest { + + Stack s; + @Before + public void setUp() throws Exception { + s = new Stack(); + } + + @After + public void tearDown() throws Exception { + s = null; + } + + @Test + public void testReverse() { + for(int i = 5; i >= 1; i--) { + s.push(i); + } + + StackUtil.reverse(s); + assertEquals(s.toString(),"[1, 2, 3, 4, 5]"); + + } + + @Test + public void testRemove() { + for(int i = 5; i >= 1; i--) { + s.push(i); + } + + StackUtil.remove(s,2); + assertEquals(s.toString(),"[5, 4, 3, 1]"); + + StackUtil.remove(s,5); + assertEquals(s.toString(),"[4, 3, 1]"); + + StackUtil.remove(s,1); + assertEquals(s.toString(),"[4, 3]"); + + s = new Stack(); + assertEquals(s.toString(),"[]"); + } + + @Test + public void testGetTop() { + for(int i = 5; i >= 1; i--) { + s.push(i); + } + + Object[] o = StackUtil.getTop(s,2); + + assertEquals(s.toString(),"[5, 4, 3, 2, 1]"); + assertEquals(Arrays.toString(o),"[1, 2]"); + + o = StackUtil.getTop(s,6); + assertEquals(Arrays.toString(o),"[1, 2, 3, 4, 5]"); + + o = StackUtil.getTop(s,0); + assertEquals(Arrays.toString(o),"[]"); + } + + @Test + public void testIsValidPairs() { + + String s1 = "([e{d}f])"; + assertEquals(true,StackUtil.isValidPairs(s1)); + + s1 = "([b{x]y})"; + assertEquals(false,StackUtil.isValidPairs(s1)); + + } + +} From bc287a6bce510371321a59cd5597ab4f5e2f66a7 Mon Sep 17 00:00:00 2001 From: wa122as Date: Sat, 8 Apr 2017 20:42:40 +0800 Subject: [PATCH 078/203] =?UTF-8?q?=E7=AC=AC=E5=9B=9B=E6=AC=A1=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A=E8=A1=A5=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/task4/jvm/loader/ClassFileLoader.java | 51 +++++ .../task4/jvm/test/ClassFileloaderTest.java | 84 ++++++++ .../src/task4/jvm/test/EmployeeV1.java | 28 +++ .../src/task4/linklist/LRUPageFrame.java | 157 ++++++++++++++ .../src/task4/linklist/LRUPageFrameTest.java | 34 +++ .../src/task5/jvm/clz/AccessFlag.java | 25 +++ .../src/task5/jvm/clz/ClassFile.java | 76 +++++++ .../src/task5/jvm/clz/ClassIndex.java | 19 ++ .../src/task5/jvm/constant/ClassInfo.java | 24 +++ .../src/task5/jvm/constant/ConstantInfo.java | 29 +++ .../src/task5/jvm/constant/ConstantPool.java | 29 +++ .../src/task5/jvm/constant/FieldRefInfo.java | 54 +++++ .../src/task5/jvm/constant/MethodRefInfo.java | 55 +++++ .../task5/jvm/constant/NameAndTypeInfo.java | 45 ++++ .../task5/jvm/constant/NullConstantInfo.java | 13 ++ .../src/task5/jvm/constant/StringInfo.java | 26 +++ .../src/task5/jvm/constant/UTF8Info.java | 32 +++ .../task5/jvm/loader/ByteCodeIterator.java | 5 + .../src/task5/jvm/loader/ClassFileLoader.java | 132 ++++++++++++ .../src/task5/jvm/loader/ClassFileParser.java | 38 ++++ .../task5/jvm/test/ClassFileloaderTest.java | 194 ++++++++++++++++++ .../src/task5/jvm/test/EmployeeV1.java | 28 +++ .../src/task5/jvm/util/Util.java | 24 +++ 23 files changed, 1202 insertions(+) create mode 100644 group15/1521_653895972/src/task4/jvm/loader/ClassFileLoader.java create mode 100644 group15/1521_653895972/src/task4/jvm/test/ClassFileloaderTest.java create mode 100644 group15/1521_653895972/src/task4/jvm/test/EmployeeV1.java create mode 100644 group15/1521_653895972/src/task4/linklist/LRUPageFrame.java create mode 100644 group15/1521_653895972/src/task4/linklist/LRUPageFrameTest.java create mode 100644 group15/1521_653895972/src/task5/jvm/clz/AccessFlag.java create mode 100644 group15/1521_653895972/src/task5/jvm/clz/ClassFile.java create mode 100644 group15/1521_653895972/src/task5/jvm/clz/ClassIndex.java create mode 100644 group15/1521_653895972/src/task5/jvm/constant/ClassInfo.java create mode 100644 group15/1521_653895972/src/task5/jvm/constant/ConstantInfo.java create mode 100644 group15/1521_653895972/src/task5/jvm/constant/ConstantPool.java create mode 100644 group15/1521_653895972/src/task5/jvm/constant/FieldRefInfo.java create mode 100644 group15/1521_653895972/src/task5/jvm/constant/MethodRefInfo.java create mode 100644 group15/1521_653895972/src/task5/jvm/constant/NameAndTypeInfo.java create mode 100644 group15/1521_653895972/src/task5/jvm/constant/NullConstantInfo.java create mode 100644 group15/1521_653895972/src/task5/jvm/constant/StringInfo.java create mode 100644 group15/1521_653895972/src/task5/jvm/constant/UTF8Info.java create mode 100644 group15/1521_653895972/src/task5/jvm/loader/ByteCodeIterator.java create mode 100644 group15/1521_653895972/src/task5/jvm/loader/ClassFileLoader.java create mode 100644 group15/1521_653895972/src/task5/jvm/loader/ClassFileParser.java create mode 100644 group15/1521_653895972/src/task5/jvm/test/ClassFileloaderTest.java create mode 100644 group15/1521_653895972/src/task5/jvm/test/EmployeeV1.java create mode 100644 group15/1521_653895972/src/task5/jvm/util/Util.java diff --git a/group15/1521_653895972/src/task4/jvm/loader/ClassFileLoader.java b/group15/1521_653895972/src/task4/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..cdecffed32 --- /dev/null +++ b/group15/1521_653895972/src/task4/jvm/loader/ClassFileLoader.java @@ -0,0 +1,51 @@ +package task4.jvm.loader; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + + + +public class ClassFileLoader { + + private List clzPaths = new ArrayList(); + + public byte[] readBinaryCode(String className) throws Exception { + URL base = this.getClass().getResource("/"); + String baseToString = ""+base; + String filePath = baseToString.replaceAll("file:/", "")+className.replace(".", "\\")+".class"; + //String filePath = clzPaths.get(0)+"\\"+className.replace(".", "\\")+".class"; //符合Junit测试调用addClassPath方法 + File file = new File(filePath); + + BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + byte[] buffer = new byte[1024]; + int len = 0; + while((len = bis.read(buffer)) != -1){ + baos.write(buffer,0,len); + } + return baos.toByteArray(); + } + + public void addClassPath(String path) { + clzPaths.add(path); + } + + public String getClassPath(){ + StringBuffer strBuffer = new StringBuffer(); + for(int i=0;i= capacity) { + removeLast(); + + } + + addNewNodetoHead(node); + + + } + } + + private void addNewNodetoHead(Node node) { + + if (isEmpty()) { + + node.prev = null; + node.next = null; + first = node; + last = node; + + } else { + node.prev = null; + node.next = first; + first.prev = node; + first = node; + } + this.currentSize++; + } + + private Node find(int data) { + + Node node = first; + while (node != null) { + if (node.pageNum == data) { + return node; + } + node = node.next; + } + return null; + + } + + + /** + * 删除链表尾部节点 表示 删除最少使用的缓存对象 + */ + private void removeLast() { + Node prev = last.prev; + prev.next = null; + last.prev = null; + last = prev; + this.currentSize--; + } + + /** + * 移动到链表头,表示这个节点是最新使用过的 + * + * @param node + */ + private void moveExistingNodeToHead(Node node) { + + if (node == first) { + + return; + } else if (node == last) { + //当前节点是链表尾, 需要放到链表头 + Node prevNode = node.prev; + prevNode.next = null; + last.prev = null; + last = prevNode; + + } else { + //node 在链表的中间, 把node 的前后节点连接起来 + Node prevNode = node.prev; + prevNode.next = node.next; + + Node nextNode = node.next; + nextNode.prev = prevNode; + + + } + + node.prev = null; + node.next = first; + first.prev = node; + first = node; + + } + + private boolean isEmpty() { + return (first == null) && (last == null); + } + + public String toString() { + StringBuilder buffer = new StringBuilder(); + Node node = first; + while (node != null) { + buffer.append(node.pageNum); + + node = node.next; + if (node != null) { + buffer.append(","); + } + } + return buffer.toString(); + } + + +} diff --git a/group15/1521_653895972/src/task4/linklist/LRUPageFrameTest.java b/group15/1521_653895972/src/task4/linklist/LRUPageFrameTest.java new file mode 100644 index 0000000000..5ebfe09c0f --- /dev/null +++ b/group15/1521_653895972/src/task4/linklist/LRUPageFrameTest.java @@ -0,0 +1,34 @@ +package task4.linklist; + +import org.junit.Assert; + +import org.junit.Test; + + +public class LRUPageFrameTest { + + @Test + public void testAccess() { + LRUPageFrame frame = new LRUPageFrame(3); + frame.access(7); + frame.access(0); + frame.access(1); + Assert.assertEquals("1,0,7", frame.toString()); + frame.access(2); + Assert.assertEquals("2,1,0", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(3); + Assert.assertEquals("3,0,2", frame.toString()); + frame.access(0); + Assert.assertEquals("0,3,2", frame.toString()); + frame.access(4); + Assert.assertEquals("4,0,3", frame.toString()); + frame.access(5); + Assert.assertEquals("5,4,0", frame.toString()); + System.out.println("3232"); + } + +} diff --git a/group15/1521_653895972/src/task5/jvm/clz/AccessFlag.java b/group15/1521_653895972/src/task5/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..65e98c15e6 --- /dev/null +++ b/group15/1521_653895972/src/task5/jvm/clz/AccessFlag.java @@ -0,0 +1,25 @@ +package task5.jvm.clz; + +public class AccessFlag { + private int flagValue; + + public AccessFlag(int value) { + this.flagValue = value; + } + + public int getFlagValue() { + return flagValue; + } + + public void setFlagValue(int flag) { + this.flagValue = flag; + } + + public boolean isPublicClass(){ + return (this.flagValue & 0x0001) != 0; + } + public boolean isFinalClass(){ + return (this.flagValue & 0x0010) != 0; + } + +} \ No newline at end of file diff --git a/group15/1521_653895972/src/task5/jvm/clz/ClassFile.java b/group15/1521_653895972/src/task5/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..5e60ab4b81 --- /dev/null +++ b/group15/1521_653895972/src/task5/jvm/clz/ClassFile.java @@ -0,0 +1,76 @@ +package task5.jvm.clz; + + +import task5.jvm.constant.ClassInfo; +import task5.jvm.constant.ConstantPool; + +public class ClassFile { + + private int minorVersion; + private int majorVersion; + + private AccessFlag accessFlag; + private ClassIndex clzIndex; + private ConstantPool pool; + + + public ClassIndex getClzIndex() { + return clzIndex; + } + public AccessFlag getAccessFlag() { + return accessFlag; + } + public void setAccessFlag(AccessFlag accessFlag) { + this.accessFlag = accessFlag; + } + + + + public ConstantPool getConstantPool() { + return pool; + } + public int getMinorVersion() { + return minorVersion; + } + public void setMinorVersion(int minorVersion) { + this.minorVersion = minorVersion; + } + public int getMajorVersion() { + return majorVersion; + } + public void setMajorVersion(int majorVersion) { + this.majorVersion = majorVersion; + } + public void setConstPool(ConstantPool pool) { + this.pool = pool; + + } + public void setClassIndex(ClassIndex clzIndex) { + this.clzIndex = clzIndex; + } + + + + + public void print(){ + + if(this.accessFlag.isPublicClass()){ + System.out.println("Access flag : public "); + } + System.out.println("Class Name:"+ getClassName()); + + System.out.println("Super Class Name:"+ getSuperClassName()); + + + } + + private String getClassName(){ + int thisClassIndex = this.clzIndex.getThisClassIndex(); + ClassInfo thisClass = (ClassInfo)this.getConstantPool().getConstantInfo(thisClassIndex); + return thisClass.getClassName(); + } + private String getSuperClassName(){ + ClassInfo superClass = (ClassInfo)this.getConstantPool().getConstantInfo(this.clzIndex.getSuperClassIndex()); + return superClass.getClassName(); + } +} diff --git a/group15/1521_653895972/src/task5/jvm/clz/ClassIndex.java b/group15/1521_653895972/src/task5/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..5aba6a953a --- /dev/null +++ b/group15/1521_653895972/src/task5/jvm/clz/ClassIndex.java @@ -0,0 +1,19 @@ +package task5.jvm.clz; + +public class ClassIndex { + private int thisClassIndex; + private int superClassIndex; + + public int getThisClassIndex() { + return thisClassIndex; + } + public void setThisClassIndex(int thisClassIndex) { + this.thisClassIndex = thisClassIndex; + } + public int getSuperClassIndex() { + return superClassIndex; + } + public void setSuperClassIndex(int superClassIndex) { + this.superClassIndex = superClassIndex; + } +} \ No newline at end of file diff --git a/group15/1521_653895972/src/task5/jvm/constant/ClassInfo.java b/group15/1521_653895972/src/task5/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..6f8e5229cc --- /dev/null +++ b/group15/1521_653895972/src/task5/jvm/constant/ClassInfo.java @@ -0,0 +1,24 @@ +package task5.jvm.constant; + +public class ClassInfo extends ConstantInfo { + private int type = ConstantInfo.CLASS_INFO; + private int utf8Index ; + public ClassInfo(ConstantPool pool) { + super(pool); + } + public int getUtf8Index() { + return utf8Index; + } + public void setUtf8Index(int utf8Index) { + this.utf8Index = utf8Index; + } + public int getType() { + return type; + } + + public String getClassName() { + int index = getUtf8Index(); + UTF8Info utf8Info = (UTF8Info)constantPool.getConstantInfo(index); + return utf8Info.getValue(); + } +} diff --git a/group15/1521_653895972/src/task5/jvm/constant/ConstantInfo.java b/group15/1521_653895972/src/task5/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..3e00cd378c --- /dev/null +++ b/group15/1521_653895972/src/task5/jvm/constant/ConstantInfo.java @@ -0,0 +1,29 @@ +package task5.jvm.constant; + +public abstract class ConstantInfo { + public static final int UTF8_INFO = 1; + public static final int FLOAT_INFO = 4; + public static final int CLASS_INFO = 7; + public static final int STRING_INFO = 8; + public static final int FIELD_INFO = 9; + public static final int METHOD_INFO = 10; + public static final int NAME_AND_TYPE_INFO = 12; + protected ConstantPool constantPool; + + public ConstantInfo(){ + + } + + public ConstantInfo(ConstantPool pool) { + this.constantPool = pool; + } + public abstract int getType(); + + public ConstantPool getConstantPool() { + return constantPool; + } + public ConstantInfo getConstantInfo(int index){ + return this.constantPool.getConstantInfo(index); + } + +} diff --git a/group15/1521_653895972/src/task5/jvm/constant/ConstantPool.java b/group15/1521_653895972/src/task5/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..eb6eb2b692 --- /dev/null +++ b/group15/1521_653895972/src/task5/jvm/constant/ConstantPool.java @@ -0,0 +1,29 @@ +package task5.jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List constantInfos = new ArrayList(); + + + public ConstantPool(){ + + } + public void addConstantInfo(ConstantInfo info){ + + this.constantInfos.add(info); + + } + + public ConstantInfo getConstantInfo(int index){ + return this.constantInfos.get(index); + } + public String getUTF8String(int index){ + return ((UTF8Info)this.constantInfos.get(index)).getValue(); + } + public Object getSize() { + return this.constantInfos.size() -1; + } +} diff --git a/group15/1521_653895972/src/task5/jvm/constant/FieldRefInfo.java b/group15/1521_653895972/src/task5/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..957d882b7a --- /dev/null +++ b/group15/1521_653895972/src/task5/jvm/constant/FieldRefInfo.java @@ -0,0 +1,54 @@ +package task5.jvm.constant; + +public class FieldRefInfo extends ConstantInfo{ + private int type = ConstantInfo.FIELD_INFO; + private int classInfoIndex; + private int nameAndTypeIndex; + + public FieldRefInfo(ConstantPool pool) { + super(pool); + } + public int getType() { + return type; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String toString(){ + + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + + return getClassName() +" : "+ typeInfo.getName() + ":" + typeInfo.getTypeInfo() +"]"; + } + + public String getClassName(){ + + ClassInfo classInfo = (ClassInfo) this.getConstantInfo(this.getClassInfoIndex()); + + UTF8Info utf8Info = (UTF8Info)this.getConstantInfo(classInfo.getUtf8Index()); + + return utf8Info.getValue(); + + } + + public String getFieldName(){ + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getFieldType(){ + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } +} diff --git a/group15/1521_653895972/src/task5/jvm/constant/MethodRefInfo.java b/group15/1521_653895972/src/task5/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..2a25d2cbee --- /dev/null +++ b/group15/1521_653895972/src/task5/jvm/constant/MethodRefInfo.java @@ -0,0 +1,55 @@ +package task5.jvm.constant; + +public class MethodRefInfo extends ConstantInfo { + + private int type = ConstantInfo.METHOD_INFO; + + private int classInfoIndex; + private int nameAndTypeIndex; + + public MethodRefInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String toString(){ + + return getClassName() +" : "+ this.getMethodName() + " : " + this.getParamAndReturnType() ; + } + public String getClassName(){ + ConstantPool pool = this.getConstantPool(); + ClassInfo clzInfo = (ClassInfo)pool.getConstantInfo(this.getClassInfoIndex()); + return clzInfo.getClassName(); + } + + public String getMethodName(){ + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo)pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getParamAndReturnType(){ + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo)pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } + + + +} diff --git a/group15/1521_653895972/src/task5/jvm/constant/NameAndTypeInfo.java b/group15/1521_653895972/src/task5/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..e3a65591f1 --- /dev/null +++ b/group15/1521_653895972/src/task5/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,45 @@ +package task5.jvm.constant; + +public class NameAndTypeInfo extends ConstantInfo{ + public int type = ConstantInfo.NAME_AND_TYPE_INFO; + + private int index1; + private int index2; + + public NameAndTypeInfo(ConstantPool pool) { + super(pool); + } + + public int getIndex1() { + return index1; + } + public void setIndex1(int index1) { + this.index1 = index1; + } + public int getIndex2() { + return index2; + } + public void setIndex2(int index2) { + this.index2 = index2; + } + public int getType() { + return type; + } + + + public String getName(){ + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info1 = (UTF8Info)pool.getConstantInfo(index1); + return utf8Info1.getValue(); + } + + public String getTypeInfo(){ + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info2 = (UTF8Info)pool.getConstantInfo(index2); + return utf8Info2.getValue(); + } + + public String toString(){ + return "(" + getName() + "," + getTypeInfo()+")"; + } +} diff --git a/group15/1521_653895972/src/task5/jvm/constant/NullConstantInfo.java b/group15/1521_653895972/src/task5/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..a8895facd3 --- /dev/null +++ b/group15/1521_653895972/src/task5/jvm/constant/NullConstantInfo.java @@ -0,0 +1,13 @@ +package task5.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo(){ + + } + @Override + public int getType() { + return -1; + } + +} diff --git a/group15/1521_653895972/src/task5/jvm/constant/StringInfo.java b/group15/1521_653895972/src/task5/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..509a008b1d --- /dev/null +++ b/group15/1521_653895972/src/task5/jvm/constant/StringInfo.java @@ -0,0 +1,26 @@ +package task5.jvm.constant; + +public class StringInfo extends ConstantInfo{ + private int type = ConstantInfo.STRING_INFO; + private int index; + public StringInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } + + + public String toString(){ + return this.getConstantPool().getUTF8String(index); + } + +} diff --git a/group15/1521_653895972/src/task5/jvm/constant/UTF8Info.java b/group15/1521_653895972/src/task5/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..05aec836eb --- /dev/null +++ b/group15/1521_653895972/src/task5/jvm/constant/UTF8Info.java @@ -0,0 +1,32 @@ +package task5.jvm.constant; + +public class UTF8Info extends ConstantInfo{ + private int type = ConstantInfo.UTF8_INFO; + private int length ; + private String value; + public UTF8Info(ConstantPool pool) { + super(pool); + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getType() { + return type; + } + @Override + public String toString() { + return "UTF8Info [type=" + type + ", length=" + length + ", value=" + value +")]"; + } + public String getValue() { + return value; + } + public void setValue(String value) { + this.value = value; + } + + + +} diff --git a/group15/1521_653895972/src/task5/jvm/loader/ByteCodeIterator.java b/group15/1521_653895972/src/task5/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..20e12c3503 --- /dev/null +++ b/group15/1521_653895972/src/task5/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,5 @@ +package task5.jvm.loader; + +public class ByteCodeIterator { + +} diff --git a/group15/1521_653895972/src/task5/jvm/loader/ClassFileLoader.java b/group15/1521_653895972/src/task5/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..3778d22280 --- /dev/null +++ b/group15/1521_653895972/src/task5/jvm/loader/ClassFileLoader.java @@ -0,0 +1,132 @@ +package task5.jvm.loader; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import task5.jvm.clz.ClassFile; + +import java.io.*; +import java.util.ArrayList; +import java.util.List; + + +public class ClassFileLoader { + + private List clzPaths = new ArrayList(); + + public byte[] readBinaryCode(String className) { + + className = className.replace('.', File.separatorChar) +".class"; + + for(String path : this.clzPaths){ + + String clzFileName = path + File.separatorChar + className; + byte[] codes = loadClassFile(clzFileName); + if(codes != null){ + return codes; + } + } + + return null; + + + + } + + private byte[] loadClassFile(String clzFileName) { + + File f = new File(clzFileName); + + try { + + return IOUtils.toByteArray(new FileInputStream(f)); + + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + + + public void addClassPath(String path) { + if(this.clzPaths.contains(path)){ + return; + } + + this.clzPaths.add(path); + + } + + + + public String getClassPath(){ + return StringUtils.join(this.clzPaths,";"); + } + + public ClassFile loadClass(String className) { + byte[] codes = this.readBinaryCode(className); + ClassFileParser parser = new ClassFileParser(); + return parser.parse(codes); + + } + + + + // ------------------------------backup------------------------ + public String getClassPath_V1(){ + + StringBuffer buffer = new StringBuffer(); + for(int i=0;i", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(10); + Assert.assertEquals("(Ljava/lang/String;I)V", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(11); + Assert.assertEquals("Code", utf8Info.getValue()); + } + + { + MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(12); + Assert.assertEquals(3, methodRef.getClassInfoIndex()); + Assert.assertEquals(13, methodRef.getNameAndTypeIndex()); + } + + { + NameAndTypeInfo nameAndType = (NameAndTypeInfo) pool.getConstantInfo(13); + Assert.assertEquals(9, nameAndType.getIndex1()); + Assert.assertEquals(14, nameAndType.getIndex2()); + } + //抽查几个吧 + { + MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(45); + Assert.assertEquals(1, methodRef.getClassInfoIndex()); + Assert.assertEquals(46, methodRef.getNameAndTypeIndex()); + } + + { + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(53); + Assert.assertEquals("EmployeeV1.java", utf8Info.getValue()); + } + } + @Test + public void testClassIndex(){ + + ClassIndex clzIndex = clzFile.getClzIndex(); + ClassInfo thisClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getThisClassIndex()); + ClassInfo superClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getSuperClassIndex()); + + + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); + Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); + } + + + +} diff --git a/group15/1521_653895972/src/task5/jvm/test/EmployeeV1.java b/group15/1521_653895972/src/task5/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..21d20a053c --- /dev/null +++ b/group15/1521_653895972/src/task5/jvm/test/EmployeeV1.java @@ -0,0 +1,28 @@ +package task5.jvm.test; + +public class EmployeeV1 { + + + private String name; + private int age; + + public EmployeeV1(String name, int age) { + this.name = name; + this.age = age; + } + + public void setName(String name) { + this.name = name; + } + public void setAge(int age){ + this.age = age; + } + public void sayHello() { + System.out.println("Hello , this is class Employee "); + } + public static void main(String[] args){ + EmployeeV1 p = new EmployeeV1("Andy",29); + p.sayHello(); + + } +} \ No newline at end of file diff --git a/group15/1521_653895972/src/task5/jvm/util/Util.java b/group15/1521_653895972/src/task5/jvm/util/Util.java new file mode 100644 index 0000000000..d274eacc08 --- /dev/null +++ b/group15/1521_653895972/src/task5/jvm/util/Util.java @@ -0,0 +1,24 @@ +package task5.jvm.util; + +public class Util { + public static int byteToInt(byte[] codes){ + String s1 = byteToHexString(codes); + return Integer.valueOf(s1, 16).intValue(); + } + + + + public static String byteToHexString(byte[] codes ){ + StringBuffer buffer = new StringBuffer(); + for(int i=0;i Date: Sat, 8 Apr 2017 21:00:57 +0800 Subject: [PATCH 079/203] =?UTF-8?q?400=E5=A4=9A=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group11/1178243325/week06/build.gradle | 13 ++++ group11/1178243325/week06/readme.md | 11 +++ .../com/sprint/jvm/clz/.ClassIndex.java.swp | Bin 0 -> 12288 bytes .../java/com/sprint/jvm/clz/AccessFlag.java | 25 ++++++ .../java/com/sprint/jvm/clz/ClassFile.java | 71 ++++++++++++++++++ .../java/com/sprint/jvm/clz/ClassIndex.java | 22 ++++++ .../com/sprint/jvm/constant/ClassInfo.java | 28 +++++++ .../com/sprint/jvm/constant/ConstantInfo.java | 29 +++++++ .../com/sprint/jvm/constant/ConstantPool.java | 28 +++++++ .../com/sprint/jvm/constant/UTF8Info.java | 35 +++++++++ .../sprint/jvm/loader/ByteCodeIterator.java | 5 ++ .../sprint/jvm/loader/ClassFileLoader.java | 52 +++++++++++++ .../sprint/jvm/loader/ClassFileParser.java | 25 ++++++ .../jvm/loader/ClassFileLoaderTest.java | 20 +++++ .../com/sprint/jvm/loader/EmployeeV1.java | 28 +++++++ 15 files changed, 392 insertions(+) create mode 100644 group11/1178243325/week06/build.gradle create mode 100644 group11/1178243325/week06/readme.md create mode 100644 group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/.ClassIndex.java.swp create mode 100644 group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/AccessFlag.java create mode 100644 group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/ClassFile.java create mode 100644 group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/ClassIndex.java create mode 100644 group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/ClassInfo.java create mode 100644 group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/ConstantInfo.java create mode 100644 group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/ConstantPool.java create mode 100644 group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/UTF8Info.java create mode 100644 group11/1178243325/week06/src/main/java/com/sprint/jvm/loader/ByteCodeIterator.java create mode 100644 group11/1178243325/week06/src/main/java/com/sprint/jvm/loader/ClassFileLoader.java create mode 100644 group11/1178243325/week06/src/main/java/com/sprint/jvm/loader/ClassFileParser.java create mode 100644 group11/1178243325/week06/src/test/java/com/sprint/jvm/loader/ClassFileLoaderTest.java create mode 100644 group11/1178243325/week06/src/test/java/com/sprint/jvm/loader/EmployeeV1.java diff --git a/group11/1178243325/week06/build.gradle b/group11/1178243325/week06/build.gradle new file mode 100644 index 0000000000..128f6fda07 --- /dev/null +++ b/group11/1178243325/week06/build.gradle @@ -0,0 +1,13 @@ +apply plugin: 'java' + +repositories { + mavenCentral() +} + +dependencies { + compile("commons-io:commons-io:2.4") + //compile("commons-lang:commons-lang:2.6") + compile("org.apache.commons:commons-lang3:3.4") + testCompile("junit:junit:4.12") +} + diff --git a/group11/1178243325/week06/readme.md b/group11/1178243325/week06/readme.md new file mode 100644 index 0000000000..d32158bcdf --- /dev/null +++ b/group11/1178243325/week06/readme.md @@ -0,0 +1,11 @@ +## 讲课内容: +- 17-03-29 :JVM之classLoader + +## 第六周作业(3-27 至 04-02) +读取常量池 + +## 完成情况: +未补 + +## 我的收获: + diff --git a/group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/.ClassIndex.java.swp b/group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/.ClassIndex.java.swp new file mode 100644 index 0000000000000000000000000000000000000000..0d37255a755129f38ce5d0a21bf3eb0c2f18fc4d GIT binary patch literal 12288 zcmeI2y-wpm6h?2LN&$;NqM$$nG)v=&6Cj9)ii!eO;!kud#~B6V*fF+a5NP2EK=2+s z!>&ZfJJ3PFBTxZ%)`>y_ifAFD%BSg=akGsF!Nm`m9 zih|JbV|}Cd`s}&W^q}0g5=+|kiqaRyujX@RQC7oxBQQ;An#INZT%nMkmxoHZxdj=8 zw)8B=Z$0P9R!-tcyLK#BYE~4j`W1C#=;+?X;w}vIt$`sb constantInfos = new ArrayList(); + + public ConstantPool() { + + } + + public void addConstantInfo(ConstantInfo info) { + this.constantInfos.add(info); + } + + public ConstantInfo getConstantInfo(int index) { + return this.constantInfos.get(index); + } + + public String getUTF8String(int index) { + return ((UTF8Info)this.constantInfos.get(index)).getValue(); + } + + public Object getSize() { + return this.constantInfos.size() - 1; + } +} diff --git a/group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/UTF8Info.java b/group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..5516999c0e --- /dev/null +++ b/group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/UTF8Info.java @@ -0,0 +1,35 @@ +package com.sprint.jvm.constant; + +public class UTF8Info extends ConstantInfo { + private int type = ConstantInfo.UTF8_INFO; + private int length; + private String value; + public UTF8Info(ConstantPool pool) { + super(pool); + } + + public int getLength() { + return length; + } + + public void setLength(int length) { + this.length = length; + } + + public int getType() { + return type; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + @Override + public String toString() { + return "UTF8Info [type=" + type + ", length=" + length + ", value=" + value + "]"; + } +} diff --git a/group11/1178243325/week06/src/main/java/com/sprint/jvm/loader/ByteCodeIterator.java b/group11/1178243325/week06/src/main/java/com/sprint/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..3144d5828d --- /dev/null +++ b/group11/1178243325/week06/src/main/java/com/sprint/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,5 @@ +package com.sprint.jvm.loader; + +public class ByteCodeIterator { + +} diff --git a/group11/1178243325/week06/src/main/java/com/sprint/jvm/loader/ClassFileLoader.java b/group11/1178243325/week06/src/main/java/com/sprint/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..f190f54915 --- /dev/null +++ b/group11/1178243325/week06/src/main/java/com/sprint/jvm/loader/ClassFileLoader.java @@ -0,0 +1,52 @@ +package com.sprint.jvm.loader; + +import com.sprint.jvm.clz.ClassFile; +import java.io.IOException; +import java.io.File; +import java.io.FileInputStream; +import java.util.List; +import java.util.ArrayList; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; + +public class ClassFileLoader { + private List clzPaths = new ArrayList(); + public byte[] readBinaryCode(String className) { + className = className.replace('.', File.separatorChar) + ".class"; + for (String path : this.clzPaths) { + String clzFileName = path + File.separatorChar + className; + byte[] codes = loadClassFile(clzFileName); + if (codes != null) { + return codes; + } + } + return null; + } + + private byte[] loadClassFile(String clzFileName) { + File f = new File(clzFileName); + try { + return IOUtils.toByteArray(new FileInputStream(f)); + } catch(IOException e) { + e.printStackTrace(); + return null; + } + } + + public void addClassPath(String path) { + if (this.clzPaths.contains(path)) { + return; + } + this.clzPaths.add(path); + } + + public String getClassPath() { + return StringUtils.join(this.clzPaths, ";"); + } + + public ClassFile loadClass(String className) { + byte[] codes = this.readBinaryCode(className); + ClassFileParser parser = new ClassFileParser(); + return parser.parse(codes); + } +} diff --git a/group11/1178243325/week06/src/main/java/com/sprint/jvm/loader/ClassFileParser.java b/group11/1178243325/week06/src/main/java/com/sprint/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..4c32858fa4 --- /dev/null +++ b/group11/1178243325/week06/src/main/java/com/sprint/jvm/loader/ClassFileParser.java @@ -0,0 +1,25 @@ +package com.sprint.jvm.loader; + +import com.sprint.jvm.clz.ClassFile; +import com.sprint.jvm.clz.AccessFlag; +import com.sprint.jvm.clz.ClassIndex; +import com.sprint.jvm.constant.ConstantPool; +public class ClassFileParser { + public ClassFile parse(byte[] codes) { + return null; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + return null; + } + + private ClassIndex parseClassIndex(ByteCodeIterator iter) { + return null; + } + + private ConstantPool parseConstantPool(ByteCodeIterator iter) { + return null; + } + + +} diff --git a/group11/1178243325/week06/src/test/java/com/sprint/jvm/loader/ClassFileLoaderTest.java b/group11/1178243325/week06/src/test/java/com/sprint/jvm/loader/ClassFileLoaderTest.java new file mode 100644 index 0000000000..6795595e89 --- /dev/null +++ b/group11/1178243325/week06/src/test/java/com/sprint/jvm/loader/ClassFileLoaderTest.java @@ -0,0 +1,20 @@ +package com.sprint.jvm.loader; + +import com.sprint.jvm.clz.ClassFile; +import org.junit.Test; +import org.junit.Assert; +public class ClassFileLoaderTest { + + private static final String FULL_QUALTFIED_CLASS_NAME = "com/sprint/jvm/EmployeeV1"; + + static String path1 = ""; + static String path2 = ""; + static ClassFile clzFile = null; + static { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "com.sprint.jvm.EmployeeV1"; + clzFile = loader.loadClass(className); + clzFile.print(); + } +} diff --git a/group11/1178243325/week06/src/test/java/com/sprint/jvm/loader/EmployeeV1.java b/group11/1178243325/week06/src/test/java/com/sprint/jvm/loader/EmployeeV1.java new file mode 100644 index 0000000000..6b8532842b --- /dev/null +++ b/group11/1178243325/week06/src/test/java/com/sprint/jvm/loader/EmployeeV1.java @@ -0,0 +1,28 @@ +package com.sprint.jvm.loader; + +public class EmployeeV1 { + private String name; + private int age; + + public EmployeeV1(String name, int age) { + this.name = name; + this.age = age; + } + + public void setName(String name) { + this.name = name; + } + + public void setAge(int age) { + this.age = age; + } + + public void sayHello() { + System.out.println("Hello, this is class Employee"); + } + + public static void main(String[] args) { + EmployeeV1 p = new EmployeeV1("Andy", 20); + p.sayHello(); + } +} From 02c7c6b4809dfc725ac8e6e37fbd21724de22fa2 Mon Sep 17 00:00:00 2001 From: x_zhaohu Date: Sat, 8 Apr 2017 21:01:44 +0800 Subject: [PATCH 080/203] delete swp --- .../com/sprint/jvm/clz/.ClassIndex.java.swp | Bin 12288 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/.ClassIndex.java.swp diff --git a/group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/.ClassIndex.java.swp b/group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/.ClassIndex.java.swp deleted file mode 100644 index 0d37255a755129f38ce5d0a21bf3eb0c2f18fc4d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI2y-wpm6h?2LN&$;NqM$$nG)v=&6Cj9)ii!eO;!kud#~B6V*fF+a5NP2EK=2+s z!>&ZfJJ3PFBTxZ%)`>y_ifAFD%BSg=akGsF!Nm`m9 zih|JbV|}Cd`s}&W^q}0g5=+|kiqaRyujX@RQC7oxBQQ;An#INZT%nMkmxoHZxdj=8 zw)8B=Z$0P9R!-tcyLK#BYE~4j`W1C#=;+?X;w}vIt$`sb Date: Sat, 8 Apr 2017 22:02:30 +0800 Subject: [PATCH 081/203] =?UTF-8?q?=E4=BF=AE=E6=94=B9arrayList-=E8=80=81?= =?UTF-8?q?=E5=B8=88=E6=8C=87=E5=87=BA=E7=9A=84=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/johnChnia/coding2017/basic/ArrayList.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/ArrayList.java b/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/ArrayList.java index 8c4b8807be..464f1f5c7f 100644 --- a/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/ArrayList.java +++ b/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/ArrayList.java @@ -4,6 +4,7 @@ /** * Created by john on 2017/3/8. + * * @// TODO: 2017/4/1 实现Iterator 接口 */ @@ -23,7 +24,7 @@ public ArrayList() { /** * Constructs an list with the specified initial capacity. * - * @param initialCapacity + * @param initialCapacity capacity of arrayList. * @throws IllegalArgumentException if the specified initial capacity * is negative or zero */ @@ -88,7 +89,9 @@ public void add(int index, E element) { * @throws IndexOutOfBoundsException {@inheritDoc} */ public E remove(int index) { - rangeCheckForAdd(index); + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + } Object oldValue = elementData[index]; int numMoved = size() - index - 1; if (numMoved > 0) { From 61a6da56c8c9e21e543f326da227f0001107e7b1 Mon Sep 17 00:00:00 2001 From: johnChnia Date: Sat, 8 Apr 2017 22:08:52 +0800 Subject: [PATCH 082/203] =?UTF-8?q?=E4=BF=AE=E6=94=B9arrayList=E4=B8=AD?= =?UTF-8?q?=E8=80=81=E5=B8=88=E6=8C=87=E5=87=BA=E7=9A=84=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../johnChnia/coding2017/basic/ArrayList.java | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/ArrayList.java b/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/ArrayList.java index 464f1f5c7f..80bb60298e 100644 --- a/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/ArrayList.java +++ b/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/ArrayList.java @@ -71,7 +71,7 @@ public void add(E element) { * @throws IndexOutOfBoundsException {@inheritDoc} */ public void add(int index, E element) { - rangeCheckForAdd(index); + rangeCheck(index); ensureCapacityInternal(size + 1); System.arraycopy(elementData, index, elementData, index + 1, size - index); @@ -86,12 +86,10 @@ public void add(int index, E element) { * * @param index the index of the element to be removed * @return the element that was removed from the list - * @throws IndexOutOfBoundsException {@inheritDoc} + * @throws IndexOutOfBoundsException {@inheritDoc} index out of B */ public E remove(int index) { - if (index < 0 || index >= size) { - throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); - } + rangeCheck(index); Object oldValue = elementData[index]; int numMoved = size() - index - 1; if (numMoved > 0) { @@ -170,14 +168,6 @@ public Object[] toArray() { return Arrays.copyOf(elementData, size()); } - /** - * A version of rangeCheck used by add and addAll. - */ - private void rangeCheckForAdd(int index) { - if (index > size() - 1 || index < 0) { - throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); - } - } /** * Constructs an IndexOutOfBoundsException detail message. @@ -195,7 +185,7 @@ private String outOfBoundsMsg(int index) { * which throws an ArrayIndexOutOfBoundsException if index is negative. */ private void rangeCheck(int index) { - if (index >= size()) { + if (index < 0 || index >= size()) { throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } } From 1240657054c05587d37892a0d42b77a6e847ec43 Mon Sep 17 00:00:00 2001 From: wdn <626451284@163.com> Date: Sat, 8 Apr 2017 22:45:23 +0800 Subject: [PATCH 083/203] =?UTF-8?q?=E5=AE=8C=E6=88=90minijvm=E8=AF=BB?= =?UTF-8?q?=E5=8F=96=E5=B8=B8=E9=87=8F=E6=B1=A0=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wdn/coding2017/jvm/clz/AccessFlag.java | 7 + .../wdn/coding2017/jvm/clz/ClassFile.java | 60 +++++++++ .../wdn/coding2017/jvm/clz/ClassIndex.java | 20 +++ .../coding2017/jvm/constant/ClassInfo.java | 35 +++++ .../coding2017/jvm/constant/ConstantInfo.java | 30 +++++ .../coding2017/jvm/constant/ConstantPool.java | 32 +++++ .../coding2017/jvm/constant/FieldRefInfo.java | 39 ++++++ .../jvm/constant/MethodRefInfo.java | 37 ++++++ .../jvm/constant/NameAndTypeInfo.java | 38 ++++++ .../jvm/constant/NullConstantInfo.java | 14 ++ .../coding2017/jvm/constant/StringInfo.java | 30 +++++ .../wdn/coding2017/jvm/constant/UTF8Info.java | 23 ++++ .../jvm/loader/ByteCodeIterator.java | 39 ++++++ .../jvm/loader/ClassFileLoader.java | 11 +- .../jvm/loader/ClassFileParser.java | 76 +++++++++++ .../jvm/test/ClassFileloaderTest.java | 120 +++++++++++++++--- .../github/wdn/coding2017/jvm/util/Util.java | 24 ++++ 17 files changed, 610 insertions(+), 25 deletions(-) create mode 100644 group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/clz/AccessFlag.java create mode 100644 group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/clz/ClassFile.java create mode 100644 group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/clz/ClassIndex.java create mode 100644 group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/ClassInfo.java create mode 100644 group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/ConstantInfo.java create mode 100644 group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/ConstantPool.java create mode 100644 group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/FieldRefInfo.java create mode 100644 group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/MethodRefInfo.java create mode 100644 group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/NameAndTypeInfo.java create mode 100644 group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/NullConstantInfo.java create mode 100644 group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/StringInfo.java create mode 100644 group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/UTF8Info.java create mode 100644 group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/loader/ByteCodeIterator.java create mode 100644 group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/loader/ClassFileParser.java create mode 100644 group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/util/Util.java diff --git a/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/clz/AccessFlag.java b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..b6968a64e5 --- /dev/null +++ b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/clz/AccessFlag.java @@ -0,0 +1,7 @@ +package com.github.wdn.coding2017.jvm.clz; + +/** + * Created by Administrator on 2017/4/6 0006. + */ +public class AccessFlag { +} diff --git a/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/clz/ClassFile.java b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..3b321732ce --- /dev/null +++ b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/clz/ClassFile.java @@ -0,0 +1,60 @@ +package com.github.wdn.coding2017.jvm.clz; + +import com.github.wdn.coding2017.jvm.constant.ConstantPool; + +/** + * Created by Administrator on 2017/4/6 0006. + */ +public class ClassFile { + private int minorVersion; + private int majorVersion; + private ConstantPool constantPool; + private AccessFlag accessFlag; + private ClassIndex classIndex; + public void print() { + } + + public int getMinorVersion() { + return minorVersion; + } + + public int getMajorVersion() { + return majorVersion; + } + + public void setMinorVersion(int minorVersion) { + this.minorVersion = minorVersion; + } + + public void setMajorVersion(int majorVersion) { + this.majorVersion = majorVersion; + } + + public ConstantPool getConstantPool() { + return constantPool; + } + + public void setConstantPool(ConstantPool constantPool) { + this.constantPool = constantPool; + } + + public AccessFlag getAccessFlag() { + return accessFlag; + } + + public void setAccessFlag(AccessFlag accessFlag) { + this.accessFlag = accessFlag; + } + + public ClassIndex getClassIndex() { + return classIndex; + } + + public void setClassIndex(ClassIndex classIndex) { + this.classIndex = classIndex; + } + + public ClassIndex getClzIndex() { + return null; + } +} diff --git a/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/clz/ClassIndex.java b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..f65a403d0a --- /dev/null +++ b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/clz/ClassIndex.java @@ -0,0 +1,20 @@ +package com.github.wdn.coding2017.jvm.clz; + +/** + * Created by Administrator on 2017/4/6 0006. + */ +public class ClassIndex { + private int thisClassIndex; + private int superClassIndex; + public ClassIndex(int thisClassIndex,int superClassIndex){ + this.thisClassIndex = thisClassIndex; + this.superClassIndex = superClassIndex; + } + public int getThisClassIndex() { + return thisClassIndex; + } + + public int getSuperClassIndex() { + return superClassIndex; + } +} diff --git a/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/ClassInfo.java b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..358f935e75 --- /dev/null +++ b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/ClassInfo.java @@ -0,0 +1,35 @@ +package com.github.wdn.coding2017.jvm.constant; + +/** + * Created by Administrator on 2017/4/6 0006. + */ +public class ClassInfo extends ConstantInfo{ + private int nameIndex; + public ClassInfo(ConstantPool constantPool){ + super(constantPool); + } + @Override + public int getType() { + return CLASS_INFO; + } + @Override + public String getValue() { + return getConstantPool().getConstantInfo(nameIndex).getValue(); + } + + public int getNameIndex() { + return nameIndex; + } + + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + + public int getUtf8Index() { + return 0; + } + + public String getClassName() { + return getConstantPool().getConstantInfo(nameIndex).getValue(); + } +} diff --git a/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/ConstantInfo.java b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..24975d30c8 --- /dev/null +++ b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/ConstantInfo.java @@ -0,0 +1,30 @@ +package com.github.wdn.coding2017.jvm.constant; + +/** + * Created by Administrator on 2017/4/6 0006. + */ +public abstract class ConstantInfo { + public static final int UTF8_INFO = 1; + public static final int FLOAT_INFO = 4; + public static final int CLASS_INFO = 7; + public static final int STRING_INFO = 8; + public static final int FIELD_INFO = 9; + public static final int METHOD_INFO = 10; + public static final int NAME_AND_TYPE_INFO = 12; + protected ConstantPool constantPool; + public ConstantInfo(){ + + } + public ConstantInfo(ConstantPool constantPool){ + this.constantPool = constantPool; + } + public abstract int getType(); + public abstract String getValue(); + public ConstantPool getConstantPool(){ + return constantPool; + } + public ConstantInfo getConstantInfo(int index){ + return constantPool.getConstantInfo(index); + } + +} diff --git a/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/ConstantPool.java b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..3a3f4e03e4 --- /dev/null +++ b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/ConstantPool.java @@ -0,0 +1,32 @@ +package com.github.wdn.coding2017.jvm.constant; + + +import java.util.ArrayList; + +/** + * Created by Administrator on 2017/4/6 0006. + */ +public class ConstantPool { + public static ArrayList constantPool = new ArrayList(); + static{ + constantPool.add(new NullConstantInfo()); + } + public void put(ConstantInfo info){ + constantPool.add(info); + } + public int getSize() { + return constantPool.size()-1; + } + + public ConstantInfo getConstantInfo(int i) { + return constantPool.get(i); + } + @Override + public String toString(){ + StringBuffer stringBuffer = new StringBuffer(); + for (int i = 1; i < constantPool.size(); i++) { + stringBuffer.append("#"+i+"=>"+constantPool.get(i).getValue()); + } + return stringBuffer.toString(); + } +} diff --git a/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/FieldRefInfo.java b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..86c89dc9c3 --- /dev/null +++ b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/FieldRefInfo.java @@ -0,0 +1,39 @@ +package com.github.wdn.coding2017.jvm.constant; + +/** + * Created by Administrator on 2017/4/8 0008. + */ +public class FieldRefInfo extends ConstantInfo { + private int classInfoIndex; + private int nameAndTypeIndex; + + public FieldRefInfo(ConstantPool constantPool) { + super(constantPool); + } + + @Override + public int getType() { + return FIELD_INFO; + } + + @Override + public String getValue() { + return getConstantPool().getConstantInfo(classInfoIndex).getValue()+getConstantPool().getConstantInfo(nameAndTypeIndex).getValue(); + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } +} diff --git a/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/MethodRefInfo.java b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..e4d6412cd1 --- /dev/null +++ b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/MethodRefInfo.java @@ -0,0 +1,37 @@ +package com.github.wdn.coding2017.jvm.constant; + +/** + * Created by Administrator on 2017/4/8 0008. + */ +public class MethodRefInfo extends ConstantInfo { + private int classInfoIndex; + private int nameAndTypeIndex; + + public MethodRefInfo(ConstantPool constantPool) { + super(constantPool); + } + @Override + public int getType() { + return METHOD_INFO; + } + @Override + public String getValue() { + return getConstantPool().getConstantInfo(classInfoIndex).getValue()+getConstantPool().getConstantInfo(nameAndTypeIndex).getValue(); + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } +} diff --git a/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/NameAndTypeInfo.java b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..3a3f1bf4c8 --- /dev/null +++ b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,38 @@ +package com.github.wdn.coding2017.jvm.constant; + +/** + * Created by Administrator on 2017/4/8 0008. + */ +public class NameAndTypeInfo extends ConstantInfo{ + private int nameIndex; + private int descriptorIndex; + + public NameAndTypeInfo(ConstantPool constantPool) { + super(constantPool); + } + + @Override + public int getType() { + return 0; + } + @Override + public String getValue() { + return getConstantPool().getConstantInfo(nameIndex).getValue()+getConstantPool().getConstantInfo(descriptorIndex).getValue(); + } + + public int getNameIndex() { + return nameIndex; + } + + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + + public int getDescriptorIndex() { + return descriptorIndex; + } + + public void setDescriptorIndex(int descriptorIndex) { + this.descriptorIndex = descriptorIndex; + } +} diff --git a/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/NullConstantInfo.java b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..bea4eb973f --- /dev/null +++ b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/NullConstantInfo.java @@ -0,0 +1,14 @@ +package com.github.wdn.coding2017.jvm.constant; + +/** + * Created by Administrator on 2017/4/8 0008. + */ +public class NullConstantInfo extends ConstantInfo { + public int getType() { + return 0; + } + + public String getValue() { + return null; + } +} diff --git a/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/StringInfo.java b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..a4cbd7bb5d --- /dev/null +++ b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/StringInfo.java @@ -0,0 +1,30 @@ +package com.github.wdn.coding2017.jvm.constant; + +/** + * Created by Administrator on 2017/4/8 0008. + */ +public class StringInfo extends ConstantInfo { + public StringInfo(ConstantPool constantPool) { + super(constantPool); + } + + private int stringIndex; + + @Override + public int getType() { + return 0; + } + + @Override + public String getValue() { + return getConstantPool().getConstantInfo(stringIndex).getValue(); + } + + public int getStringIndex() { + return stringIndex; + } + + public void setStringIndex(int stringIndex) { + this.stringIndex = stringIndex; + } +} diff --git a/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/UTF8Info.java b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..bf5efd842a --- /dev/null +++ b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/constant/UTF8Info.java @@ -0,0 +1,23 @@ +package com.github.wdn.coding2017.jvm.constant; + +/** + * Created by Administrator on 2017/4/8 0008. + */ +public class UTF8Info extends ConstantInfo{ + private String value; + public UTF8Info(ConstantPool constantPool){ + super(constantPool); + } + @Override + public int getType() { + return UTF8_INFO; + } + @Override + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/loader/ByteCodeIterator.java b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..1185f5040e --- /dev/null +++ b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,39 @@ +package com.github.wdn.coding2017.jvm.loader; + + +import com.github.wdn.coding2017.jvm.util.Util; + +public class ByteCodeIterator { + private byte[] bytes; + private int index; + + public ByteCodeIterator(byte[] bytes){ + this.bytes = bytes; + } + + public byte[] read(){ + return new byte[]{bytes[index++]}; + } + public int readToInt(){ + return Util.byteToInt(new byte[]{bytes[index++]}); + } + public int readU2ToInt(){ + return Util.byteToInt(new byte[]{bytes[index++],bytes[index++]}); + } + public String readU2ToString(){ + return Util.byteToHexString(new byte[]{bytes[index++],bytes[index++]}); + } + public int readU4ToInt(){ + return Util.byteToInt(new byte[]{bytes[index++],bytes[index++],bytes[index++],bytes[index++]}); + } + public String readU4ToString(){ + return Util.byteToHexString(new byte[]{bytes[index++],bytes[index++],bytes[index++],bytes[index++]}); + } + public String readCustomToString(int len){ + byte[] b = new byte[len]; + for (int i = 0; i < len; i++) { + b[i] = bytes[index++]; + } + return new String(b); + } +} diff --git a/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/loader/ClassFileLoader.java b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/loader/ClassFileLoader.java index 20c8183f3a..6f29b692d4 100644 --- a/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/loader/ClassFileLoader.java +++ b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/loader/ClassFileLoader.java @@ -1,5 +1,6 @@ package com.github.wdn.coding2017.jvm.loader; +import com.github.wdn.coding2017.jvm.clz.ClassFile; import org.apache.commons.io.FileUtils; import java.io.File; @@ -38,7 +39,7 @@ public byte[] readBinaryCode(String className) { int offset=0; // for循环使用inputStream api读取 一次读完。。 for(offset = 0; offset < fileLength && (len = inputStream.read(fileBytes, offset, (int)fileLength - offset)) != -1; offset += len) { - System.out.println("dd"); + ; } // while循环使用System.arraycopy读取 /*while ((len = inputStream.read(bytes))>-1){ @@ -73,8 +74,10 @@ public String getClassPath(){ return stringBuffer.toString(); } - - - + public ClassFile loadClass(String className) { + ClassFileParser classFileParser = new ClassFileParser(); + ClassFile classFile = classFileParser.parse(readBinaryCode(className)); + return classFile; + } } diff --git a/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/loader/ClassFileParser.java b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..fe2bcc52e3 --- /dev/null +++ b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/loader/ClassFileParser.java @@ -0,0 +1,76 @@ +package com.github.wdn.coding2017.jvm.loader; + +import com.github.wdn.coding2017.jvm.clz.AccessFlag; +import com.github.wdn.coding2017.jvm.clz.ClassFile; +import com.github.wdn.coding2017.jvm.clz.ClassIndex; +import com.github.wdn.coding2017.jvm.constant.*; + +public class ClassFileParser { + + public ClassFile parse(byte[] codes) { + ByteCodeIterator iter = new ByteCodeIterator(codes); + String magic = iter.readU4ToString(); + if(!"cafebabe".equals(magic)){ + throw new Error(); + } + ClassFile classFile = new ClassFile(); + classFile.setMinorVersion(iter.readU2ToInt()); + classFile.setMajorVersion(iter.readU2ToInt()); + classFile.setConstantPool(parseConstantPool(iter)); + classFile.setAccessFlag(parseAccessFlag(iter)); + classFile.setClassIndex(parseClassIndex(iter)); + return classFile; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + + return null; + } + + private ClassIndex parseClassIndex(ByteCodeIterator iter) { + + return null; + + } + + public ConstantPool parseConstantPool(ByteCodeIterator iter) { + ConstantPool pool = new ConstantPool(); + int constantPoolNum = iter.readU2ToInt(); + for (int i = 0; i < constantPoolNum-1; i++) { + int type = iter.readToInt(); + if(type==7){// class + ClassInfo classInfo = new ClassInfo(pool); + classInfo.setNameIndex(iter.readU2ToInt()); + pool.put(classInfo); + }else if(type==9){// Fieldref + FieldRefInfo fieldRefInfo = new FieldRefInfo(pool); + fieldRefInfo.setClassInfoIndex(iter.readU2ToInt()); + fieldRefInfo.setNameAndTypeIndex(iter.readU2ToInt()); + pool.put(fieldRefInfo); + }else if(type==10){// Methodref + MethodRefInfo methodRefInfo = new MethodRefInfo(pool); + methodRefInfo.setClassInfoIndex(iter.readU2ToInt()); + methodRefInfo.setNameAndTypeIndex(iter.readU2ToInt()); + pool.put(methodRefInfo); + }else if(type==1){// Utf8 + int length = iter.readU2ToInt(); + String value = iter.readCustomToString(length); + UTF8Info utf8Info = new UTF8Info(pool); + utf8Info.setValue(value); + pool.put(utf8Info); + }else if(type==8){// String + StringInfo stringInfo = new StringInfo(pool); + stringInfo.setStringIndex(iter.readU2ToInt()); + pool.put(stringInfo); + }else if(type==12){// NameAndType + NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(pool); + nameAndTypeInfo.setNameIndex(iter.readU2ToInt()); + nameAndTypeInfo.setDescriptorIndex(iter.readU2ToInt()); + pool.put(nameAndTypeInfo); + }else{ + System.out.println("未知类型"+type); + } + } + return pool; + } +} diff --git a/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/test/ClassFileloaderTest.java b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/test/ClassFileloaderTest.java index 346159abb5..907a480480 100644 --- a/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/test/ClassFileloaderTest.java +++ b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/test/ClassFileloaderTest.java @@ -1,6 +1,10 @@ package com.github.wdn.coding2017.jvm.test; +import com.github.wdn.coding2017.jvm.clz.ClassFile; +import com.github.wdn.coding2017.jvm.clz.ClassIndex; +import com.github.wdn.coding2017.jvm.constant.*; import com.github.wdn.coding2017.jvm.loader.ClassFileLoader; +import com.github.wdn.coding2017.jvm.util.Util; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -16,8 +20,17 @@ public class ClassFileloaderTest { static String path1 = "E:\\softdata\\ideaworkspace\\self\\coding2017\\group24\\626451284\\mini-jvm\\target\\classes"; static String path2 = "E:\\temp"; - - + + static ClassFile clzFile = null; + static final String FULL_QUALIFIED_CLASS_NAME=""; + static { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "com.github.wdn.coding2017.jvm.test.EmployeeV1"; + + clzFile = loader.loadClass(className); + clzFile.print(); + } @Before public void setUp() throws Exception { @@ -55,7 +68,6 @@ public void testClassFileLength() { } - @Test public void testMagicNumber(){ ClassFileLoader loader = new ClassFileLoader(); @@ -65,27 +77,93 @@ public void testMagicNumber(){ byte[] codes = new byte[]{byteCodes[0],byteCodes[1],byteCodes[2],byteCodes[3]}; - String acctualValue = this.byteToHexString(codes); + String acctualValue = Util.byteToHexString(codes); Assert.assertEquals("cafebabe", acctualValue); } - - - - - - - private String byteToHexString(byte[] codes ){ - StringBuffer buffer = new StringBuffer(); - for(int i=0;i", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(10); + Assert.assertEquals("(Ljava/lang/String;I)V", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(11); + Assert.assertEquals("Code", utf8Info.getValue()); + } + + { + MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(12); + Assert.assertEquals(3, methodRef.getClassInfoIndex()); + Assert.assertEquals(13, methodRef.getNameAndTypeIndex()); + } + + { + NameAndTypeInfo nameAndType = (NameAndTypeInfo) pool.getConstantInfo(13); + Assert.assertEquals(9, nameAndType.getNameIndex()); + Assert.assertEquals(14, nameAndType.getDescriptorIndex()); + } + //抽查几个吧 + { + MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(45); + Assert.assertEquals(1, methodRef.getClassInfoIndex()); + Assert.assertEquals(46, methodRef.getNameAndTypeIndex()); + } + + { + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(53); + Assert.assertEquals("EmployeeV1.java", utf8Info.getValue()); } - return buffer.toString(); } + @Test + public void testClassIndex(){ + + ClassIndex clzIndex = clzFile.getClzIndex(); + ClassInfo thisClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getThisClassIndex()); + ClassInfo superClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getSuperClassIndex()); + + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); + Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); + } } diff --git a/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/util/Util.java b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/util/Util.java new file mode 100644 index 0000000000..1e54f24a79 --- /dev/null +++ b/group24/626451284/mini-jvm/src/main/java/com/github/wdn/coding2017/jvm/util/Util.java @@ -0,0 +1,24 @@ +package com.github.wdn.coding2017.jvm.util; + +public class Util { + public static int byteToInt(byte[] codes){ + String s1 = byteToHexString(codes); + return Integer.valueOf(s1, 16).intValue(); + } + + + + public static String byteToHexString(byte[] codes ){ + StringBuffer buffer = new StringBuffer(); + for(int i=0;i Date: Sat, 8 Apr 2017 22:55:31 +0800 Subject: [PATCH 084/203] jvm parser --- .../coding/basic/linklist/LRUPageFrame.java | 55 +++---- .../basic/linklist/LRUPageFrameTest.java | 17 ++- group12/382266293/src/array/ArrayUtil.java | 139 ++++++++--------- .../382266293/src/array/ArrayUtilTest.java | 62 ++++---- .../coderising/download/DownloadThread.java | 25 ++-- .../com/coderising/download/DownloadUtil.java | 4 +- .../coderising/download/FileDownloader.java | 4 +- .../download/FileDownloaderTest.java | 1 - .../coderising/download/api/Connection.java | 16 +- .../download/api/ConnectionManager.java | 5 +- .../download/impl/ConnectionImpl.java | 29 ++-- .../download/impl/ConnectionManagerImpl.java | 7 +- .../download/impl/NoFreeSourceException.java | 1 - .../com/coderising/jvm/clz/AccessFlag.java | 26 ++++ .../src/com/coderising/jvm/clz/ClassFile.java | 77 ++++++++++ .../com/coderising/jvm/clz/ClassIndex.java | 22 +++ .../coderising/jvm/constant/ClassInfo.java | 28 ++++ .../coderising/jvm/constant/ConstantInfo.java | 32 ++++ .../coderising/jvm/constant/ConstantPool.java | 31 ++++ .../coderising/jvm/constant/FieldRefInfo.java | 58 +++++++ .../jvm/constant/MethodRefInfo.java | 57 +++++++ .../jvm/constant/NameAndTypeInfo.java | 48 ++++++ .../jvm/constant/NullConstantInfo.java | 14 ++ .../coderising/jvm/constant/StringInfo.java | 27 ++++ .../com/coderising/jvm/constant/UTF8Info.java | 37 +++++ .../jvm/loader/ByteCodeIterator.java | 40 +++++ .../jvm/loader/ClassFileLoader.java | 11 ++ .../jvm/loader/ClassFileParser.java | 141 ++++++++++++++++++ .../jvm/test/ClassFileloaderTest.java | 107 +++++++++++++ .../src/com/coderising/jvm/util/Util.java | 22 +++ .../coderising/litestruts/LoginAction.java | 57 +++---- .../src/litestruts/Configuration.java | 71 ++++----- .../src/litestruts/ConfigurationTest.java | 34 ++--- group12/382266293/src/litestruts/Struts.java | 113 +++++++------- .../382266293/src/litestruts/StrutsTest.java | 41 +++-- group12/382266293/src/litestruts/View.java | 5 +- group12/382266293/src/test.java | 38 +++-- 37 files changed, 1120 insertions(+), 382 deletions(-) create mode 100644 group12/382266293/src/com/coderising/jvm/clz/AccessFlag.java create mode 100644 group12/382266293/src/com/coderising/jvm/clz/ClassFile.java create mode 100644 group12/382266293/src/com/coderising/jvm/clz/ClassIndex.java create mode 100644 group12/382266293/src/com/coderising/jvm/constant/ClassInfo.java create mode 100644 group12/382266293/src/com/coderising/jvm/constant/ConstantInfo.java create mode 100644 group12/382266293/src/com/coderising/jvm/constant/ConstantPool.java create mode 100644 group12/382266293/src/com/coderising/jvm/constant/FieldRefInfo.java create mode 100644 group12/382266293/src/com/coderising/jvm/constant/MethodRefInfo.java create mode 100644 group12/382266293/src/com/coderising/jvm/constant/NameAndTypeInfo.java create mode 100644 group12/382266293/src/com/coderising/jvm/constant/NullConstantInfo.java create mode 100644 group12/382266293/src/com/coderising/jvm/constant/StringInfo.java create mode 100644 group12/382266293/src/com/coderising/jvm/constant/UTF8Info.java create mode 100644 group12/382266293/src/com/coderising/jvm/loader/ByteCodeIterator.java create mode 100644 group12/382266293/src/com/coderising/jvm/loader/ClassFileParser.java create mode 100644 group12/382266293/src/com/coderising/jvm/util/Util.java diff --git a/group12/382266293/coding/basic/linklist/LRUPageFrame.java b/group12/382266293/coding/basic/linklist/LRUPageFrame.java index df8de37c68..31b22dc26b 100644 --- a/group12/382266293/coding/basic/linklist/LRUPageFrame.java +++ b/group12/382266293/coding/basic/linklist/LRUPageFrame.java @@ -6,9 +6,9 @@ * */ public class LRUPageFrame { - + private static class Node { - + Node prev; Node next; int pageNum; @@ -24,7 +24,6 @@ public int hashCode() { result = prime * result + pageNum; return result; } - @Override public String toString() { @@ -48,18 +47,16 @@ public boolean equals(Object obj) { } private int capacity; - - + private Node first;// 链表头 private Node last;// 链表尾 - public LRUPageFrame(int capacity) { - + this.capacity = capacity; - + } - + private int size; /** @@ -83,11 +80,11 @@ public void access(int pageNum) { moveLastPoint(); return; } - + if (p == first) { return; } - + if (p == last) { p.next = first; first.prev = p; @@ -95,9 +92,9 @@ public void access(int pageNum) { moveLastPoint(); return; } - + movePtoFirst(p); - + } private void moveLastPoint() { @@ -105,8 +102,6 @@ private void moveLastPoint() { last.next = null; } - - private void movePtoFirst(Node p) { p.prev.next = p.next; p.next.prev = p.prev; @@ -115,8 +110,6 @@ private void movePtoFirst(Node p) { first = p; } - - private void addNode(int pageNum) { Node node = new Node(pageNum); if (null == first) { @@ -124,21 +117,18 @@ private void addNode(int pageNum) { size++; return; } - if (null == last) { - node.next = first; - first.prev = node; - first = node; - last = node.next; - size++; - return; - } + node.next = first; first.prev = node; first = node; size++; - } + if (null == last) { + last = node.next; + return; + } + } private Node findNode(int pageNum) { Node node = first; @@ -154,21 +144,20 @@ private Node findNode(int pageNum) { public static void main(String[] args) { - } - public String toString(){ + public String toString() { StringBuilder buffer = new StringBuilder(); Node node = first; - while(node != null){ - buffer.append(node.pageNum); - + while (node != null) { + buffer.append(node.pageNum); + node = node.next; - if(node != null){ + if (node != null) { buffer.append(","); } } return buffer.toString(); } - + } diff --git a/group12/382266293/coding/basic/linklist/LRUPageFrameTest.java b/group12/382266293/coding/basic/linklist/LRUPageFrameTest.java index bea7586e15..7745d31569 100644 --- a/group12/382266293/coding/basic/linklist/LRUPageFrameTest.java +++ b/group12/382266293/coding/basic/linklist/LRUPageFrameTest.java @@ -9,23 +9,24 @@ public class LRUPageFrameTest { @Test public void testAccess() { - LRUPageFrame frame = new LRUPageFrame(3); + LRUPageFrame frame = new LRUPageFrame(4); frame.access(7); frame.access(0); frame.access(1); - Assert.assertEquals("1,0,7", frame.toString()); + frame.access(9); + Assert.assertEquals("9,1,0,7", frame.toString()); frame.access(2); - Assert.assertEquals("2,1,0", frame.toString()); + Assert.assertEquals("2,9,1,0", frame.toString()); frame.access(0); - Assert.assertEquals("0,2,1", frame.toString()); + Assert.assertEquals("0,2,9,1", frame.toString()); frame.access(0); - Assert.assertEquals("0,2,1", frame.toString()); + Assert.assertEquals("0,2,9,1", frame.toString()); frame.access(3); - Assert.assertEquals("3,0,2", frame.toString()); + Assert.assertEquals("3,0,2,9", frame.toString()); frame.access(0); - Assert.assertEquals("0,3,2", frame.toString()); + Assert.assertEquals("0,3,2,9", frame.toString()); frame.access(4); - Assert.assertEquals("4,0,3", frame.toString()); + Assert.assertEquals("4,0,3,2", frame.toString()); } } diff --git a/group12/382266293/src/array/ArrayUtil.java b/group12/382266293/src/array/ArrayUtil.java index 8412a68f48..ea847fd386 100644 --- a/group12/382266293/src/array/ArrayUtil.java +++ b/group12/382266293/src/array/ArrayUtil.java @@ -6,40 +6,37 @@ import collection.Iterator; import collection.concrete.ArrayList; - - public class ArrayUtil { - + /** - * 给定一个整形数组a , 对该数组的值进行置换 - 例如: a = [7, 9 , 30, 3] , 置换后为 [3, 30, 9,7] - 如果 a = [7, 9, 30, 3, 4] , 置换后为 [4,3, 30 , 9,7] + * 给定一个整形数组a , 对该数组的值进行置换 例如: a = [7, 9 , 30, 3] , 置换后为 [3, 30, 9,7] 如果 a = + * [7, 9, 30, 3, 4] , 置换后为 [4,3, 30 , 9,7] + * * @param origin * @return */ - public void reverseArray(int[] origin){ - + public void reverseArray(int[] origin) { + int temp; int index = origin.length - 1; - int numbersToReverse = origin.length/2; - for (int i = 0; i < numbersToReverse ; i++) { + int numbersToReverse = origin.length / 2; + for (int i = 0; i < numbersToReverse; i++) { temp = origin[i]; origin[i] = origin[index - i]; origin[index - i] = temp; } } - /** - * 现在有如下的一个数组: int oldArr[]={1,3,4,5,0,0,6,6,0,5,4,7,6,7,0,5} - * 要求将以上数组中值为0的项去掉,将不为0的值存入一个新的数组,生成的新数组为: - * {1,3,4,5,6,6,5,4,7,6,7,5} + * 现在有如下的一个数组: int oldArr[]={1,3,4,5,0,0,6,6,0,5,4,7,6,7,0,5} + * 要求将以上数组中值为0的项去掉,将不为0的值存入一个新的数组,生成的新数组为: {1,3,4,5,6,6,5,4,7,6,7,5} + * * @param oldArray * @return */ - public int[] removeZero(int[] oldArray){ - + public int[] removeZero(int[] oldArray) { + BitSet check = new BitSet(oldArray.length); boolean isZero; for (int i = 0; i < oldArray.length; i++) { @@ -47,32 +44,32 @@ public int[] removeZero(int[] oldArray){ check.set(i, isZero); } - int newSize = oldArray.length-check.cardinality(); + int newSize = oldArray.length - check.cardinality(); int[] newArr = new int[newSize]; - + int nextIndex = check.nextClearBit(0); - for(int i = 0 ; i < newSize ; i++) { + for (int i = 0; i < newSize; i++) { newArr[i] = oldArray[nextIndex]; - nextIndex = check.nextClearBit(nextIndex+1); + nextIndex = check.nextClearBit(nextIndex + 1); } return newArr; } - /** - * 给定两个已经排序好的整形数组, a1和a2 , 创建一个新的数组a3, 使得a3 包含a1和a2 的所有元素, 并且仍然是有序的 - * 例如 a1 = [3, 5, 7,8] a2 = [4, 5, 6,7] 则 a3 为[3,4,5,6,7,8] , 注意: 已经消除了重复 + * 给定两个已经排序好的整形数组, a1和a2 , 创建一个新的数组a3, 使得a3 包含a1和a2 的所有元素, 并且仍然是有序的 例如 a1 = + * [3, 5, 7,8] a2 = [4, 5, 6,7] 则 a3 为[3,4,5,6,7,8] , 注意: 已经消除了重复 + * * @param array1 * @param array2 * @return */ - - public int[] merge(int[] array1, int[] array2){ - + + public int[] merge(int[] array1, int[] array2) { + int len1 = array1.length; int len2 = array2.length; - int len3 = array1[len1-1] < array2[len2-1] ? array2[len2-1] + 1: array1[len1-1] + 1; + int len3 = array1[len1 - 1] < array2[len2 - 1] ? array2[len2 - 1] + 1 : array1[len1 - 1] + 1; int[] newArr = new int[len3]; initialArray(newArr, -1); for (int i = 0; i < len1; i++) { @@ -88,24 +85,24 @@ public int[] merge(int[] array1, int[] array2){ } return Arrays.copyOf(newArr, mergedLength); } - + public static void initialArray(int[] arr, int j) { for (int i = 0; i < arr.length; i++) { arr[i] = j; } } - + /** * 把一个已经存满数据的数组 oldArray的容量进行扩展, 扩展后的新数据大小为oldArray.length + size - * 注意,老数组的元素在新数组中需要保持 - * 例如 oldArray = [2,3,6] , size = 3,则返回的新数组为 + * 注意,老数组的元素在新数组中需要保持 例如 oldArray = [2,3,6] , size = 3,则返回的新数组为 * [2,3,6,0,0,0] + * * @param oldArray * @param size * @return */ - public int[] grow(int [] oldArray, int size){ - + public int[] grow(int[] oldArray, int size) { + int[] newArr = new int[oldArray.length + size]; for (int i = 0; i < oldArray.length; i++) { newArr[i] = oldArray[i]; @@ -113,39 +110,38 @@ public int[] grow(int [] oldArray, int size){ return newArr; } - /** - * 斐波那契数列为:1,1,2,3,5,8,13,21...... ,给定一个最大值, 返回小于该值的数列 - * 例如, max = 15 , 则返回的数组应该为 [1,1,2,3,5,8,13] - * max = 1, 则返回空数组 [] + * 斐波那契数列为:1,1,2,3,5,8,13,21...... ,给定一个最大值, 返回小于该值的数列 例如, max = 15 , + * 则返回的数组应该为 [1,1,2,3,5,8,13] max = 1, 则返回空数组 [] + * * @param max * @return */ - public int[] fibonacci(int max){ + public int[] fibonacci(int max) { if (max == 1) return new int[0]; int[] result = new int[max]; result[0] = result[1] = 1; int count = 0; - for (int i = 2, j = 0; j < max ; i++) { - result[i] = result[i-1] + result[i-2]; + for (int i = 2, j = 0; j < max; i++) { + result[i] = result[i - 1] + result[i - 2]; j = result[i]; count++; } return Arrays.copyOf(result, ++count); } - + /** - * 返回小于给定最大值max的所有素数数组 - * 例如max = 23, 返回的数组为[2,3,5,7,11,13,17,19] + * 返回小于给定最大值max的所有素数数组 例如max = 23, 返回的数组为[2,3,5,7,11,13,17,19] + * * @param max * @return */ - public int[] getPrimes(int max){ - + public int[] getPrimes(int max) { + String temp = ""; - for(int i = 0; i < max; i++) { - if(isPrime(i)) { + for (int i = 0; i < max; i++) { + if (isPrime(i)) { temp += i + " "; } } @@ -154,82 +150,77 @@ public int[] getPrimes(int max){ for (int i = 0; i < result.length; i++) { result[i] = Integer.parseInt(tempArr[i]); } - + return result; } - + public static boolean isPrime(int num) { - + if (num <= 1) return false; - + if (num == 2) return true; - - for(int i = 2; i <= Math.sqrt(num) + 1; i++) { + + for (int i = 2; i <= Math.sqrt(num) + 1; i++) { if (num % i == 0) return false; } - + return true; } - /** - * 所谓“完数”, 是指这个数恰好等于它的因子之和,例如6=1+2+3 - * 给定一个最大值max, 返回一个数组, 数组中是小于max 的所有完数 + * 所谓“完数”, 是指这个数恰好等于它的因子之和,例如6=1+2+3 给定一个最大值max, 返回一个数组, 数组中是小于max 的所有完数 + * * @param max * @return */ - public int[] getPerfectNumbers(int max){ - + public int[] getPerfectNumbers(int max) { + int count = 0; ArrayList myList = new ArrayList(); - for(int i = 1; i < max; i++) { - if(isPerfectNum(i)) { + for (int i = 1; i < max; i++) { + if (isPerfectNum(i)) { count++; myList.add(i); } } - int[] result = new int[count]; + int[] result = new int[count]; Iterator iterator = myList.iterator(); for (int i = 0; i < count; i++) { result[i] = iterator.next(); } return result; } - - + public static boolean isPerfectNum(int num) { - + int sum = 0; - for (int i = 1; i <= num/2; i++) { + for (int i = 1; i <= num / 2; i++) { if (num % i == 0) sum += i; } - + return (num == sum) ? true : false; } - /** - * 用seperator 把数组 array给连接起来 - * 例如array= [3,8,9], seperator = "-" - * 则返回值为"3-8-9" + * 用seperator 把数组 array给连接起来 例如array= [3,8,9], seperator = "-" 则返回值为"3-8-9" + * * @param array * @param s * @return */ - public String join(int[] array, String seperator){ + public String join(int[] array, String seperator) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < array.length; i++) { sb.append(array[i]); - if (i < array.length-1) + if (i < array.length - 1) sb.append(seperator); } return sb.toString(); } - } \ No newline at end of file diff --git a/group12/382266293/src/array/ArrayUtilTest.java b/group12/382266293/src/array/ArrayUtilTest.java index 42085c1e25..031ef6c09b 100644 --- a/group12/382266293/src/array/ArrayUtilTest.java +++ b/group12/382266293/src/array/ArrayUtilTest.java @@ -9,14 +9,11 @@ import org.junit.Before; import org.junit.Test; - - - public class ArrayUtilTest { private int[] actual; ArrayUtil au = new ArrayUtil(); - + @Before public void setUp() throws Exception { @@ -27,34 +24,33 @@ public void tearDown() throws Exception { actual = null; } - @Test public void testReverseArray() { - + int size = getRandomNumber(); int[] expected = getRandomIntArray(size); actual = Arrays.copyOf(expected, size); - + au.reverseArray(actual); - + for (int i = 0; i < size; i++) { - assertEquals(expected[i], actual[size-1-i]); + assertEquals(expected[i], actual[size - 1 - i]); } - + } @Test public void testRemoveZero() { - + int size = getRandomNumber(10000); int[] expected = getRandomIntArray(size); - int zeros = getRandomNumber(size-1); + int zeros = getRandomNumber(size - 1); TreeSet t = new TreeSet(); while (t.size() != zeros) { t.add(getRandomNumber(size)); } - + for (Integer i : t) { expected[i] = 0; } @@ -62,17 +58,17 @@ public void testRemoveZero() { int expectedSize = size - zeros; actual = au.removeZero(expected); assertEquals(expectedSize, actual.length); - + for (int i = 0, j = 0; i < size; i++) { if (expected[i] != 0) assertEquals(expected[i], actual[j++]); } - + } @Test public void testMerge() { - int[] arr1 = getRandomIntArray(getRandomNumber()); + int[] arr1 = getRandomIntArray(getRandomNumber()); int[] arr2 = getRandomIntArray(getRandomNumber()); Arrays.sort(arr1); Arrays.sort(arr2); @@ -85,12 +81,12 @@ public void testMerge() { } int[] actual = new int[arr1.length + arr2.length]; actual = au.merge(arr1, arr2); - + assertEquals(t.size(), actual.length); - + Iterator it = t.iterator(); - for(int i = 0; it.hasNext(); i++) { - assertEquals((int)it.next(), actual[i]); + for (int i = 0; it.hasNext(); i++) { + assertEquals((int) it.next(), actual[i]); } } @@ -100,43 +96,43 @@ public void testGrow() { int[] expected = getRandomIntArray(getRandomNumber()); int growSize = getRandomNumber(); int[] actual = au.grow(expected, growSize); - + assertEquals(expected.length + growSize, actual.length); - + for (int i = 0; i < actual.length; i++) { if (i < expected.length) { assertEquals(expected[i], actual[i]); } else { assertEquals(0, actual[i]); - } + } } } @Test public void testFibonacci() { - int[] expected = new int[] {1, 1, 2, 3, 5, 8, 13}; + int[] expected = new int[] { 1, 1, 2, 3, 5, 8, 13 }; int[] acutal = new int[expected.length]; actual = au.fibonacci(15); - assertArrayEquals(expected,actual); + assertArrayEquals(expected, actual); } @Test public void testGetPrimes() { - - int[] expected = new int[] {2,3,5,7,11,13,17,19}; + + int[] expected = new int[] { 2, 3, 5, 7, 11, 13, 17, 19 }; int[] acutal = new int[expected.length]; actual = au.getPrimes(23); - assertArrayEquals(expected,actual); + assertArrayEquals(expected, actual); } @Test public void testGetPerfectNumbers() { - - int[] expected = new int[] {6, 28, 496, 8128}; + + int[] expected = new int[] { 6, 28, 496, 8128 }; int[] acutal = new int[expected.length]; actual = au.getPerfectNumbers(10000); - assertArrayEquals(expected,actual); + assertArrayEquals(expected, actual); } @Test @@ -145,9 +141,9 @@ public void testJoin() { int[] expected = getRandomIntArray(getRandomNumber()); String seperator = "-"; String joinedString = au.join(expected, seperator); - + String[] actual = joinedString.split(seperator); - + assertEquals(expected.length, actual.length); for (int i = 0; i < expected.length; i++) { assertEquals(expected[i], Integer.parseInt(actual[i])); diff --git a/group12/382266293/src/com/coderising/download/DownloadThread.java b/group12/382266293/src/com/coderising/download/DownloadThread.java index d1e1f04c47..38f92f6677 100644 --- a/group12/382266293/src/com/coderising/download/DownloadThread.java +++ b/group12/382266293/src/com/coderising/download/DownloadThread.java @@ -7,8 +7,7 @@ import com.coderising.download.api.Connection; - -public class DownloadThread extends Thread{ +public class DownloadThread extends Thread { Connection conn; int startPos; @@ -16,15 +15,16 @@ public class DownloadThread extends Thread{ private String dest; private FileDownloader fileDownloader; - public DownloadThread( Connection conn, int startPos, int endPos){ - - this.conn = conn; + public DownloadThread(Connection conn, int startPos, int endPos) { + + this.conn = conn; this.startPos = startPos; this.endPos = endPos; } + @Override - public void run(){ - System.out.println(this.getName()+" is running"); + public void run() { + System.out.println(this.getName() + " is running"); RandomAccessFile raf = null; try { byte[] buffer = conn.read(startPos, endPos); @@ -36,7 +36,7 @@ public void run(){ e.printStackTrace(); } finally { conn.close(); - System.out.println(this.getName()+" finished"); + System.out.println(this.getName() + " finished"); try { if (raf != null) @@ -48,7 +48,7 @@ public void run(){ } } } - + public void setFileDownloader(FileDownloader fileDownloader) { this.fileDownloader = fileDownloader; } @@ -56,15 +56,14 @@ public void setFileDownloader(FileDownloader fileDownloader) { public void notifyFinished() { fileDownloader.setThreadFinished(); } - + public void setDest(String dest) { this.dest = dest; } - + public void close() { this.conn.close(); - + } - } diff --git a/group12/382266293/src/com/coderising/download/DownloadUtil.java b/group12/382266293/src/com/coderising/download/DownloadUtil.java index b01200c51d..c169214476 100644 --- a/group12/382266293/src/com/coderising/download/DownloadUtil.java +++ b/group12/382266293/src/com/coderising/download/DownloadUtil.java @@ -66,8 +66,8 @@ public static boolean rename(String from, String to) { public static void printDownloadReport(int length, long start, long end) { int time = (int) ((end - start) / 1000); - float speed = (float)length / 1024 / 1024 / time; - System.out.println("共耗时:" + time + "s,下载速度: " + (float)(Math.round(speed*100))/100 + "Mb/s"); + float speed = (float) length / 1024 / 1024 / time; + System.out.println("共耗时:" + time + "s,下载速度: " + (float) (Math.round(speed * 100)) / 100 + "Mb/s"); } } \ No newline at end of file diff --git a/group12/382266293/src/com/coderising/download/FileDownloader.java b/group12/382266293/src/com/coderising/download/FileDownloader.java index c756248bb1..671ff7243c 100644 --- a/group12/382266293/src/com/coderising/download/FileDownloader.java +++ b/group12/382266293/src/com/coderising/download/FileDownloader.java @@ -45,7 +45,6 @@ public void execute() { Connection conn = cm.open(this.url); int length = conn.getContentLength(); - System.out.println("file length:" + length); setLocation("C:\\"); @@ -53,7 +52,7 @@ public void execute() { setFileName(name); setTempName(name); checkLength(length, conn); - + DownloadUtil.createTempFile(tempName, length); int connNumbers = DownloadUtil.calculateConnects(length); @@ -153,7 +152,6 @@ private void setAndStartThreadPool(Connection conn, DownloadThread[] threadPool, } threadPool[i] = new DownloadThread(con, beginPos, endPos); setAndStartThread(threadPool[i], tempName); - } } diff --git a/group12/382266293/src/com/coderising/download/FileDownloaderTest.java b/group12/382266293/src/com/coderising/download/FileDownloaderTest.java index ae24faa19f..88a5dba40e 100644 --- a/group12/382266293/src/com/coderising/download/FileDownloaderTest.java +++ b/group12/382266293/src/com/coderising/download/FileDownloaderTest.java @@ -22,7 +22,6 @@ public void tearDown() throws Exception { public static String qq = "http://sw.bos.baidu.com/sw-search-sp/software/89179b0b248b1/QQ_8.9.20026.0_setup.exe"; public static String picture = "http://image.beekka.com/blog/201304/bg2013042401.jpg"; public static String foxmail = "http://sw.bos.baidu.com/sw-search-sp/software/6c7bb8b6674d0/fm728chb379_7.2.8.379_setup.exe"; - @Test public void testDownload() { diff --git a/group12/382266293/src/com/coderising/download/api/Connection.java b/group12/382266293/src/com/coderising/download/api/Connection.java index 63d9fc7b19..11a0eab3d8 100644 --- a/group12/382266293/src/com/coderising/download/api/Connection.java +++ b/group12/382266293/src/com/coderising/download/api/Connection.java @@ -5,23 +5,31 @@ public interface Connection { /** * 给定开始和结束位置, 读取数据, 返回值是字节数组 - * @param startPos 开始位置, 从0开始 - * @param endPos 结束位置 + * + * @param startPos + * 开始位置, 从0开始 + * @param endPos + * 结束位置 * @return */ - public byte[] read(int startPos,int endPos) throws IOException; + public byte[] read(int startPos, int endPos) throws IOException; + /** * 得到数据内容的长度 + * * @return */ public int getContentLength(); - + /** * 关闭连接 */ public void close(); + public String getFileName(); + public void setFinished(); + public boolean isFinished(); } diff --git a/group12/382266293/src/com/coderising/download/api/ConnectionManager.java b/group12/382266293/src/com/coderising/download/api/ConnectionManager.java index 17f1e544b1..c305248608 100644 --- a/group12/382266293/src/com/coderising/download/api/ConnectionManager.java +++ b/group12/382266293/src/com/coderising/download/api/ConnectionManager.java @@ -3,11 +3,12 @@ public interface ConnectionManager { /** * 给定一个url , 打开一个连接 + * * @param url * @return */ - + final int MAX_CONNECTION_SIZE = 100; - + public Connection open(String url) throws ConnectionException; } diff --git a/group12/382266293/src/com/coderising/download/impl/ConnectionImpl.java b/group12/382266293/src/com/coderising/download/impl/ConnectionImpl.java index 61ed430106..a4fa5c15ad 100644 --- a/group12/382266293/src/com/coderising/download/impl/ConnectionImpl.java +++ b/group12/382266293/src/com/coderising/download/impl/ConnectionImpl.java @@ -10,14 +10,14 @@ import sun.net.www.protocol.http.HttpURLConnection; -public class ConnectionImpl implements Connection{ +public class ConnectionImpl implements Connection { private ConnectionManager cm; private static int buffer_size = 1024; private HttpURLConnection httpConn; private URL url; private boolean finished = false; - + public ConnectionImpl(ConnectionManager cm, String _url) { this.cm = cm; try { @@ -35,28 +35,28 @@ public byte[] read(int startPos, int endPos) throws IOException { try { httpConn = (HttpURLConnection) url.openConnection(); httpConn.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos); - in = httpConn.getInputStream(); + in = httpConn.getInputStream(); out = new ByteArrayOutputStream(); in = httpConn.getInputStream(); - //in.skip(startPos); - + // in.skip(startPos); + int len = 0; byte[] b = new byte[1024]; - while((len = in.read(b)) != -1) { + while ((len = in.read(b)) != -1) { out.write(b, 0, len); } int totalLen = endPos - startPos + 1; - - if (out.size() > totalLen) { + + if (out.size() > totalLen) { byte[] data = out.toByteArray(); return data; } - + return out.toByteArray(); - + } catch (IOException e) { e.printStackTrace(); - } + } return null; } @@ -65,18 +65,18 @@ public int getContentLength() { int len = httpConn.getContentLength(); return len; - + } @Override public void close() { - httpConn.disconnect(); + httpConn.disconnect(); } @Override public String getFileName() { String fileName = httpConn.getURL().getFile(); - fileName = fileName.substring(fileName.lastIndexOf('/')+1); + fileName = fileName.substring(fileName.lastIndexOf('/') + 1); return fileName; } @@ -90,5 +90,4 @@ public boolean isFinished() { return finished; } - } diff --git a/group12/382266293/src/com/coderising/download/impl/ConnectionManagerImpl.java b/group12/382266293/src/com/coderising/download/impl/ConnectionManagerImpl.java index 4d44301b0d..122073e37b 100644 --- a/group12/382266293/src/com/coderising/download/impl/ConnectionManagerImpl.java +++ b/group12/382266293/src/com/coderising/download/impl/ConnectionManagerImpl.java @@ -11,7 +11,7 @@ public class ConnectionManagerImpl implements ConnectionManager { private int connections = 0; private String url; - + public ConnectionManagerImpl() { this.connections = 0; } @@ -24,12 +24,12 @@ public Connection open(String url) throws ConnectionException { Connection conn = null; try { address = new URL(url); - conn = new ConnectionImpl(this,url); + conn = new ConnectionImpl(this, url); connections++; return conn; } catch (IOException e) { e.printStackTrace(); - } + } return null; } @@ -43,4 +43,3 @@ private void checkConnectionSize() { } } - diff --git a/group12/382266293/src/com/coderising/download/impl/NoFreeSourceException.java b/group12/382266293/src/com/coderising/download/impl/NoFreeSourceException.java index f2f68c3aa0..909a17a29b 100644 --- a/group12/382266293/src/com/coderising/download/impl/NoFreeSourceException.java +++ b/group12/382266293/src/com/coderising/download/impl/NoFreeSourceException.java @@ -2,7 +2,6 @@ public class NoFreeSourceException extends Exception { - public NoFreeSourceException(String string) { super(string); } diff --git a/group12/382266293/src/com/coderising/jvm/clz/AccessFlag.java b/group12/382266293/src/com/coderising/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..2cc6092de0 --- /dev/null +++ b/group12/382266293/src/com/coderising/jvm/clz/AccessFlag.java @@ -0,0 +1,26 @@ +package com.coderising.jvm.clz; + +public class AccessFlag { + private int flagValue; + + public AccessFlag(int value) { + this.flagValue = value; + } + + public int getFlagValue() { + return flagValue; + } + + public void setFlagValue(int flag) { + this.flagValue = flag; + } + + public boolean isPublicClass() { + return (this.flagValue & 0x0001) != 0; + } + + public boolean isFinalClass() { + return (this.flagValue & 0x0010) != 0; + } + +} \ No newline at end of file diff --git a/group12/382266293/src/com/coderising/jvm/clz/ClassFile.java b/group12/382266293/src/com/coderising/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..359c477742 --- /dev/null +++ b/group12/382266293/src/com/coderising/jvm/clz/ClassFile.java @@ -0,0 +1,77 @@ +package com.coderising.jvm.clz; + +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantPool; + +public class ClassFile { + + private int minorVersion; + private int majorVersion; + + private AccessFlag accessFlag; + private ClassIndex clzIndex; + private ConstantPool pool; + + public ClassIndex getClzIndex() { + return clzIndex; + } + + public AccessFlag getAccessFlag() { + return accessFlag; + } + + public void setAccessFlag(AccessFlag accessFlag) { + this.accessFlag = accessFlag; + } + + public ConstantPool getConstantPool() { + return pool; + } + + public int getMinorVersion() { + return minorVersion; + } + + public void setMinorVersion(int minorVersion) { + this.minorVersion = minorVersion; + } + + public int getMajorVersion() { + return majorVersion; + } + + public void setMajorVersion(int majorVersion) { + this.majorVersion = majorVersion; + } + + public void setConstPool(ConstantPool pool) { + this.pool = pool; + + } + + public void setClassIndex(ClassIndex clzIndex) { + this.clzIndex = clzIndex; + } + + public void print() { + + if (this.accessFlag.isPublicClass()) { + System.out.println("Access flag : public "); + } + System.out.println("Class Name:" + getClassName()); + + System.out.println("Super Class Name:" + getSuperClassName()); + + } + + private String getClassName() { + int thisClassIndex = this.clzIndex.getThisClassIndex(); + ClassInfo thisClass = (ClassInfo) this.getConstantPool().getConstantInfo(thisClassIndex); + return thisClass.getClassName(); + } + + private String getSuperClassName() { + ClassInfo superClass = (ClassInfo) this.getConstantPool().getConstantInfo(this.clzIndex.getSuperClassIndex()); + return superClass.getClassName(); + } +} diff --git a/group12/382266293/src/com/coderising/jvm/clz/ClassIndex.java b/group12/382266293/src/com/coderising/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..0212bc9fb3 --- /dev/null +++ b/group12/382266293/src/com/coderising/jvm/clz/ClassIndex.java @@ -0,0 +1,22 @@ +package com.coderising.jvm.clz; + +public class ClassIndex { + private int thisClassIndex; + private int superClassIndex; + + public int getThisClassIndex() { + return thisClassIndex; + } + + public void setThisClassIndex(int thisClassIndex) { + this.thisClassIndex = thisClassIndex; + } + + public int getSuperClassIndex() { + return superClassIndex; + } + + public void setSuperClassIndex(int superClassIndex) { + this.superClassIndex = superClassIndex; + } +} \ No newline at end of file diff --git a/group12/382266293/src/com/coderising/jvm/constant/ClassInfo.java b/group12/382266293/src/com/coderising/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..4b593e7347 --- /dev/null +++ b/group12/382266293/src/com/coderising/jvm/constant/ClassInfo.java @@ -0,0 +1,28 @@ +package com.coderising.jvm.constant; + +public class ClassInfo extends ConstantInfo { + private int type = ConstantInfo.CLASS_INFO; + private int utf8Index; + + public ClassInfo(ConstantPool pool) { + super(pool); + } + + public int getUtf8Index() { + return utf8Index; + } + + public void setUtf8Index(int utf8Index) { + this.utf8Index = utf8Index; + } + + public int getType() { + return type; + } + + public String getClassName() { + int index = getUtf8Index(); + UTF8Info utf8Info = (UTF8Info) constantPool.getConstantInfo(index); + return utf8Info.getValue(); + } +} diff --git a/group12/382266293/src/com/coderising/jvm/constant/ConstantInfo.java b/group12/382266293/src/com/coderising/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..96845046b3 --- /dev/null +++ b/group12/382266293/src/com/coderising/jvm/constant/ConstantInfo.java @@ -0,0 +1,32 @@ +package com.coderising.jvm.constant; + +public abstract class ConstantInfo { + public static final int UTF8_INFO = 1; + public static final int FLOAT_INFO = 4; + public static final int CLASS_INFO = 7; + public static final int STRING_INFO = 8; + public static final int FIELD_INFO = 9; + public static final int METHOD_INFO = 10; + public static final int NAME_AND_TYPE_INFO = 12; + protected ConstantPool constantPool; + + public ConstantInfo() { + + } + + public ConstantInfo(ConstantPool pool) { + this.constantPool = pool; + pool.addConstantInfo(this); + } + + public abstract int getType(); + + public ConstantPool getConstantPool() { + return constantPool; + } + + public ConstantInfo getConstantInfo(int index) { + return this.constantPool.getConstantInfo(index); + } + +} diff --git a/group12/382266293/src/com/coderising/jvm/constant/ConstantPool.java b/group12/382266293/src/com/coderising/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..15eb086a94 --- /dev/null +++ b/group12/382266293/src/com/coderising/jvm/constant/ConstantPool.java @@ -0,0 +1,31 @@ +package com.coderising.jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List constantInfos = new ArrayList(); + + public ConstantPool() { + + } + + public void addConstantInfo(ConstantInfo info) { + + this.constantInfos.add(info); + + } + + public ConstantInfo getConstantInfo(int index) { + return this.constantInfos.get(index); + } + + public String getUTF8String(int index) { + return ((UTF8Info) this.constantInfos.get(index)).getValue(); + } + + public Object getSize() { + return this.constantInfos.size() - 1; + } +} diff --git a/group12/382266293/src/com/coderising/jvm/constant/FieldRefInfo.java b/group12/382266293/src/com/coderising/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..e9f34e550c --- /dev/null +++ b/group12/382266293/src/com/coderising/jvm/constant/FieldRefInfo.java @@ -0,0 +1,58 @@ +package com.coderising.jvm.constant; + +public class FieldRefInfo extends ConstantInfo { + private int type = ConstantInfo.FIELD_INFO; + private int classInfoIndex; + private int nameAndTypeIndex; + + public FieldRefInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String toString() { + + NameAndTypeInfo typeInfo = (NameAndTypeInfo) this.getConstantInfo(this.getNameAndTypeIndex()); + + return getClassName() + " : " + typeInfo.getName() + ":" + typeInfo.getTypeInfo() + "]"; + } + + public String getClassName() { + + ClassInfo classInfo = (ClassInfo) this.getConstantInfo(this.getClassInfoIndex()); + + UTF8Info utf8Info = (UTF8Info) this.getConstantInfo(classInfo.getUtf8Index()); + + return utf8Info.getValue(); + + } + + public String getFieldName() { + NameAndTypeInfo typeInfo = (NameAndTypeInfo) this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getFieldType() { + NameAndTypeInfo typeInfo = (NameAndTypeInfo) this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } +} diff --git a/group12/382266293/src/com/coderising/jvm/constant/MethodRefInfo.java b/group12/382266293/src/com/coderising/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..d58de16f72 --- /dev/null +++ b/group12/382266293/src/com/coderising/jvm/constant/MethodRefInfo.java @@ -0,0 +1,57 @@ +package com.coderising.jvm.constant; + +public class MethodRefInfo extends ConstantInfo { + + private int type = ConstantInfo.METHOD_INFO; + + private int classInfoIndex; + private int nameAndTypeIndex; + + public MethodRefInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String toString() { + + return getClassName() + " : " + this.getMethodName() + " : " + this.getParamAndReturnType(); + } + + public String getClassName() { + ConstantPool pool = this.getConstantPool(); + ClassInfo clzInfo = (ClassInfo) pool.getConstantInfo(this.getClassInfoIndex()); + return clzInfo.getClassName(); + } + + public String getMethodName() { + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo) pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getParamAndReturnType() { + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo) pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } + +} diff --git a/group12/382266293/src/com/coderising/jvm/constant/NameAndTypeInfo.java b/group12/382266293/src/com/coderising/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..a792e2dc13 --- /dev/null +++ b/group12/382266293/src/com/coderising/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,48 @@ +package com.coderising.jvm.constant; + +public class NameAndTypeInfo extends ConstantInfo { + public int type = ConstantInfo.NAME_AND_TYPE_INFO; + + private int index1; + private int index2; + + public NameAndTypeInfo(ConstantPool pool) { + super(pool); + } + + public int getIndex1() { + return index1; + } + + public void setIndex1(int index1) { + this.index1 = index1; + } + + public int getIndex2() { + return index2; + } + + public void setIndex2(int index2) { + this.index2 = index2; + } + + public int getType() { + return type; + } + + public String getName() { + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info1 = (UTF8Info) pool.getConstantInfo(index1); + return utf8Info1.getValue(); + } + + public String getTypeInfo() { + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info2 = (UTF8Info) pool.getConstantInfo(index2); + return utf8Info2.getValue(); + } + + public String toString() { + return "(" + getName() + "," + getTypeInfo() + ")"; + } +} diff --git a/group12/382266293/src/com/coderising/jvm/constant/NullConstantInfo.java b/group12/382266293/src/com/coderising/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..7d1abf7699 --- /dev/null +++ b/group12/382266293/src/com/coderising/jvm/constant/NullConstantInfo.java @@ -0,0 +1,14 @@ +package com.coderising.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo() { + + } + + @Override + public int getType() { + return -1; + } + +} diff --git a/group12/382266293/src/com/coderising/jvm/constant/StringInfo.java b/group12/382266293/src/com/coderising/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..0ea1f6bdac --- /dev/null +++ b/group12/382266293/src/com/coderising/jvm/constant/StringInfo.java @@ -0,0 +1,27 @@ +package com.coderising.jvm.constant; + +public class StringInfo extends ConstantInfo { + private int type = ConstantInfo.STRING_INFO; + private int index; + + public StringInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + + public String toString() { + return this.getConstantPool().getUTF8String(index); + } + +} diff --git a/group12/382266293/src/com/coderising/jvm/constant/UTF8Info.java b/group12/382266293/src/com/coderising/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..a7e88969a4 --- /dev/null +++ b/group12/382266293/src/com/coderising/jvm/constant/UTF8Info.java @@ -0,0 +1,37 @@ +package com.coderising.jvm.constant; + +public class UTF8Info extends ConstantInfo { + private int type = ConstantInfo.UTF8_INFO; + private int length; + private String value; + + public UTF8Info(ConstantPool pool) { + super(pool); + } + + public int getLength() { + return length; + } + + public void setLength(int length) { + this.length = length; + } + + public int getType() { + return type; + } + + @Override + public String toString() { + return "UTF8Info [type=" + type + ", length=" + length + ", value=" + value + ")]"; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + +} diff --git a/group12/382266293/src/com/coderising/jvm/loader/ByteCodeIterator.java b/group12/382266293/src/com/coderising/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..a4f91e0876 --- /dev/null +++ b/group12/382266293/src/com/coderising/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,40 @@ +package com.coderising.jvm.loader; + +import com.coderising.jvm.util.Util; + +public class ByteCodeIterator { + + private byte[] codes = null; + private int currPos = 0; + + public ByteCodeIterator(byte[] codes) { + this.codes = codes; + } + + public String nextU4toHexString() { + byte[] u4 = new byte[] { codes[currPos++], codes[currPos++], codes[currPos++], codes[currPos++] }; + return Util.byteToHexString(u4); + } + + public int nextU1toInt() { + byte[] u1 = new byte[] { codes[currPos++] }; + return Util.byteToInt(u1); + + } + + public int nextU2toInt() { + byte[] u2 = new byte[] { codes[currPos++], codes[currPos++] }; + return Util.byteToInt(u2); + } + + public byte[] nextNbytesToHexString(int length) { + byte[] bytes = new byte[length]; + int len = currPos + length; + for(int j = 0; currPos < len; j++) { + bytes[j] = codes[currPos++]; + } + + return bytes; + } + +} diff --git a/group12/382266293/src/com/coderising/jvm/loader/ClassFileLoader.java b/group12/382266293/src/com/coderising/jvm/loader/ClassFileLoader.java index 9ba4ff935b..71a8b6fefa 100644 --- a/group12/382266293/src/com/coderising/jvm/loader/ClassFileLoader.java +++ b/group12/382266293/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -4,9 +4,12 @@ import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; +import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; +import com.coderising.jvm.clz.ClassFile; + public class ClassFileLoader { private List clzPaths = new ArrayList(); @@ -17,6 +20,14 @@ public byte[] readBinaryCode(String className) { return loadClassFile(clzFileName); } + public ClassFile loadClass(String className) throws UnsupportedEncodingException { + + ClassFileParser clzParser = new ClassFileParser(); + byte[] codes = readBinaryCode(className); + ClassFile clzFile = clzParser.parse(codes); + return clzFile; + } + @SuppressWarnings("resource") private byte[] loadClassFile(String clzFileName) { File classFile = getClassFile(clzFileName); diff --git a/group12/382266293/src/com/coderising/jvm/loader/ClassFileParser.java b/group12/382266293/src/com/coderising/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..84a38b1fff --- /dev/null +++ b/group12/382266293/src/com/coderising/jvm/loader/ClassFileParser.java @@ -0,0 +1,141 @@ +package com.coderising.jvm.loader; + +import java.io.UnsupportedEncodingException; + +import org.junit.Assert; + +import com.coderising.jvm.clz.AccessFlag; +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.clz.ClassIndex; +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.FieldRefInfo; +import com.coderising.jvm.constant.MethodRefInfo; +import com.coderising.jvm.constant.NameAndTypeInfo; +import com.coderising.jvm.constant.NullConstantInfo; +import com.coderising.jvm.constant.StringInfo; +import com.coderising.jvm.constant.UTF8Info; +import com.coderising.jvm.util.Util; + +public class ClassFileParser { + + public ClassFile parse(byte[] codes) { + + ClassFile clzFile = new ClassFile(); + + ByteCodeIterator iter = new ByteCodeIterator(codes); + + String magicNumber = iter.nextU4toHexString(); + if ("cafebabe".equals(magicNumber) == false) { + throw new RuntimeException("invalide class file!" + magicNumber); + } + + int minorVersion = iter.nextU2toInt(); + System.out.println("minorVersion is " + minorVersion); + clzFile.setMinorVersion(minorVersion); + + int majorVersion = iter.nextU2toInt(); + System.out.println("majorVersion is " + majorVersion); + clzFile.setMajorVersion(majorVersion); + + int constantsNum = iter.nextU2toInt(); + System.out.println("constantsNum is " + constantsNum); + ConstantPool pool = new ConstantPool(); + clzFile.setConstPool(pool); + + pool.addConstantInfo(new NullConstantInfo()); + + for (int i = 1; i < constantsNum; i++) { + + int tag = iter.nextU1toInt(); + + if (tag == 7) { + // Class info + ClassInfo classInfo = new ClassInfo(pool); + int utf8Index = iter.nextU2toInt(); + classInfo.setUtf8Index(utf8Index); + + + } else if (tag == 1) { + + // utf8-info + UTF8Info utf8Info = new UTF8Info(pool); + int length = iter.nextU2toInt(); + System.out.println("length is " + length); + utf8Info.setLength(length); + byte[] bytes = iter.nextNbytesToHexString(length); + System.out.println(bytes.length); + String value = ""; + try { + value = new String(bytes, "UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + System.out.println("value is " + value); + utf8Info.setValue(value); + + } else if (tag == 8) { + + // StringInfo + StringInfo stringInfo = new StringInfo(pool); + int stringIndex = iter.nextU2toInt(); + stringInfo.setIndex(stringIndex); + } else if (tag == 9) { + + // FieldRefInfo + FieldRefInfo fieldRefInfo = new FieldRefInfo(pool); + int classIndex = iter.nextU2toInt(); + fieldRefInfo.setClassInfoIndex(classIndex); + int nameAndTypeIndex = iter.nextU2toInt(); + fieldRefInfo.setNameAndTypeIndex(nameAndTypeIndex); + + } else if (tag == 10) { + + // MethodRefInfo + MethodRefInfo methodRefInfo = new MethodRefInfo(pool); + int classIndex = iter.nextU2toInt(); + methodRefInfo.setClassInfoIndex(classIndex); + int nameAndTypeIndex = iter.nextU2toInt(); + methodRefInfo.setNameAndTypeIndex(nameAndTypeIndex); + + } else if (tag == 12) { + + // NameAndTypeInfo + NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(pool); + int index1 = iter.nextU2toInt(); + nameAndTypeInfo.setIndex1(index1); + int index2 = iter.nextU2toInt(); + nameAndTypeInfo.setIndex2(index2); + + } + + } + + return clzFile; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + AccessFlag accessFlag = new AccessFlag(iter.nextU2toInt()); + + return accessFlag; + } + + private ClassIndex parseClassIndex(ByteCodeIterator iter) { + + int thisClassIndex = iter.nextU2toInt(); + int superClassIndex = iter.nextU2toInt(); + ClassIndex classIndex = new ClassIndex(); + classIndex.setThisClassIndex(thisClassIndex); + classIndex.setSuperClassIndex(superClassIndex); + return classIndex; + + } + + private ConstantPool parseConstantPool(ByteCodeIterator iter) { + + ConstantPool pool = new ConstantPool(); + + return pool; + } + +} diff --git a/group12/382266293/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group12/382266293/src/com/coderising/jvm/test/ClassFileloaderTest.java index fb2f3be0a6..b7ec06da0f 100644 --- a/group12/382266293/src/com/coderising/jvm/test/ClassFileloaderTest.java +++ b/group12/382266293/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -1,5 +1,6 @@ package com.coderising.jvm.test; +import java.io.UnsupportedEncodingException; import java.util.Arrays; import org.junit.After; @@ -7,12 +8,31 @@ import org.junit.Before; import org.junit.Test; +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.clz.ClassIndex; +import com.coderising.jvm.constant.*; import com.coderising.jvm.loader.ClassFileLoader; public class ClassFileloaderTest { static String path1 = "C:\\Users\\Administrator\\git\\coding2017n\\group12\\382266293\\bin"; static String path2 = "C:\temp"; + String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + + static ClassFile clzFile = null; + static { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + loader.addClassPath(path2); + String className = "com.coderising.jvm.test.EmployeeV1"; + + try { + clzFile = loader.loadClass(className); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + //clzFile.print(); + } @Before public void setUp() throws Exception { @@ -77,4 +97,91 @@ private String byteToHexString(byte[] codes) { return buffer.toString(); } + @Test + public void testVersion() { + + Assert.assertEquals(0, clzFile.getMinorVersion()); + Assert.assertEquals(52, clzFile.getMajorVersion()); + + } + + @Test + public void testConstantPool() { + + ConstantPool pool = clzFile.getConstantPool(); + + Assert.assertEquals(53, pool.getSize()); + + { + ClassInfo clzInfo = (ClassInfo) pool.getConstantInfo(1); + Assert.assertEquals(2, clzInfo.getUtf8Index()); + + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(2); + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, utf8Info.getValue()); + } + { + ClassInfo clzInfo = (ClassInfo) pool.getConstantInfo(3); + Assert.assertEquals(4, clzInfo.getUtf8Index()); + + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(4); + Assert.assertEquals("java/lang/Object", utf8Info.getValue()); + } + { + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(5); + Assert.assertEquals("name", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(6); + Assert.assertEquals("Ljava/lang/String;", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(7); + Assert.assertEquals("age", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(8); + Assert.assertEquals("I", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(9); + Assert.assertEquals("", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(10); + Assert.assertEquals("(Ljava/lang/String;I)V", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(11); + Assert.assertEquals("Code", utf8Info.getValue()); + } + + { + MethodRefInfo methodRef = (MethodRefInfo) pool.getConstantInfo(12); + Assert.assertEquals(3, methodRef.getClassInfoIndex()); + Assert.assertEquals(13, methodRef.getNameAndTypeIndex()); + } + + { + NameAndTypeInfo nameAndType = (NameAndTypeInfo) pool.getConstantInfo(13); + Assert.assertEquals(9, nameAndType.getIndex1()); + Assert.assertEquals(14, nameAndType.getIndex2()); + } + // 抽查几个吧 + { + MethodRefInfo methodRef = (MethodRefInfo) pool.getConstantInfo(45); + Assert.assertEquals(1, methodRef.getClassInfoIndex()); + Assert.assertEquals(46, methodRef.getNameAndTypeIndex()); + } + + { + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(53); + Assert.assertEquals("EmployeeV1.java", utf8Info.getValue()); + } + } + + @Test + public void testClassIndex() { + + ClassIndex clzIndex = clzFile.getClzIndex(); + ClassInfo thisClassInfo = (ClassInfo) clzFile.getConstantPool().getConstantInfo(clzIndex.getThisClassIndex()); + ClassInfo superClassInfo = (ClassInfo) clzFile.getConstantPool().getConstantInfo(clzIndex.getSuperClassIndex()); + + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); + Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); + } + } diff --git a/group12/382266293/src/com/coderising/jvm/util/Util.java b/group12/382266293/src/com/coderising/jvm/util/Util.java new file mode 100644 index 0000000000..1f9e087bb9 --- /dev/null +++ b/group12/382266293/src/com/coderising/jvm/util/Util.java @@ -0,0 +1,22 @@ +package com.coderising.jvm.util; + +public class Util { + public static int byteToInt(byte[] codes) { + String s1 = byteToHexString(codes); + return Integer.valueOf(s1, 16).intValue(); + } + + public static String byteToHexString(byte[] codes) { + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < codes.length; i++) { + byte b = codes[i]; + int value = b & 0xFF; + String strHex = Integer.toHexString(value); + if (strHex.length() < 2) { + strHex = "0" + strHex; + } + buffer.append(strHex); + } + return buffer.toString(); + } +} diff --git a/group12/382266293/src/com/coderising/litestruts/LoginAction.java b/group12/382266293/src/com/coderising/litestruts/LoginAction.java index a3ce652047..95fd144d4d 100644 --- a/group12/382266293/src/com/coderising/litestruts/LoginAction.java +++ b/group12/382266293/src/com/coderising/litestruts/LoginAction.java @@ -2,38 +2,41 @@ /** * 这是一个用来展示登录的业务类, 其中的用户名和密码都是硬编码的。 + * * @author liuxin * */ -public class LoginAction{ - private String name ; - private String password; - private String message; +public class LoginAction { + private String name; + private String password; + private String message; - public String getName() { - return name; - } + public String getName() { + return name; + } - public String getPassword() { - return password; - } + public String getPassword() { + return password; + } - public String execute(){ - if("test".equals(name) && "1234".equals(password)){ - this.message = "login successful"; - return "success"; - } - this.message = "login failed,please check your user/pwd"; - return "fail"; - } + public String execute() { + if ("test".equals(name) && "1234".equals(password)) { + this.message = "login successful"; + return "success"; + } + this.message = "login failed,please check your user/pwd"; + return "fail"; + } - public void setName(String name){ - this.name = name; - } - public void setPassword(String password){ - this.password = password; - } - public String getMessage(){ - return this.message; - } + public void setName(String name) { + this.name = name; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getMessage() { + return this.message; + } } \ No newline at end of file diff --git a/group12/382266293/src/litestruts/Configuration.java b/group12/382266293/src/litestruts/Configuration.java index 4efedbce67..731a4218b0 100644 --- a/group12/382266293/src/litestruts/Configuration.java +++ b/group12/382266293/src/litestruts/Configuration.java @@ -9,84 +9,84 @@ import org.jdom2.JDOMException; import org.jdom2.input.SAXBuilder; import static util.Print.*; + public class Configuration { - Map actions = new HashMap<>(); + Map actions = new HashMap<>(); private static Configuration cfg = new Configuration(); - + private Configuration() { } + public static Configuration getNewInstance() { - + if (cfg == null) { cfg = new Configuration(); } return cfg; } - + public void parse(String fileName) { - + String src = this.getClass().getPackage().getName(); - String filepath = src.replace(".", "/") + "/" +fileName; + String filepath = src.replace(".", "/") + "/" + fileName; InputStream is = this.getClass().getResourceAsStream("/" + filepath); - + parseXML(is); - + try { is.close(); - } catch (IOException e) { - + } catch (IOException e) { + } - + } - + public void parseXML(InputStream is) { SAXBuilder reader = new SAXBuilder(); - try { + try { Document doc = reader.build(is); Element root = doc.getRootElement(); - - for(Element element : root.getChildren("action")) { - + + for (Element element : root.getChildren("action")) { + String actionName = element.getAttributeValue("name"); String clz = element.getAttributeValue("class"); - ActionCfg ac = new ActionCfg(actionName,clz); - - for(Element e : element.getChildren("result")) { - + ActionCfg ac = new ActionCfg(actionName, clz); + + for (Element e : element.getChildren("result")) { + String result = e.getAttributeValue("name"); String jsp = e.getText().trim(); ac.addViewResult(result, jsp); } - + actions.put(actionName, ac); } - + } catch (JDOMException | IOException e) { e.printStackTrace(); } } - - + public String getClassName(String action) { ActionCfg cfg = this.actions.get(action); if (cfg == null) { return null; } - return cfg.getClassName(); + return cfg.getClassName(); } - - + public String getResultView(String action, String resultName) { ActionCfg cfg = this.actions.get(action); if (cfg == null) { return null; } - return cfg.getViewResult().get(resultName); + return cfg.getViewResult().get(resultName); } public static void main(String[] args) { @@ -94,17 +94,14 @@ public static void main(String[] args) { cfg.parse("struts.xml"); String clz = cfg.getClassName("login"); println(clz); - } - - private static class ActionCfg { - + String name; String clz; - Map viewResult = new HashMap<>(); + Map viewResult = new HashMap<>(); public Map getViewResult() { return viewResult; @@ -117,7 +114,7 @@ public ActionCfg(String name, String clz) { public void addViewResult(String result, String jsp) { viewResult.put(result, jsp); - + } public String getClassName() { @@ -126,10 +123,4 @@ public String getClassName() { } - - - - - - } diff --git a/group12/382266293/src/litestruts/ConfigurationTest.java b/group12/382266293/src/litestruts/ConfigurationTest.java index e9d41a07c9..bf47334da5 100644 --- a/group12/382266293/src/litestruts/ConfigurationTest.java +++ b/group12/382266293/src/litestruts/ConfigurationTest.java @@ -5,18 +5,13 @@ import org.junit.Before; import org.junit.Test; - - public class ConfigurationTest { - Configuration cfg = Configuration.getNewInstance(); - - - + @Before public void setUp() throws Exception { - + cfg.parse("struts.xml"); } @@ -27,29 +22,28 @@ public void tearDown() throws Exception { @Test public void testGetClassName() { - + String clzName = cfg.getClassName("login"); Assert.assertEquals("com.coderising.litestruts.LoginAction", clzName); - - + clzName = cfg.getClassName("logout"); Assert.assertEquals("com.coderising.litestruts.LogoutAction", clzName); } - + @Test - public void testGetResultView(){ - String jsp = cfg.getResultView("login","success"); + public void testGetResultView() { + String jsp = cfg.getResultView("login", "success"); Assert.assertEquals("/jsp/homepage.jsp", jsp); - - jsp = cfg.getResultView("login","fail"); + + jsp = cfg.getResultView("login", "fail"); Assert.assertEquals("/jsp/showLogin.jsp", jsp); - - jsp = cfg.getResultView("logout","success"); + + jsp = cfg.getResultView("logout", "success"); Assert.assertEquals("/jsp/welcome.jsp", jsp); - - jsp = cfg.getResultView("logout","error"); + + jsp = cfg.getResultView("logout", "error"); Assert.assertEquals("/jsp/error.jsp", jsp); - + } } diff --git a/group12/382266293/src/litestruts/Struts.java b/group12/382266293/src/litestruts/Struts.java index df9c4ed535..b84e2e6264 100644 --- a/group12/382266293/src/litestruts/Struts.java +++ b/group12/382266293/src/litestruts/Struts.java @@ -16,48 +16,46 @@ public class Struts { private static Object actionObj = null; private static String address = "src/litestruts/struts.xml"; private static ActionXMLreader reader = new ActionXMLreader(); - - @SuppressWarnings("unchecked") - public static View runAction(String actionName, Map parameters){ - - Node root = reader.getRootNode(address); - String clazz = reader.parseClass(root, actionName); - actionObj = getObj(clazz); - BeanInfo bi = getBeanInfo(actionObj); - PropertyDescriptor[] pd = bi.getPropertyDescriptors(); - - setParameters(actionObj, pd, parameters); - String executeResult = getResult(actionObj, bi, "execute"); - String jsp = reader.parseResult(root, actionName, executeResult); - Map readParamters = getReadParameters(actionObj, pd); - + + @SuppressWarnings("unchecked") + public static View runAction(String actionName, Map parameters) { + + Node root = reader.getRootNode(address); + String clazz = reader.parseClass(root, actionName); + actionObj = getObj(clazz); + BeanInfo bi = getBeanInfo(actionObj); + PropertyDescriptor[] pd = bi.getPropertyDescriptors(); + + setParameters(actionObj, pd, parameters); + String executeResult = getResult(actionObj, bi, "execute"); + String jsp = reader.parseResult(root, actionName, executeResult); + Map readParamters = getReadParameters(actionObj, pd); + View view = new View(); view.setJsp(jsp); view.setParameters(readParamters); - - return view; - } - + + return view; + } private static Object getObj(String clazz) { - @SuppressWarnings("rawtypes") + @SuppressWarnings("rawtypes") Class cls = null; - + try { cls = Class.forName(clazz); return cls.newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); - }catch (InstantiationException | IllegalAccessException e) { + } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); - } + } return null; } + private static BeanInfo getBeanInfo(Object obj) { - private static BeanInfo getBeanInfo(Object obj) { - - BeanInfo bi = null; + BeanInfo bi = null; try { bi = Introspector.getBeanInfo(obj.getClass(), Object.class); } catch (IntrospectionException e) { @@ -65,51 +63,50 @@ private static BeanInfo getBeanInfo(Object obj) { } return bi; } - - private static void setParameters(Object obj, PropertyDescriptor[] pd ,Map parameters) { - - for (int i = 0; i < pd.length; i++) { - String name = pd[i].getName(); - if(parameters.containsKey(name)) - try { - pd[i].getWriteMethod().invoke(obj,parameters.get(name)); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - e.printStackTrace(); - } - } - } - - private static String getResult(Object obj, BeanInfo bi,String execute) { - MethodDescriptor[] methods = bi.getMethodDescriptors(); - for (int i = 0; i < methods.length; i++) { - String methodName = methods[i].getName(); - if(methodName.equals(execute)) + + private static void setParameters(Object obj, PropertyDescriptor[] pd, Map parameters) { + + for (int i = 0; i < pd.length; i++) { + String name = pd[i].getName(); + if (parameters.containsKey(name)) + try { + pd[i].getWriteMethod().invoke(obj, parameters.get(name)); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + e.printStackTrace(); + } + } + } + + private static String getResult(Object obj, BeanInfo bi, String execute) { + MethodDescriptor[] methods = bi.getMethodDescriptors(); + for (int i = 0; i < methods.length; i++) { + String methodName = methods[i].getName(); + if (methodName.equals(execute)) try { return (String) methods[i].getMethod().invoke(actionObj); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { e.printStackTrace(); } - } - return null; + } + return null; } - + @SuppressWarnings("rawtypes") - public static Map getReadParameters (Object obj, PropertyDescriptor[] pd) { + public static Map getReadParameters(Object obj, PropertyDescriptor[] pd) { - Map viewParams = new HashMap(); + Map viewParams = new HashMap(); - for (int i = 0; i < pd.length; i++) { - String readMethod = pd[i].getReadMethod().getName().substring(3); - String value = null; + for (int i = 0; i < pd.length; i++) { + String readMethod = pd[i].getReadMethod().getName().substring(3); + String value = null; try { value = (String) pd[i].getReadMethod().invoke(obj); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { e.printStackTrace(); } - viewParams.put(readMethod.toLowerCase(), value); - } - return viewParams; - } - + viewParams.put(readMethod.toLowerCase(), value); + } + return viewParams; + } } \ No newline at end of file diff --git a/group12/382266293/src/litestruts/StrutsTest.java b/group12/382266293/src/litestruts/StrutsTest.java index 4b59f846f5..b450d7a935 100644 --- a/group12/382266293/src/litestruts/StrutsTest.java +++ b/group12/382266293/src/litestruts/StrutsTest.java @@ -6,38 +6,33 @@ import org.junit.Assert; import org.junit.Test; - - - - public class StrutsTest { @Test public void testLoginActionSuccess() { - + String actionName = "login"; - - Map params = new HashMap(); - params.put("name","test"); - params.put("password","1234"); - - - View view = Struts.runAction(actionName,params); - - Assert.assertEquals("/jsp/homepage.jsp", view.getJsp()); - Assert.assertEquals("login successful", view.getParameters().get("message")); + + Map params = new HashMap(); + params.put("name", "test"); + params.put("password", "1234"); + + View view = Struts.runAction(actionName, params); + + Assert.assertEquals("/jsp/homepage.jsp", view.getJsp()); + Assert.assertEquals("login successful", view.getParameters().get("message")); } @Test public void testLoginActionFailed() { String actionName = "login"; - Map params = new HashMap(); - params.put("name","test"); - params.put("password","123456"); //密码和预设的不一致 - - View view = Struts.runAction(actionName,params); - - Assert.assertEquals("/jsp/showLogin.jsp", view.getJsp()); - Assert.assertEquals("login failed,please check your user/pwd", view.getParameters().get("message")); + Map params = new HashMap(); + params.put("name", "test"); + params.put("password", "123456"); // 密码和预设的不一致 + + View view = Struts.runAction(actionName, params); + + Assert.assertEquals("/jsp/showLogin.jsp", view.getJsp()); + Assert.assertEquals("login failed,please check your user/pwd", view.getParameters().get("message")); } } diff --git a/group12/382266293/src/litestruts/View.java b/group12/382266293/src/litestruts/View.java index 5a7d948765..0c917dcb35 100644 --- a/group12/382266293/src/litestruts/View.java +++ b/group12/382266293/src/litestruts/View.java @@ -5,17 +5,20 @@ public class View { private String jsp; private Map parameters; - + public String getJsp() { return jsp; } + public View setJsp(String jsp) { this.jsp = jsp; return this; } + public Map getParameters() { return parameters; } + public View setParameters(Map parameters) { this.parameters = parameters; return this; diff --git a/group12/382266293/src/test.java b/group12/382266293/src/test.java index a705772df2..b3a32d2556 100644 --- a/group12/382266293/src/test.java +++ b/group12/382266293/src/test.java @@ -10,24 +10,24 @@ public class test { - public static String url = "http://sw.bos.baidu.com/sw-search-sp/software/89179b0b248b1/QQ_8.9.20026.0_setup.exe"; + public static String url = "http://sw.bos.baidu.com/sw-search-sp/software/89179b0b248b1/QQ_8.9.20026.0_setup.exe"; public static String url2 = "http://image.beekka.com/blog/201304/bg2013042401.jpg"; public static String downloadLocation = "C:\\"; public static String tempName = ""; public static String fileName = ""; - + LinkedList a; - + private static void createTempFile1(String from) { long length = 0; URL url = null; HttpURLConnection conn = null; try { url = new URL(from); - conn = (HttpURLConnection)url.openConnection(); + conn = (HttpURLConnection) url.openConnection(); String file = conn.getURL().getFile(); - fileName = file.substring(file.lastIndexOf('/')+1); - tempName = fileName.substring(0, fileName.lastIndexOf('.')+1) + "lyj"; + fileName = file.substring(file.lastIndexOf('/') + 1); + tempName = fileName.substring(0, fileName.lastIndexOf('.') + 1) + "lyj"; length = conn.getContentLength(); conn.disconnect(); } catch (IOException e) { @@ -37,7 +37,7 @@ private static void createTempFile1(String from) { } tempName = downloadLocation + tempName; fileName = downloadLocation + fileName; - bufferFile(tempName,length); + bufferFile(tempName, length); } public static void bufferFile(String name, long len) { @@ -53,7 +53,7 @@ public static void bufferFile(String name, long len) { temp.write(buffer); } temp.write(buffer, 0, left); - + } catch (Exception e) { e.printStackTrace(); } finally { @@ -65,23 +65,22 @@ public static void bufferFile(String name, long len) { } } } - - + public static void download(String src) { createTempFile1(src); - + URL url = null; HttpURLConnection conn = null; FileOutputStream out = null; InputStream in = null; try { url = new URL(src); - conn = (HttpURLConnection)url.openConnection(); - in = conn.getInputStream(); + conn = (HttpURLConnection) url.openConnection(); + in = conn.getInputStream(); out = new FileOutputStream(tempName); byte[] buffer = new byte[1024]; int len = 0; - while( (len = in.read(buffer)) != -1) { + while ((len = in.read(buffer)) != -1) { out.write(buffer, 0, len); } conn.disconnect(); @@ -95,20 +94,19 @@ public static void download(String src) { } } - + public static boolean rename(String temp) { - File file=new File(temp); - File f1=new File(fileName); - if( file.exists() ) { + File file = new File(temp); + File f1 = new File(fileName); + if (file.exists()) { file.renameTo(f1); file = f1; - System.out.println("文件重命名为:"+f1.getName()); + System.out.println("文件重命名为:" + f1.getName()); return true; } return false; } - public static void main(String[] args) throws IOException { download(url2); From 0dca69e376ea2c4dbe8ae4c6a4e54711832fed1b Mon Sep 17 00:00:00 2001 From: GallenZhang <1298552064@qq.com> Date: Sun, 9 Apr 2017 01:18:47 +0800 Subject: [PATCH 085/203] =?UTF-8?q?=E7=AC=AC=E5=9B=9B=E6=AC=A1=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A=E6=8F=90=E4=BB=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1.ClassFileLoader读取字节码到字节数组 2.LRU算法简单实现 --- .../src/week04/lru/LRUPageFrame.java | 116 ++++++++++++++++++ .../minijvm/loader/ClassFileLoader.java | 67 ++++++++++ .../src/week04/test/ClassFileloaderTest.java | 78 ++++++++++++ .../src/week04/test/EmployeeV1.java | 30 +++++ .../src/week04/test/LRUPageFrameTest.java | 29 +++++ 5 files changed, 320 insertions(+) create mode 100644 group01/1298552064/src/week04/lru/LRUPageFrame.java create mode 100644 group01/1298552064/src/week04/minijvm/loader/ClassFileLoader.java create mode 100644 group01/1298552064/src/week04/test/ClassFileloaderTest.java create mode 100644 group01/1298552064/src/week04/test/EmployeeV1.java create mode 100644 group01/1298552064/src/week04/test/LRUPageFrameTest.java diff --git a/group01/1298552064/src/week04/lru/LRUPageFrame.java b/group01/1298552064/src/week04/lru/LRUPageFrame.java new file mode 100644 index 0000000000..b00ff2c116 --- /dev/null +++ b/group01/1298552064/src/week04/lru/LRUPageFrame.java @@ -0,0 +1,116 @@ +package week04.lru; + +public class LRUPageFrame { + private static class Node { + + Node prev; + Node next; + int pageNum; + + Node(Node prev, Node next, int pageNum) { + this.prev = prev; + this.next = next; + this.pageNum = pageNum; + } + } + + private int capacity; + + private Node first;// 链表头 + private Node last;// 链表尾 + private int size; // 链表长度 + + public LRUPageFrame(int capacity) { + this.capacity = capacity; + } + + /** + * 获取缓存中对象 + * + * @param key + * @return + */ + public void access(int pageNum) { + int index = find(pageNum); + if (size != 0) { + if(index >= 0){ + remove(index); + }else if(size == capacity){ + remove(size - 1); + } + } + addToHead(pageNum); + } + + public void remove(int index) { + if (index == 0) { + if(size == 1){ + first = last = null; + }else{ + first = first.next; + first.prev = null; + } + } else if (index == (size - 1)) { + if(size == 1){ + first = last = null; + }else{ + last = last.prev; + last.next = null; + } + } else { + Node node = first; + for (int i = 1; i < index; i++) { + node = node.next; + } + + Node nxt = node.next; + + node.next = nxt.next; + (nxt.next).prev = node; + nxt = null; + } + size--; + } + + public int find(int pageNum) { + int index = 0; + Node cur = first; + while (cur != null) { + if (pageNum == cur.pageNum) { + return index; + } + cur = cur.next; + index++; + } + return -1; + } + + public void addToHead(int pageNum) { + // 链表为空 + if (first == null) { + Node node = new Node(null, null, pageNum); + first = node; + last = node; + } else { + Node node = new Node(null,first,pageNum); + first.prev = node; + first = node; + } + size ++; + } + + @Override + public String toString() { + StringBuilder buffer = new StringBuilder(); + Node node = first; + while (node != null) { + buffer.append(node.pageNum); + + node = node.next; + if (node != null) { + buffer.append(","); + } + } + return buffer.toString(); + } +} diff --git a/group01/1298552064/src/week04/minijvm/loader/ClassFileLoader.java b/group01/1298552064/src/week04/minijvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..2e80e89587 --- /dev/null +++ b/group01/1298552064/src/week04/minijvm/loader/ClassFileLoader.java @@ -0,0 +1,67 @@ +package week04.minijvm.loader; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class ClassFileLoader { + private List clzPaths = new ArrayList(); + + public byte[] readBinaryCode(String className) throws IOException { + if(className == null){ + return null; + } + + boolean isFileExist = false; + File file = null; + String classPath = className.replace(".", "\\"); + for(int i = 0 ; i < clzPaths.size(); i++){ + String basePath = clzPaths.get(i); + file = new File(basePath + File.separator + classPath + ".class"); + + if(file.exists()){ + isFileExist = true; + break; + } + } + + //找不到类 + if(!isFileExist){ + throw new FileNotFoundException(); + } + + //读取字节码文件到数组 + FileInputStream in = new FileInputStream(file); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte [] rs = new byte[1024]; + int len = 0; + while((len = in.read(rs)) != -1){ + bos.write(rs, 0, len); + } + bos.close(); + in.close(); + System.out.println("readBinaryCode:" + " file size = " + file.length()); + return bos.toByteArray(); + } + + public void addClassPath(String path) { + if(! clzPaths.contains(path)){ + clzPaths.add(path); + } + } + + public String getClassPath() { + StringBuffer buffer = new StringBuffer(); + for(int i = 0;i < clzPaths.size();i++){ + buffer.append(clzPaths.get(i)); + if(i != clzPaths.size() - 1){ + buffer.append(";"); + } + } + return buffer.toString(); + } +} diff --git a/group01/1298552064/src/week04/test/ClassFileloaderTest.java b/group01/1298552064/src/week04/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..18b42f859d --- /dev/null +++ b/group01/1298552064/src/week04/test/ClassFileloaderTest.java @@ -0,0 +1,78 @@ +package week04.test; + +import java.io.IOException; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import week04.minijvm.loader.ClassFileLoader; + + +public class ClassFileloaderTest { + static String path1 = "D:\\Git_2017\\coding2017\\group01\\1298552064\\bin"; + static String path2 = "C:\\temp"; + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testClassPath() { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + loader.addClassPath(path2); + + String clzPath = loader.getClassPath(); + + Assert.assertEquals(path1 + ";" + path2, clzPath); + } + + @Test + public void testClassFileLength() throws IOException { + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + + String className = "week04.test.EmployeeV1"; + + byte[] byteCodes = loader.readBinaryCode(className); + + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + Assert.assertEquals(1032, byteCodes.length); + + } + + @Test + public void testMagicNumber() throws IOException { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "week04.test.EmployeeV1"; + byte[] byteCodes = loader.readBinaryCode(className); + byte[] codes = new byte[] { byteCodes[0], byteCodes[1], byteCodes[2], + byteCodes[3] }; + + String acctualValue = this.byteToHexString(codes); + + Assert.assertEquals("cafebabe", acctualValue); + } + + private String byteToHexString(byte[] codes) { + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < codes.length; i++) { + byte b = codes[i]; + int value = b & 0xFF; + String strHex = Integer.toHexString(value); + if (strHex.length() < 2) { + strHex = "0" + strHex; + } + buffer.append(strHex); + } + return buffer.toString(); + } +} diff --git a/group01/1298552064/src/week04/test/EmployeeV1.java b/group01/1298552064/src/week04/test/EmployeeV1.java new file mode 100644 index 0000000000..1c292f7744 --- /dev/null +++ b/group01/1298552064/src/week04/test/EmployeeV1.java @@ -0,0 +1,30 @@ +package week04.test; + +public class EmployeeV1 { + + private String name; + private int age; + + public EmployeeV1(String name, int age) { + this.name = name; + this.age = age; + } + + public void setName(String name) { + this.name = name; + } + + public void setAge(int age) { + this.age = age; + } + + public void sayHello() { + System.out.println("Hello , this is class Employee "); + } + + public static void main(String[] args) { + EmployeeV1 p = new EmployeeV1("Andy", 29); + p.sayHello(); + + } +} diff --git a/group01/1298552064/src/week04/test/LRUPageFrameTest.java b/group01/1298552064/src/week04/test/LRUPageFrameTest.java new file mode 100644 index 0000000000..6fbf3ddef9 --- /dev/null +++ b/group01/1298552064/src/week04/test/LRUPageFrameTest.java @@ -0,0 +1,29 @@ +package week04.test; + +import org.junit.Assert; +import org.junit.Test; + +import week04.lru.LRUPageFrame; + +public class LRUPageFrameTest { + @Test + public void testAccess() { + LRUPageFrame frame = new LRUPageFrame(3); + frame.access(7); + frame.access(0); + frame.access(1); + Assert.assertEquals("1,0,7", frame.toString()); + frame.access(2); + Assert.assertEquals("2,1,0", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(3); + Assert.assertEquals("3,0,2", frame.toString()); + frame.access(0); + Assert.assertEquals("0,3,2", frame.toString()); + frame.access(4); + Assert.assertEquals("4,0,3", frame.toString()); + } +} From 08f0ba90951866df5a0659877ff2de95ccfa93d8 Mon Sep 17 00:00:00 2001 From: wa122as Date: Sun, 9 Apr 2017 11:34:25 +0800 Subject: [PATCH 086/203] =?UTF-8?q?=E8=A1=A5=E4=BA=A4=E7=AC=AC=E5=9B=9B?= =?UTF-8?q?=E6=AC=A1=E4=BD=9C=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/task4/jvm/loader/ClassFileLoader.java | 19 ++++++------------- .../task4/jvm/test/ClassFileloaderTest.java | 9 ++++----- .../src/task4/jvm/test/EmployeeV1.java | 2 +- .../src/task4/linklist/LRUPageFrame.java | 2 +- .../task5/jvm/test/ClassFileloaderTest.java | 10 +++++----- "\357\274\201" | 8 -------- 6 files changed, 17 insertions(+), 33 deletions(-) delete mode 100644 "\357\274\201" diff --git a/group15/1521_653895972/src/task4/jvm/loader/ClassFileLoader.java b/group15/1521_653895972/src/task4/jvm/loader/ClassFileLoader.java index cdecffed32..440341fda4 100644 --- a/group15/1521_653895972/src/task4/jvm/loader/ClassFileLoader.java +++ b/group15/1521_653895972/src/task4/jvm/loader/ClassFileLoader.java @@ -1,5 +1,7 @@ package task4.jvm.loader; +import org.apache.commons.lang3.StringUtils; + import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.File; @@ -15,10 +17,7 @@ public class ClassFileLoader { private List clzPaths = new ArrayList(); public byte[] readBinaryCode(String className) throws Exception { - URL base = this.getClass().getResource("/"); - String baseToString = ""+base; - String filePath = baseToString.replaceAll("file:/", "")+className.replace(".", "\\")+".class"; - //String filePath = clzPaths.get(0)+"\\"+className.replace(".", "\\")+".class"; //符合Junit测试调用addClassPath方法 + String filePath = clzPaths.get(0)+File.separatorChar+className.replace('.',File.separatorChar)+".class"; File file = new File(filePath); BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); @@ -33,19 +32,13 @@ public byte[] readBinaryCode(String className) throws Exception { } public void addClassPath(String path) { + if (clzPaths.contains(path)) + return; clzPaths.add(path); } public String getClassPath(){ - StringBuffer strBuffer = new StringBuffer(); - for(int i=0;i Date: Sun, 9 Apr 2017 13:46:32 +0800 Subject: [PATCH 087/203] week05 --- .../com/coderising/jvm/clz/AccessFlag.java | 25 +++ .../src/com/coderising/jvm/clz/ClassFile.java | 75 +++++++ .../com/coderising/jvm/clz/ClassIndex.java | 19 ++ .../coderising/jvm/constant/ClassInfo.java | 24 +++ .../coderising/jvm/constant/ConstantInfo.java | 29 +++ .../coderising/jvm/constant/ConstantPool.java | 29 +++ .../coderising/jvm/constant/FieldRefInfo.java | 54 +++++ .../jvm/constant/MethodRefInfo.java | 55 +++++ .../jvm/constant/NameAndTypeInfo.java | 45 +++++ .../jvm/constant/NullConstantInfo.java | 13 ++ .../coderising/jvm/constant/StringInfo.java | 26 +++ .../com/coderising/jvm/constant/UTF8Info.java | 32 +++ .../jvm/loader/ClassFileLoader.java | 189 +++++++++++++++++- .../coderising/jvm/test/ByteCodeIterator.java | 47 +++++ .../coderising/jvm/test/ClassFileParser.java | 114 +++++++++++ .../jvm/test/ClassFileloaderTest.java | 156 +++++++++++++-- .../src/com/coding/basic/stack/Stack.java | 44 ++++ .../src/com/coding/basic/stack/StackUtil.java | 102 ++++++++++ 18 files changed, 1051 insertions(+), 27 deletions(-) create mode 100644 group27/1016908591/week04/src/com/coderising/jvm/clz/AccessFlag.java create mode 100644 group27/1016908591/week04/src/com/coderising/jvm/clz/ClassFile.java create mode 100644 group27/1016908591/week04/src/com/coderising/jvm/clz/ClassIndex.java create mode 100644 group27/1016908591/week04/src/com/coderising/jvm/constant/ClassInfo.java create mode 100644 group27/1016908591/week04/src/com/coderising/jvm/constant/ConstantInfo.java create mode 100644 group27/1016908591/week04/src/com/coderising/jvm/constant/ConstantPool.java create mode 100644 group27/1016908591/week04/src/com/coderising/jvm/constant/FieldRefInfo.java create mode 100644 group27/1016908591/week04/src/com/coderising/jvm/constant/MethodRefInfo.java create mode 100644 group27/1016908591/week04/src/com/coderising/jvm/constant/NameAndTypeInfo.java create mode 100644 group27/1016908591/week04/src/com/coderising/jvm/constant/NullConstantInfo.java create mode 100644 group27/1016908591/week04/src/com/coderising/jvm/constant/StringInfo.java create mode 100644 group27/1016908591/week04/src/com/coderising/jvm/constant/UTF8Info.java create mode 100644 group27/1016908591/week04/src/com/coderising/jvm/test/ByteCodeIterator.java create mode 100644 group27/1016908591/week04/src/com/coderising/jvm/test/ClassFileParser.java create mode 100644 group27/1016908591/week04/src/com/coding/basic/stack/Stack.java create mode 100644 group27/1016908591/week04/src/com/coding/basic/stack/StackUtil.java diff --git a/group27/1016908591/week04/src/com/coderising/jvm/clz/AccessFlag.java b/group27/1016908591/week04/src/com/coderising/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..faae056835 --- /dev/null +++ b/group27/1016908591/week04/src/com/coderising/jvm/clz/AccessFlag.java @@ -0,0 +1,25 @@ +package com.coderising.jvm.clz; + +public class AccessFlag { + private int flagValue; + + public AccessFlag(int value) { + this.flagValue = value; + } + + public int getFlagValue() { + return flagValue; + } + + public void setFlagValue(int flag) { + this.flagValue = flag; + } + + public boolean isPublicClass(){ + return (this.flagValue & 0x0001) != 0; + } + public boolean isFinalClass(){ + return (this.flagValue & 0x0010) != 0; + } + +} \ No newline at end of file diff --git a/group27/1016908591/week04/src/com/coderising/jvm/clz/ClassFile.java b/group27/1016908591/week04/src/com/coderising/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..650ca8375d --- /dev/null +++ b/group27/1016908591/week04/src/com/coderising/jvm/clz/ClassFile.java @@ -0,0 +1,75 @@ +package com.coderising.jvm.clz; + +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantPool; + +public class ClassFile { + + private int minorVersion; + private int majorVersion; + + private AccessFlag accessFlag; + private ClassIndex clzIndex; + private ConstantPool pool; + + + public ClassIndex getClzIndex() { + return clzIndex; + } + public AccessFlag getAccessFlag() { + return accessFlag; + } + public void setAccessFlag(AccessFlag accessFlag) { + this.accessFlag = accessFlag; + } + + + + public ConstantPool getConstantPool() { + return pool; + } + public int getMinorVersion() { + return minorVersion; + } + public void setMinorVersion(int minorVersion) { + this.minorVersion = minorVersion; + } + public int getMajorVersion() { + return majorVersion; + } + public void setMajorVersion(int majorVersion) { + this.majorVersion = majorVersion; + } + public void setConstPool(ConstantPool pool) { + this.pool = pool; + + } + public void setClassIndex(ClassIndex clzIndex) { + this.clzIndex = clzIndex; + } + + + + + public void print(){ + + if(this.accessFlag.isPublicClass()){ + System.out.println("Access flag : public "); + } + System.out.println("Class Name:"+ getClassName()); + + System.out.println("Super Class Name:"+ getSuperClassName()); + + + } + + private String getClassName(){ + int thisClassIndex = this.clzIndex.getThisClassIndex(); + ClassInfo thisClass = (ClassInfo)this.getConstantPool().getConstantInfo(thisClassIndex); + return thisClass.getClassName(); + } + private String getSuperClassName(){ + ClassInfo superClass = (ClassInfo)this.getConstantPool().getConstantInfo(this.clzIndex.getSuperClassIndex()); + return superClass.getClassName(); + } +} diff --git a/group27/1016908591/week04/src/com/coderising/jvm/clz/ClassIndex.java b/group27/1016908591/week04/src/com/coderising/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..e424f284b3 --- /dev/null +++ b/group27/1016908591/week04/src/com/coderising/jvm/clz/ClassIndex.java @@ -0,0 +1,19 @@ +package com.coderising.jvm.clz; + +public class ClassIndex { + private int thisClassIndex; + private int superClassIndex; + + public int getThisClassIndex() { + return thisClassIndex; + } + public void setThisClassIndex(int thisClassIndex) { + this.thisClassIndex = thisClassIndex; + } + public int getSuperClassIndex() { + return superClassIndex; + } + public void setSuperClassIndex(int superClassIndex) { + this.superClassIndex = superClassIndex; + } +} \ No newline at end of file diff --git a/group27/1016908591/week04/src/com/coderising/jvm/constant/ClassInfo.java b/group27/1016908591/week04/src/com/coderising/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..aea9048ea4 --- /dev/null +++ b/group27/1016908591/week04/src/com/coderising/jvm/constant/ClassInfo.java @@ -0,0 +1,24 @@ +package com.coderising.jvm.constant; + +public class ClassInfo extends ConstantInfo { + private int type = ConstantInfo.CLASS_INFO; + private int utf8Index ; + public ClassInfo(ConstantPool pool) { + super(pool); + } + public int getUtf8Index() { + return utf8Index; + } + public void setUtf8Index(int utf8Index) { + this.utf8Index = utf8Index; + } + public int getType() { + return type; + } + + public String getClassName() { + int index = getUtf8Index(); + UTF8Info utf8Info = (UTF8Info)constantPool.getConstantInfo(index); + return utf8Info.getValue(); + } +} diff --git a/group27/1016908591/week04/src/com/coderising/jvm/constant/ConstantInfo.java b/group27/1016908591/week04/src/com/coderising/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..466b072244 --- /dev/null +++ b/group27/1016908591/week04/src/com/coderising/jvm/constant/ConstantInfo.java @@ -0,0 +1,29 @@ +package com.coderising.jvm.constant; + +public abstract class ConstantInfo { + public static final int UTF8_INFO = 1; + public static final int FLOAT_INFO = 4; + public static final int CLASS_INFO = 7; + public static final int STRING_INFO = 8; + public static final int FIELD_INFO = 9; + public static final int METHOD_INFO = 10; + public static final int NAME_AND_TYPE_INFO = 12; + protected ConstantPool constantPool; + + public ConstantInfo(){ + + } + + public ConstantInfo(ConstantPool pool) { + this.constantPool = pool; + } + public abstract int getType(); + + public ConstantPool getConstantPool() { + return constantPool; + } + public ConstantInfo getConstantInfo(int index){ + return this.constantPool.getConstantInfo(index); + } + +} diff --git a/group27/1016908591/week04/src/com/coderising/jvm/constant/ConstantPool.java b/group27/1016908591/week04/src/com/coderising/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..86c0445695 --- /dev/null +++ b/group27/1016908591/week04/src/com/coderising/jvm/constant/ConstantPool.java @@ -0,0 +1,29 @@ +package com.coderising.jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List constantInfos = new ArrayList(); + + + public ConstantPool(){ + + } + public void addConstantInfo(ConstantInfo info){ + + this.constantInfos.add(info); + + } + + public ConstantInfo getConstantInfo(int index){ + return this.constantInfos.get(index); + } + public String getUTF8String(int index){ + return ((UTF8Info)this.constantInfos.get(index)).getValue(); + } + public Object getSize() { + return this.constantInfos.size() -1; + } +} diff --git a/group27/1016908591/week04/src/com/coderising/jvm/constant/FieldRefInfo.java b/group27/1016908591/week04/src/com/coderising/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..65475e194c --- /dev/null +++ b/group27/1016908591/week04/src/com/coderising/jvm/constant/FieldRefInfo.java @@ -0,0 +1,54 @@ +package com.coderising.jvm.constant; + +public class FieldRefInfo extends ConstantInfo{ + private int type = ConstantInfo.FIELD_INFO; + private int classInfoIndex; + private int nameAndTypeIndex; + + public FieldRefInfo(ConstantPool pool) { + super(pool); + } + public int getType() { + return type; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String toString(){ + + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + + return getClassName() +" : "+ typeInfo.getName() + ":" + typeInfo.getTypeInfo() +"]"; + } + + public String getClassName(){ + + ClassInfo classInfo = (ClassInfo) this.getConstantInfo(this.getClassInfoIndex()); + + UTF8Info utf8Info = (UTF8Info)this.getConstantInfo(classInfo.getUtf8Index()); + + return utf8Info.getValue(); + + } + + public String getFieldName(){ + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getFieldType(){ + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } +} diff --git a/group27/1016908591/week04/src/com/coderising/jvm/constant/MethodRefInfo.java b/group27/1016908591/week04/src/com/coderising/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..7f05870020 --- /dev/null +++ b/group27/1016908591/week04/src/com/coderising/jvm/constant/MethodRefInfo.java @@ -0,0 +1,55 @@ +package com.coderising.jvm.constant; + +public class MethodRefInfo extends ConstantInfo { + + private int type = ConstantInfo.METHOD_INFO; + + private int classInfoIndex; + private int nameAndTypeIndex; + + public MethodRefInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String toString(){ + + return getClassName() +" : "+ this.getMethodName() + " : " + this.getParamAndReturnType() ; + } + public String getClassName(){ + ConstantPool pool = this.getConstantPool(); + ClassInfo clzInfo = (ClassInfo)pool.getConstantInfo(this.getClassInfoIndex()); + return clzInfo.getClassName(); + } + + public String getMethodName(){ + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo)pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getParamAndReturnType(){ + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo)pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } + + + +} diff --git a/group27/1016908591/week04/src/com/coderising/jvm/constant/NameAndTypeInfo.java b/group27/1016908591/week04/src/com/coderising/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..402f9dec86 --- /dev/null +++ b/group27/1016908591/week04/src/com/coderising/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,45 @@ +package com.coderising.jvm.constant; + +public class NameAndTypeInfo extends ConstantInfo{ + public int type = ConstantInfo.NAME_AND_TYPE_INFO; + + private int index1; + private int index2; + + public NameAndTypeInfo(ConstantPool pool) { + super(pool); + } + + public int getIndex1() { + return index1; + } + public void setIndex1(int index1) { + this.index1 = index1; + } + public int getIndex2() { + return index2; + } + public void setIndex2(int index2) { + this.index2 = index2; + } + public int getType() { + return type; + } + + + public String getName(){ + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info1 = (UTF8Info)pool.getConstantInfo(index1); + return utf8Info1.getValue(); + } + + public String getTypeInfo(){ + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info2 = (UTF8Info)pool.getConstantInfo(index2); + return utf8Info2.getValue(); + } + + public String toString(){ + return "(" + getName() + "," + getTypeInfo()+")"; + } +} diff --git a/group27/1016908591/week04/src/com/coderising/jvm/constant/NullConstantInfo.java b/group27/1016908591/week04/src/com/coderising/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..936736016f --- /dev/null +++ b/group27/1016908591/week04/src/com/coderising/jvm/constant/NullConstantInfo.java @@ -0,0 +1,13 @@ +package com.coderising.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo(){ + + } + @Override + public int getType() { + return -1; + } + +} diff --git a/group27/1016908591/week04/src/com/coderising/jvm/constant/StringInfo.java b/group27/1016908591/week04/src/com/coderising/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..f1f8eb4ed4 --- /dev/null +++ b/group27/1016908591/week04/src/com/coderising/jvm/constant/StringInfo.java @@ -0,0 +1,26 @@ +package com.coderising.jvm.constant; + +public class StringInfo extends ConstantInfo{ + private int type = ConstantInfo.STRING_INFO; + private int index; + public StringInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } + + + public String toString(){ + return this.getConstantPool().getUTF8String(index); + } + +} diff --git a/group27/1016908591/week04/src/com/coderising/jvm/constant/UTF8Info.java b/group27/1016908591/week04/src/com/coderising/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..5cac9f04f7 --- /dev/null +++ b/group27/1016908591/week04/src/com/coderising/jvm/constant/UTF8Info.java @@ -0,0 +1,32 @@ +package com.coderising.jvm.constant; + +public class UTF8Info extends ConstantInfo{ + private int type = ConstantInfo.UTF8_INFO; + private int length ; + private String value; + public UTF8Info(ConstantPool pool) { + super(pool); + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getType() { + return type; + } + @Override + public String toString() { + return "UTF8Info [type=" + type + ", length=" + length + ", value=" + value +")]"; + } + public String getValue() { + return value; + } + public void setValue(String value) { + this.value = value; + } + + + +} diff --git a/group27/1016908591/week04/src/com/coderising/jvm/loader/ClassFileLoader.java b/group27/1016908591/week04/src/com/coderising/jvm/loader/ClassFileLoader.java index b1b316dbeb..122f174ab6 100644 --- a/group27/1016908591/week04/src/com/coderising/jvm/loader/ClassFileLoader.java +++ b/group27/1016908591/week04/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -15,9 +15,179 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.test.ClassFileParser; + public class ClassFileLoader { +/* + private List clzPaths = new ArrayList(); + + public byte[] readBinaryCode(String className) { + className = className.replace('.', File.separatorChar); + + for(String path:this.clzPaths) + { + String clzFileName = path + File.separatorChar+className; + byte[] codes = loadClassFile_V2(clzFileName); + if(codes != null){ + return codes; + } + + } + + return null; + + + } + + private byte[] loadClassFile_V2(String clzFileName) { + File f= new File(clzFileName); + try { + return IOUtils.toByteArray(new FileInputStream(f)); + + } catch (Exception e) { + + return null; + } + + } + + //第一种加载类的方法 + private byte[] loadClassFile_V1(String clzFileName) { + BufferedInputStream bis = null; + try{ + File f = new File(clzFileName); + bis = new BufferedInputStream(new FileInputStream(f)); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int length = -1; + while((length = bis.read(buffer))!=-1) + { + bos.write(buffer,0,length); + + } + byte[] codes = bos.toByteArray(); + return codes; + }catch(IOException e){ + e.printStackTrace(); + return null; + } +/* + public void addClassPath(String path) { + if(this.clzPaths.contains(path)) + { + return; + } + this.clzPaths.add(path); + + } + + public String getClassPath() { + int count = 0; + String clzP = null; + for(String clzPathName:clzPaths){ + if(count clzPaths = new ArrayList(); /* @@ -97,7 +267,7 @@ public String getClassPath() { public byte[] readBinaryCode(String className) throws IOException { className = className.replace('.', File.separatorChar); for(String path:this.clzPaths){ - String clz = path+File.separatorChar+className; + String clz = path+File.separatorChar+className+".class"; byte[] codes = loadClassFile_V2(clz); if(codes!=null){ return codes; @@ -110,6 +280,8 @@ public byte[] readBinaryCode(String className) throws IOException { return null; } + + private byte[] loadClassFile_V2(String clz) throws IOException { BufferedInputStream in = null; @@ -139,7 +311,8 @@ private byte[] loadClassFile_V2(String clz) throws IOException { return null; } - + + /* } @@ -173,8 +346,14 @@ public String getClassPathV1(){ return StringUtils.join(this.clzPaths,";"); } */ - - - + public ClassFile loadClass(String className) throws IOException { + //变成字节数组 + byte[] codes = this.readBinaryCode(className); + + ClassFileParser parser = new ClassFileParser(); + //把字节数组传给解析类 + return parser.parse(codes); + + } } diff --git a/group27/1016908591/week04/src/com/coderising/jvm/test/ByteCodeIterator.java b/group27/1016908591/week04/src/com/coderising/jvm/test/ByteCodeIterator.java new file mode 100644 index 0000000000..75c57e5755 --- /dev/null +++ b/group27/1016908591/week04/src/com/coderising/jvm/test/ByteCodeIterator.java @@ -0,0 +1,47 @@ +package com.coderising.jvm.test; + +import java.lang.reflect.Array; +import java.util.Arrays; + +import com.coderising.jvm.util.Util; + +public class ByteCodeIterator { + + + + byte[] codes; + int pos = 0; + + public ByteCodeIterator(byte[] codes) { + this.codes = codes; + + } + public int nextU1ToInt() { + + return Util.byteToInt(new byte[]{codes[pos++]}); + } + + public int nextU2ToInt() { + + return Util.byteToInt(new byte[]{codes[pos++],codes[pos++]}); + } + public int nextU4ToInt() { + + return Util.byteToInt(new byte[]{codes[pos++],codes[pos++],codes[pos++],codes[pos++]}); + } + + public String nextU4ToHexString() { + + return Util.byteToHexString(new byte[]{codes[pos++],codes[pos++],codes[pos++],codes[pos++]}); + } + public byte[] getBytes(int len) { + if (pos+len>=codes.length) { + throw new ArrayIndexOutOfBoundsException(); + } + byte[] data = Arrays.copyOfRange(codes, pos, pos+len); + pos +=len; + return data; + } + + +} diff --git a/group27/1016908591/week04/src/com/coderising/jvm/test/ClassFileParser.java b/group27/1016908591/week04/src/com/coderising/jvm/test/ClassFileParser.java new file mode 100644 index 0000000000..1ebd2d4c1b --- /dev/null +++ b/group27/1016908591/week04/src/com/coderising/jvm/test/ClassFileParser.java @@ -0,0 +1,114 @@ +package com.coderising.jvm.test; + +import java.io.UnsupportedEncodingException; + +import javax.management.RuntimeErrorException; + +import com.coderising.jvm.clz.AccessFlag; +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.clz.ClassIndex; +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.FieldRefInfo; +import com.coderising.jvm.constant.MethodRefInfo; +import com.coderising.jvm.constant.NameAndTypeInfo; +import com.coderising.jvm.constant.NullConstantInfo; +import com.coderising.jvm.constant.StringInfo; +import com.coderising.jvm.constant.UTF8Info; + +public class ClassFileParser { + + public ClassFile parse(byte[] codes) { + ClassFile clzFile = new ClassFile(); + ByteCodeIterator iter = new ByteCodeIterator(codes); + String magicNumber = iter.nextU4ToHexString(); + if(!"cafebabe".equals(magicNumber)){ + return null; + } + //读版本号 + clzFile.setMinorVersion(iter.nextU2ToInt()); + clzFile.setMajorVersion(iter.nextU2ToInt()); + //读常量池 + ConstantPool pool = parseConstantPool(iter); + clzFile.setConstPool(pool); + return clzFile; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + + return null; + } + + private ClassIndex parseClassInfex(ByteCodeIterator iter) { + + return null; + + } + + private ConstantPool parseConstantPool(ByteCodeIterator iter) { + //取出常量池的个数 + int constPoolCount = iter.nextU2ToInt(); + System.out.println("Constant pool Count:"+constPoolCount); + //定义一个常量池 + ConstantPool pool = new ConstantPool(); + //因为数组的第零项是无效的,数组从0开始,但是JVM确从1开始 + pool.addConstantInfo(new NullConstantInfo()); + + for(int i = 1;i<=constPoolCount-1;i++){ + int tag = iter.nextU1ToInt(); + + if(tag == 7){ + //class Info + int utf8Index = iter.nextU2ToInt(); + ClassInfo clzInfo = new ClassInfo(pool); + clzInfo.setUtf8Index(utf8Index); + //把classInfo加入到常量池中 + pool.addConstantInfo(clzInfo); + }else if(tag == 1){ + int len = iter.nextU2ToInt(); + byte[] data = iter.getBytes(len); + String value = null; + try { + value = new String(data,"UTF-8"); + } catch (UnsupportedEncodingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + UTF8Info utf8str = new UTF8Info(pool); + utf8str.setLength(len); + utf8str.setValue(value); + pool.addConstantInfo(utf8str); + + } + else if(tag == 8){ + StringInfo info = new StringInfo(pool); + info.setIndex(iter.nextU2ToInt()); + pool.addConstantInfo(info); + }else if(tag == 9){ + FieldRefInfo field = new FieldRefInfo(pool); + field.setClassInfoIndex(iter.nextU2ToInt()); + field.setNameAndTypeIndex(iter.nextU2ToInt()); + pool.addConstantInfo(field); + }else if (tag == 10) { + MethodRefInfo method = new MethodRefInfo(pool); + method.setClassInfoIndex(iter.nextU2ToInt()); + method.setNameAndTypeIndex(iter.nextU2ToInt()); + pool.addConstantInfo(method); + + }else if(tag == 12){ + NameAndTypeInfo nameType = new NameAndTypeInfo(pool); + nameType.setIndex1(iter.nextU2ToInt()); + nameType.setIndex2(iter.nextU2ToInt()); + pool.addConstantInfo(nameType); + }else{ + throw new RuntimeErrorException(null, "the constant pool tag"+tag+"has not been implemented yet "); + } + } + + + System.out.println("Finshed reading Constant pool"); + return pool; + } + + +} diff --git a/group27/1016908591/week04/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group27/1016908591/week04/src/com/coderising/jvm/test/ClassFileloaderTest.java index 5801c7ca04..9119be2105 100644 --- a/group27/1016908591/week04/src/com/coderising/jvm/test/ClassFileloaderTest.java +++ b/group27/1016908591/week04/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -7,6 +7,13 @@ import org.junit.Before; import org.junit.Test; +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.clz.ClassIndex; +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.MethodRefInfo; +import com.coderising.jvm.constant.NameAndTypeInfo; +import com.coderising.jvm.constant.UTF8Info; import com.coderising.jvm.loader.ClassFileLoader; @@ -16,9 +23,28 @@ public class ClassFileloaderTest { - static String path1 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\mini-jvm\\bin"; + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + + static String path1 = "E:\\Git\\myGit\\coding2017\\group27\\1016908591\\week04\\bin"; + static String path2 = "C:\temp"; + static ClassFile clzFile = null; + static { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "com.coderising.jvm.test.EmployeeV1"; + + + try { + clzFile = loader.loadClass(className); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + clzFile.print(); + } @Before @@ -49,14 +75,8 @@ public void testClassFileLength() throws IOException { loader.addClassPath(path1); String className = "com.coderising.jvm.test.EmployeeV1"; - //装载这个类 - byte[] byteCodes = null; - try { - byteCodes = loader.readBinaryCode(className); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + + byte[] byteCodes = loader.readBinaryCode(className); // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 Assert.assertEquals(1056, byteCodes.length); @@ -72,7 +92,7 @@ public void testMagicNumber() throws IOException{ byte[] byteCodes = loader.readBinaryCode(className); byte[] codes = new byte[]{byteCodes[0],byteCodes[1],byteCodes[2],byteCodes[3]}; - //这个函数是关于16进制字符串 + String acctualValue = this.byteToHexString(codes); Assert.assertEquals("cafebabe", acctualValue); @@ -80,21 +100,113 @@ public void testMagicNumber() throws IOException{ + private String byteToHexString(byte[] codes ){ + StringBuffer buffer = new StringBuffer(); + for(int i=0;i", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(10); + Assert.assertEquals("(Ljava/lang/String;I)V", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(11); + Assert.assertEquals("Code", utf8Info.getValue()); + } + + { + MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(12); + Assert.assertEquals(3, methodRef.getClassInfoIndex()); + Assert.assertEquals(13, methodRef.getNameAndTypeIndex()); + } + + { + NameAndTypeInfo nameAndType = (NameAndTypeInfo) pool.getConstantInfo(13); + Assert.assertEquals(9, nameAndType.getIndex1()); + Assert.assertEquals(14, nameAndType.getIndex2()); + } + //抽查几个吧 + { + MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(45); + Assert.assertEquals(1, methodRef.getClassInfoIndex()); + Assert.assertEquals(46, methodRef.getNameAndTypeIndex()); + } + + { + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(53); + Assert.assertEquals("EmployeeV1.java", utf8Info.getValue()); + } + } + @Test + public void testClassIndex(){ + + ClassIndex clzIndex = clzFile.getClzIndex(); + ClassInfo thisClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getThisClassIndex()); + ClassInfo superClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getSuperClassIndex()); + + + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); + Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); + } + + } diff --git a/group27/1016908591/week04/src/com/coding/basic/stack/Stack.java b/group27/1016908591/week04/src/com/coding/basic/stack/Stack.java new file mode 100644 index 0000000000..9a35110681 --- /dev/null +++ b/group27/1016908591/week04/src/com/coding/basic/stack/Stack.java @@ -0,0 +1,44 @@ +package com.coding.basic.stack; +import java.util.Arrays; +import java.util.EmptyStackException; + + +import com.coding.basic.array.ArrayList; + +public class Stack { + private ArrayList elementData = new ArrayList(); + private int topIndex =-1;//栈顶元素索引 + private static final int DEFAULT_MAX_SIZE = 50; + private int length; + + //压入一个元素 + public void push(Object o){ + topIndex++; + elementData.add(o); + + + + } + + public Object pop(){ + if(elementData.size() ==0 ){ + throw new EmptyStackException(); + } + topIndex--; + return elementData.remove(elementData.size()-1); + + } + + public Object peek(){ + if(elementData.size()!=1){ + return elementData.get(elementData.size()-1); + } + return null; + } + public boolean isEmpty(){ + return topIndex>0; + } + public int size(){ + return topIndex; + } +} diff --git a/group27/1016908591/week04/src/com/coding/basic/stack/StackUtil.java b/group27/1016908591/week04/src/com/coding/basic/stack/StackUtil.java new file mode 100644 index 0000000000..c205c101ce --- /dev/null +++ b/group27/1016908591/week04/src/com/coding/basic/stack/StackUtil.java @@ -0,0 +1,102 @@ +package com.coding.basic.stack; + +import java.util.ArrayList; + + + +public class StackUtil { + + + /** + * 假设栈中的元素是Integer, 从栈顶到栈底是 : 5,4,3,2,1 调用该方法后, 元素次序变为: 1,2,3,4,5 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + */ + public static void reverse(Stack s) { + Stack newStack = new Stack(); + while(!s.isEmpty()){ + newStack.push(s.peek()); + s.pop(); + } + s = newStack; + + + } + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s,Object o) { + Stack newStack = new Stack(); + while(s.isEmpty()){ + if(o == s.peek()){ + s.pop(); + break; + }else { + newStack.push(s.pop()); + + } + + } + while(!newStack.isEmpty()){ + s.push(newStack.pop()); + } + + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * @param len + * @return + */ + public static Object[] getTop(Stack s,int len) { + Stack newStack= new Stack(); + Object[] arr = (Object[]) new Object(); + for(int count = 0;count Date: Sun, 9 Apr 2017 13:47:21 +0800 Subject: [PATCH 088/203] Ralf --- .../coderising/litestruts/LoginAction.java" | 34 ++ .../com/coderising/litestruts/ReadXml.java" | 71 +++ .../com/coderising/litestruts/StrutTEST.java" | 37 ++ .../com/coderising/litestruts/Struts.java" | 93 +++ .../coderising/litestruts/StrutsTest.java" | 40 ++ .../com/coderising/litestruts/View.java" | 28 + .../com/coderising/litestruts/xmlTest.java" | 24 + .../com/ralf/linkedlist/LinkedListTest.java" | 46 ++ .../com/ralf/linkedlist/MyLinkedList.java" | 528 ++++++++++++++++++ .../com/ralf/lru/LRUPageFrame.java" | 122 ++++ .../com/ralf/lru/LRUPageFrameTest.java" | 37 ++ .../data-struct/com/ralf/stack/MyStack.java" | 44 ++ .../com/ralf/stack/StackUtil.java" | 159 ++++++ .../com/ralf/stack/StackUtilsTest.java" | 87 +++ .../coderising/jvm/clasfile/AccessFlag.java" | 22 + .../coderising/jvm/clasfile/ClassFile.java" | 67 +++ .../coderising/jvm/clasfile/ClassIndex.java" | 21 + .../coderising/jvm/constant/ClassInfo.java" | 29 + .../jvm/constant/ConstantInfo.java" | 26 + .../jvm/constant/ConstantPool.java" | 22 + .../jvm/constant/FieldRefInfo.java" | 63 +++ .../coderising/jvm/constant/MethodInfo.java" | 63 +++ .../jvm/constant/NameAndTypeInfo.java" | 46 ++ .../jvm/constant/NullConstantInfo.java" | 11 + .../coderising/jvm/constant/StringInfo.java" | 32 ++ .../coderising/jvm/constant/Utf8Info.java" | 31 + .../jvm/loader/ByteCodeIterator.java" | 48 ++ .../jvm/loader/ClassFileLoader.java" | 97 ++++ .../jvm/loader/ClassFileParser.java" | 134 +++++ .../jvm/test/ClassFileLoaderTest.java" | 197 +++++++ .../com/coderising/jvm/test/EmployeeV1.java" | 32 ++ .../jvm/com/coderising/jvm/utils/Util.java" | 22 + 32 files changed, 2313 insertions(+) create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/LoginAction.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/ReadXml.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/StrutTEST.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/Struts.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/StrutsTest.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/View.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/xmlTest.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/linkedlist/LinkedListTest.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/linkedlist/MyLinkedList.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/lru/LRUPageFrame.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/lru/LRUPageFrameTest.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/MyStack.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/StackUtil.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/StackUtilsTest.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/clasfile/AccessFlag.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/clasfile/ClassFile.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/clasfile/ClassIndex.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/ClassInfo.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/ConstantInfo.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/ConstantPool.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/FieldRefInfo.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/MethodInfo.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/NameAndTypeInfo.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/NullConstantInfo.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/StringInfo.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/Utf8Info.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/loader/ByteCodeIterator.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/loader/ClassFileLoader.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/loader/ClassFileParser.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/test/ClassFileLoaderTest.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/test/EmployeeV1.java" create mode 100644 "group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/utils/Util.java" diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/LoginAction.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/LoginAction.java" new file mode 100644 index 0000000000..40b5de161a --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/LoginAction.java" @@ -0,0 +1,34 @@ +package com.coderising.litestruts; + +public class LoginAction { + + private String name; + private String passWord; + private String message; + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public String getPassWord() { + return passWord; + } + public void setPassWord(String passWord) { + this.passWord = passWord; + } + public String getMessage() { + return message; + } + public void setMessage(String message) { + this.message = message; + } + public String execute(){ + if ("test".equals(name) && "1234".equals(passWord)) { + this.message = "login successful"; + return "success"; + } + this.message = "login failed,please check your user/pwd"; + return "fail"; + } +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/ReadXml.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/ReadXml.java" new file mode 100644 index 0000000000..e971e779b6 --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/ReadXml.java" @@ -0,0 +1,71 @@ +package com.coderising.litestruts; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import org.dom4j.Attribute; +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.Element; +import org.dom4j.io.SAXReader; + +public class ReadXml { + + private Document document = null; + private HashMap hashMap; + + public ReadXml(String filename) { + try { + document = new SAXReader().read((filename)); + hashMap = new HashMap(); + } catch (DocumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public String parseXml(String actionName) { + + // List actions = document.selectNodes("//struts/action"); + String className = null; + Element root = document.getRootElement(); + List actions = root.elements("action"); + if (actions.isEmpty()) { + return null; + } + for (Iterator iter = actions.iterator(); iter.hasNext();) { + Element element = (Element) iter.next(); + Attribute attr1 = element.attribute("name"); + if (attr1.getValue().equals(actionName)) { + Attribute attr2 = element.attribute("class"); + className = attr2.getValue(); + //��ȡ��Ԫ�صĵ�����ֵ + for (Iterator iterator = element.elementIterator(); iterator + .hasNext();) { + Element childElement = (Element) iterator.next(); + Attribute childAttribute = childElement.attribute("name"); + hashMap.put(childAttribute.getValue(), + childElement.getText()); + } + } + + } + return className; + } + + public String getJsp(String result) { + if (result == null) { + return null; + } + String string_jsp = null; + if (!hashMap.isEmpty()) { + for (String string : hashMap.keySet()) { + if (result.equals(string)) { + string_jsp = hashMap.get(string); + } + } + } + return string_jsp; + } +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/StrutTEST.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/StrutTEST.java" new file mode 100644 index 0000000000..7921041560 --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/StrutTEST.java" @@ -0,0 +1,37 @@ +package com.coderising.litestruts; + +import java.util.HashMap; + +import org.junit.Assert; +import org.junit.Test; + +public class StrutTEST { + + @Test + public void runActionSuccess() { + String action = "login"; + + HashMap hashMap = new HashMap(); + hashMap.put("name", "test"); + hashMap.put("password", "1234"); + + View view = Struts.runAction(action, hashMap); + Assert.assertEquals("login successful", view.getParameters().get("message")); + Assert.assertEquals("/jsp/homepage.jsp", view.getJsp()); + } + + @Test + public void runActionFail(){ +String action = "login"; + + HashMap hashMap = new HashMap(); + hashMap.put("name", "test"); + hashMap.put("password", "12345"); + + View view = Struts.runAction(action, hashMap); + Assert.assertEquals("login failed,please check your user/pwd", view.getParameters().get("message")); + Assert.assertEquals("/jsp/showLogin.jsp", view.getJsp()); + + } + +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/Struts.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/Struts.java" new file mode 100644 index 0000000000..2892617845 --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/Struts.java" @@ -0,0 +1,93 @@ +package com.coderising.litestruts; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +public class Struts { + + private static final String NAME = "name"; + private static final String PASSWORD = "password"; + private static String excuteString; + private static Object object = null;// ���ط����ʵ�� + private static Class actionClass = null;// �����ȡ���� + + @SuppressWarnings("unchecked") + public static View runAction(String actionName, + Map parameters) { + // ��ȡ�����ļ�struts.xml + View view = new View(); + ReadXml readXml = new ReadXml("E:\\struts.xml"); + String classNameString = readXml.parseXml(actionName);//��ȡxml + object = initAction(classNameString);//ͨ�������ʼ���� + + excuteMethod(parameters);//ִ��setter��excute���� + + view.setParameterMap(setMapParameter());//��ȡ���е�getter������ִ�к󽫷������ͽ�����浽view�� + String jspResult = readXml.getJsp(excuteString);//��ȡjsp���� + view.setJsp(jspResult); + + return view; + } + + public static Object initAction(String classNameString) { + System.out.println(classNameString); + try { + actionClass = Class.forName(classNameString); + } catch (ClassNotFoundException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + Object newObject = null; + try { + newObject = actionClass.newInstance(); + } catch (InstantiationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return newObject; + } + + public static void excuteMethod(Map parameters) { + + try { + Method methodOfName = actionClass + .getMethod("setName", String.class); + methodOfName.invoke(object, parameters.get(NAME)); + // + Method methodOfPassword = actionClass.getMethod("setPassWord", + String.class); + methodOfPassword.invoke(object, parameters.get(PASSWORD)); + + Method excuteMethod = actionClass.getMethod("execute"); + excuteString = (String) excuteMethod.invoke(object); + + } catch (Exception e) { + // TODO: handle exception + } + } + + public static Map setMapParameter() { + + Method[] getterMethods = actionClass.getMethods(); + HashMap hashMap = new HashMap<>(); + + for (int i = 0; i < getterMethods.length; i++) { + String getterName = getterMethods[i].getName(); + if (getterName.startsWith("get")) { + try { + String value = (String) getterMethods[i].invoke(object); + hashMap.put(getterName.substring(3).toLowerCase(), value); + //System.out.println("----" + getterName.substring(2)); + } catch (Exception e) { + // TODO: handle exception + } + + } + } + return hashMap; + } +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/StrutsTest.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/StrutsTest.java" new file mode 100644 index 0000000000..b7f0884f41 --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/StrutsTest.java" @@ -0,0 +1,40 @@ +package com.coderising.litestruts; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; + +public class StrutsTest { + + @Test + public void testLoginActionSuccess() { + + String actionName = "login"; + + Map params = new HashMap(); + params.put("name","test"); + params.put("password","1234"); + + + View view = Struts.runAction(actionName,params); + + Assert.assertEquals("/jsp/homepage.jsp", view.getJsp()); + Assert.assertEquals("login successful", view.getParameters().get("message")); + } + + @Test + public void testLoginActionFailed() { + String actionName = "login"; + Map params = new HashMap(); + params.put("name","test"); + params.put("password","123456"); //�����Ԥ��IJ�һ�� + + View view = Struts.runAction(actionName,params); + + Assert.assertEquals("/jsp/showLogin.jsp", view.getJsp()); + Assert.assertEquals("login failed,please check your user/pwd", view.getParameters().get("message")); + } + +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/View.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/View.java" new file mode 100644 index 0000000000..bda8419e5f --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/View.java" @@ -0,0 +1,28 @@ +package com.coderising.litestruts; + +import java.util.Map; + +public class View { + + private String jsp; + private Map parameter; + + public String getJsp() { + return jsp; + } + + public View setJsp(String jsp) { + this.jsp = jsp; + return this; + } + + public Map getParameters() { + return parameter; + } + + public View setParameterMap(Map parameter) { + this.parameter = parameter; + return this; + } + +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/xmlTest.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/xmlTest.java" new file mode 100644 index 0000000000..cd5edf1143 --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/coderising/litestruts/xmlTest.java" @@ -0,0 +1,24 @@ +package com.coderising.litestruts; + +import java.util.HashMap; +import java.util.Map; + +public class xmlTest { + + /** + * @param args + */ + public static void main(String[] args) { + // TODO Auto-generated method stub + String actionName = "login"; + + Map params = new HashMap(); + params.put("name","test"); + params.put("password","1234"); + + View view = Struts.runAction(actionName,params); + String str = view.getJsp(); + System.out.println(str); + } + +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/linkedlist/LinkedListTest.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/linkedlist/LinkedListTest.java" new file mode 100644 index 0000000000..4a800335e5 --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/linkedlist/LinkedListTest.java" @@ -0,0 +1,46 @@ +package com.ralf.linkedlist; + +import BasicData.MyIterator; + +public class LinkedListTest { + + /** + * @param args + */ + @SuppressWarnings("unchecked") + public static void main(String[] args) { + // TODO Auto-generated method stub + MyLinkedList list = new MyLinkedList<>(); + + MyLinkedList listB = new MyLinkedList<>(); + MyLinkedList listC = new MyLinkedList<>(); + list.add(11); + list.add(12); + list.add(13); + list.add(14); + list.add(15); + list.add(17); + list.add(18); + + listB.add(10); + listB.add(12); + listB.add(14); + listB.add(15); + listB.add(18); + + + listC = (MyLinkedList) list.intersection(listB); + + + System.out.println(listC.size()); + + MyIterator iterator = listC.iterator(); + while(iterator.hasNext()){ + Integer integer = iterator.Next(); + System.out.println(integer); + } + + + } + +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/linkedlist/MyLinkedList.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/linkedlist/MyLinkedList.java" new file mode 100644 index 0000000000..7ae0787ed0 --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/linkedlist/MyLinkedList.java" @@ -0,0 +1,528 @@ +package com.ralf.linkedlist; + +import java.util.Arrays; +import java.util.Objects; +import java.util.TreeSet; + +import BasicData.MyArrayList; +import BasicData.MyIterator; +import BasicData.MyList; + +public class MyLinkedList> implements MyList { + + private Node head;// ָ��ͷ����ʼ������Ϊ�� + // private Node tail;// ָ��β���Ľڵ� + private int size; + + public MyLinkedList() { + this.head = new Node(null); + this.size = 0; + } + + private static class Node { + Node next = null; + T item = null; + + public Node(T t) { + item = t; + } + + } + + @Override + public boolean add(T t) { + // TODO Auto-generated method stub + return addLast(t); + } + + @Override + public void add(int index, T t) { + // TODO Auto-generated method stub + if (index < 0 || index > size) { + throw new IndexOutOfBoundsException(); + } + Node newNode = new Node(t); + if (index == 0) { + Node oldNode = head.next; + head.next = newNode; + newNode.next = oldNode; + size++; + } + + else { + Node current = getNode(index - 1); + newNode.next = current.next; + current.next = newNode; + size++; + } + + } + + @Override + public int size() { + // TODO Auto-generated method stub + return size; + } + + @Override + public T remove(int index) { + // TODO Auto-generated method stub + if (index < 0 || index > size) { + throw new IndexOutOfBoundsException(); + } else if (index == 0) { + return removeFirst(); + } else if (index == size - 1) { + return removeLast(); + } else { + Node current = getNode(index - 1); + T data = current.next.item; + current.next.item = null; + current.next = current.next.next; + size--; + return data; + } + } + + @Override + public T set(int index, T t) { + // TODO Auto-generated method stub + Node current = getNode(index); + T data = current.item; + current.item = t; + return data; + } + + @Override + public T get(int index) { + // TODO Auto-generated method stub + T data = getNode(index).item; + return data; + } + + public int indexOf(T t) { + Node current = this.head; + int index = 0; + while (current.next != null) { + current = current.next; + if (Objects.equals(current.item, t)) { + return index; + } + index++; + } + return -1; + } + + private Node getNode(int index) { + + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException(); + } + Node current = this.head; + int m_size = 0; + while (current.next != null && m_size <= index) { + current = current.next; + m_size++; + } + return current; + } + + public boolean addFirst(T t) { + + if (head.next == null) { + Node current = new Node(t); + head.next = current; + current = null; + size++; + return true; + } else { + Node current = new Node(t); + current.next = head.next; + head.next = current; + size++; + return true; + } + } + + public boolean addLast(T t) { + + if (head.next == null) { + Node current = new Node(t); + head.next = current; + current.next = null; + size++; + return true; + } else { + Node current = new Node(t); + Node oldNode = getNode(size - 1); + oldNode.next = current; + current.next = null; + size++; + return true; + } + + } + + public T removeFirst() { + if (head.next == null) { + return null; + } else if (head.next.next == null) { + T data = head.next.item; + head.next.item = null; + head = null; + size--; + return data; + } else { + T data = head.next.item; + Node current = head.next.next; + head.next.item = null; + head.next = current; + size--; + return data; + } + } + + public T removeLast() { + if (head.next == null) { + return null; + } else if (head.next.next == null) { + T data = head.next.item; + head.next.item = null; + size--; + return data; + } else { + Node current = getNode(size - 2); + T data = current.next.item; + current.next.item = null; + current.next = null; + size--; + return data; + } + } + + public boolean isContain(T t){ + + if (head.next == null) { + return false; + } + Node current = head; + while(current.next != null){ + current = current.next; + if (Objects.equals(t, current.item)) { + return true; + } + } + return false; + } + + /** + * �Ѹ��������� ��������Ϊ 3->7->10 , ���ú��Ϊ 10->7->3 + */ + public void reverse() { + this.head.next = reverseList(head.next); + } + + private Node reverseList(Node mhead) { + + if (mhead == null || mhead.next == null) { + return mhead; + } + Node reHead = reverseList(mhead.next); + mhead.next.next = mhead; + mhead.next = null; + return reHead; + } + + /** + * ɾ��һ���������ĺ�벿�� ���磺list = 2->5->7->8 , ɾ���Ժ��ֵΪ 2->5 ���list = 2->5->7->8->10 + * ,ɾ���Ժ��ֵΪ2,5,7 + */ + public void removeLastHalf() { + + if (size < 2) { + return; + } + int index = (size - 1) / 2 + 1; + Node current = getNode(index - 1); + Node temp = current; + while (index < size) { + temp = temp.next; + temp.item = null; + index++; + } + size = (size - 1) / 2 + 1; + current.next = null; + } + + /** + * ɾ��һ����������ǰ�벿�� ���磺list = 2->5->7->8 , ɾ���Ժ��ֵΪ 7->8 ���list = 2->5->7->8->10 + * ,ɾ���Ժ��ֵΪ7,8,10 + */ + public void removeFirstHalf() { + + if (size < 2) { + return; + } + int maxIndex = size/ 2; + int index = 0; + Node current = head; + while (index < maxIndex) { + current = current.next; + current.item = null; + index++; + size--; + } + //size = (size - 1) / 2 + 1; + head.next = current.next; + } + + /** + * �ӵ�i��Ԫ�ؿ�ʼ�� ɾ��length ��Ԫ�� �� ע��i��0��ʼ + * + * @param i + * @param length + */ + public void remove(int i, int length) { + + if (i < 0 || i >= size || (i + length - 1) > size) { + throw new IndexOutOfBoundsException(); + } + int index = 0; + Node current; + if (i == 0) { + current = head; + } else { + current = getNode(i - 1); + } + Node temp = current; + while (index < length) { + current = current.next; + current.item = null; + index++; + } + if (current.next == null) { + if (i == 0) { + head.next = null; + } else { + temp.next = null; + } + } else { + if (i == 0) { + head.next = current.next; + } else { + temp.next = current.next; + } + } + size = size - length; + + } + + /** + * �ٶ���ǰ������list���������������е����� �ӵ�ǰ������ȡ����Щlist��ָ����Ԫ�� ���統ǰ���� = + * 11->101->201->301->401->501->601->701 listB = 1->3->4->6 + * ���صĽ��Ӧ����[101,301,401,601] + * + * @param list + */ + @SuppressWarnings("unchecked") + public int[] getElements(MyLinkedList list) { + int[] elements = new int[list.size]; + int i = 0; + MyIterator iterator = (MyIterator) list.iterator(); + while (iterator.hasNext()) { + int index = iterator.Next(); + if (index < this.size) { + Node current = getNode(index); + elements[i++] = (Integer) current.item; + } else { + elements[i++] = 0;// û�и�Ԫ��ʱֵΪ�㣬������int���ͣ���������ʱΪnull + } + } + return Arrays.copyOf(elements, i); + } + + /** + * ��֪�����е�Ԫ����ֵ�����������У����Ե��������洢�ṹ�� �ӵ�ǰ��������ɾ����list�г��ֵ�Ԫ�� + * + * @param list + */ + + public void subtract(MyLinkedList list) { + + if (list.size == 0) { + return; + } + MyIterator iterator = list.iterator(); + + while (iterator.hasNext()) { + T element = iterator.Next(); + int index = indexOf(element);// ��ǰ���������� + if (index != -1) { + remove(index); + } + } + } + + /** + * ɾ����������ֵ��ͬ�Ķ���Ԫ�أ�ʹ�ò���������Ա�������Ԫ�ص�ֵ������ͬ�� + */ + public void removeRepeatValues() { + if (head.next == null || head.next.next == null) { + return; + } + // �����Լ���MyArrayList + MyArrayList list = new MyArrayList<>(); + // �������� + Node current = head; + T obj = null; + while (current.next != null) { + current = current.next; + obj = current.item; + if (list.isContain(obj)) { + // int index = indexOf(obj); + remove(indexOf(obj)); // ��������remove(T t)������������ + + } else { + list.add(obj); + } + } + } + + /** + * ��֪��ǰ�����е�Ԫ����ֵ�����������У����Ե��������洢�ṹ�� ɾ����������ֵ��ͬ�Ķ���Ԫ�أ�ʹ�ò���������Ա�������Ԫ�ص�ֵ������ͬ�� + */ + public void removeDuplicateValues() { + + if (head.next == null || head.next.next == null) { + return; + } + Node current = head; + T obj = null; + while (current.next != null) { + current = current.next; + obj = current.item; + if (current.next != null && Objects.equals(obj, current.next.item)) { + // int index = indexOf(obj); + remove(indexOf(obj)); // ��������remove(T t)������������ + } + } + } + + /** + * ��֪�����е�Ԫ����ֵ�����������У����Ե��������洢�ṹ�� ��дһ��Ч���㷨��ɾ����������ֵ����min��С��max��Ԫ�أ������д���������Ԫ�أ� + * + * @param min + * @param max + */ + public void removeRange(int min, int max) { + + if (head.next == null) { + return; + } + Node current = head; + Integer integer;// Ŀǰֻ�Ƚ��������͵ģ�����Ӧ�����ͣ���Ҫʵ��Comparable�ӿ� + while (current.next != null) { + current = current.next; + integer = (Integer) current.item; + if (integer.intValue() > min && integer.intValue() < max) { + remove(indexOf(current.item)); + } + } + } + + /** + * ���赱ǰ�����Ͳ���listָ������������Ԫ����ֵ�����������У�ͬһ���е�Ԫ��ֵ������ͬ�� + * ��Ҫ������������C����Ԫ��Ϊ��ǰ������list��Ԫ�صĽ������ұ�C�е�Ԫ������ֵ������������ + * + * @param list + */ + public MyLinkedList intersection(MyLinkedList list) { + + if (list.size == 0 || head.next == null) { + return null; + } + MyLinkedList newLinked = new MyLinkedList(); + MyIterator iterator = list.iterator(); + //MyArrayList arrayList = new MyArrayList<>();//û���������� + //ArrayList arrayList = new ArrayList<>(); + TreeSet treeSet = new TreeSet<>(); + + while (iterator.hasNext()) { + T element = iterator.Next(); + if (isContain(element)) { + treeSet.add(element); + } + } + + for(T t : treeSet){ + newLinked.add(t); + } + return newLinked; + + } + /* + @SuppressWarnings("unchecked") + public MyLinkedList union(MyLinkedList list) { + + if (head.next == null) { + + if (list.size == 0) { + return null; + } else { + return list; + } + } else { + if (list.size == 0) { + return this; + } else { + + MyLinkedList newList = new MyLinkedList(); + TreeSet treeSet = new TreeSet<>();// ����MyArrayListװ���в�ͬԪ�أ����������ӵ�linkedlist�� + + Node current = head; + while (current.next != null) { + current = current.next; + treeSet.add(current.item); + } + MyIterator iterator = (MyIterator) list.iterator(); + while (iterator.hasNext()) { + treeSet.add(iterator.Next()); + } + for (T t : treeSet) { + newList.add(t); + } + return newList; + } + } + + } + + */ + public MyIterator iterator() { + + return new LinkedListIterator(); + } + + private class LinkedListIterator implements MyIterator { + + private int current = 0; + T data = null; + + @Override + public boolean hasNext() { + // TODO Auto-generated method stub + return (current < size); + } + + @Override + public T Next() { + // TODO Auto-generated method stub + if (hasNext()) { + data = getNode(current).item; + current++; + return data; + } + return null; + } + } + +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/lru/LRUPageFrame.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/lru/LRUPageFrame.java" new file mode 100644 index 0000000000..47fdbbe85c --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/lru/LRUPageFrame.java" @@ -0,0 +1,122 @@ +package com.ralf.lru; + +/** + * ˫������ʵ��LRU�㷨 + * @author Ralf + * + */ +public class LRUPageFrame { + + private static class Node { + private Node prev; + private Node next; + int pageNum; + + public Node(int pageNum) { + this.pageNum = pageNum; + } + } + + private int capacity; + private Node head; + private Node tail; + private int size; + + private void addFirst(int PageNum) { + Node node = new Node(PageNum); + if (head == null) { + node.next = null; + node.prev = null; + head = node; + tail = node; + this.size++; + } else { + node.next = head; + node.prev = null; + head.prev = node; + head = node; + this.size++; + } + } + + public LRUPageFrame(int capacity) { + this.capacity = capacity; + this.head = null; + this.tail = null; + } + + /** + * ��ȡ������� + * @param PageNum + */ + public void access(int PageNum) { + + Node node = getNode(PageNum); + if (node == null) { + if (size < capacity) { + addFirst(PageNum); + } else { + removeLast(); + addFirst(PageNum); + } + } else if (this.head.pageNum == PageNum) { + return; + } + else { + moveToHead(node); + } + } + + private void moveToHead(Node node) { + Node current = node; + if (node.pageNum == this.tail.pageNum) { + node.prev.next = null; + tail = node.prev; + + } else { + node.prev.next = node.next; + node.next.prev = node.prev; + } + current.next = head; + current.prev = null; + this.head = current; + + } + + private void removeLast() { + + Node preNode = tail.prev; + tail.prev.next = null; + tail.prev = null; + tail = preNode; + this.size--; + } + + private Node getNode(int PageNum) { + Node current = this.head; + while (current != null) { + if (current.pageNum == PageNum) { + return current; + } + current = current.next; + } + return null; + } + + public String toString() { + if (this.head == null) { + return null; + } + StringBuilder stringBuilder = new StringBuilder(); + Node current = this.head; + while (current != null) { + stringBuilder.append(current.pageNum); + if (current.next != null) { + stringBuilder.append(","); + } + current = current.next; + + } + return stringBuilder.toString(); + } +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/lru/LRUPageFrameTest.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/lru/LRUPageFrameTest.java" new file mode 100644 index 0000000000..b024277905 --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/lru/LRUPageFrameTest.java" @@ -0,0 +1,37 @@ +package com.ralf.lru; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class LRUPageFrameTest { + + @Before + public void setUp() throws Exception { + } + + @Test + public void test() { + + LRUPageFrame frame = new LRUPageFrame(3); + frame.access(7); + frame.access(0); + frame.access(1); + Assert.assertEquals("1,0,7", frame.toString()); + frame.access(2); + Assert.assertEquals("2,1,0", frame.toString()); + frame.access(0); + + Assert.assertEquals("0,2,1", frame.toString()); + + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(3); + Assert.assertEquals("3,0,2", frame.toString()); + frame.access(0); + Assert.assertEquals("0,3,2", frame.toString()); + frame.access(4); + Assert.assertEquals("4,0,3", frame.toString()); + } + +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/MyStack.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/MyStack.java" new file mode 100644 index 0000000000..63c81812e3 --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/MyStack.java" @@ -0,0 +1,44 @@ +package com.ralf.stack; + +import java.util.LinkedList; +import java.util.NoSuchElementException; + +/** + * ʵ�ֻ������ݽṹջ + * + * @author Ralf + * + */ +public class MyStack { + + private LinkedList linkedList; + + public MyStack() { + if (null == linkedList) { + linkedList = new LinkedList(); + } + } + + public void push(T t) { + linkedList.addFirst(t); + } + + public T pop() { + if (size() == 0) { + throw new NoSuchElementException(); + } + return linkedList.removeFirst(); + } + + public T peek() { + return (size() == 0) ? null : linkedList.getFirst(); + } + + public int size() { + return linkedList.size(); + } + + public boolean isEmpty(){ + return linkedList.isEmpty(); + } +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/StackUtil.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/StackUtil.java" new file mode 100644 index 0000000000..e2757af444 --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/StackUtil.java" @@ -0,0 +1,159 @@ +package com.ralf.stack; + +import java.util.NoSuchElementException; + +public class StackUtil { + + private static MyStack myStack = new MyStack<>(); + + /** + * ����ջ�е�Ԫ����Integer, ��ջ����ջ���� : 5,4,3,2,1 ���ø÷����� Ԫ�ش����Ϊ: 1,2,3,4,5 + * ע�⣺ֻ��ʹ��Stack�Ļ�����������push,pop,peek,isEmpty�� ����ʹ������һ��ջ������ + * + * @param + */ + public static void reverse(MyStack stack) { + + if (stack.isEmpty()) { + System.out.println("��ջΪ��ջ��"); + return; + } + @SuppressWarnings("unchecked") + T[] elements = (T[]) new Object[stack.size()]; + for (int i = 0; i < elements.length; i++) { + elements[i] = stack.pop(); + } + for (int i = 0; i < elements.length; i++) { + stack.push(elements[i]); + } + + } + + /** + * ɾ��ջ�е�ij��Ԫ�� ע�⣺ֻ��ʹ��Stack�Ļ�����������push,pop,peek,isEmpty�� ����ʹ������һ��ջ������ + * + * @param o + */ + public static void remove(MyStack s, T o) { + if (s.isEmpty()) { + System.out.println("��ջΪ�գ�"); + return; + } + MyStack stack = new MyStack<>(); + + while (!s.isEmpty()) { + T t = s.pop(); + if (t.equals(o)) { + PopAndPush(s, stack); + return; + } + stack.push(t); + } + throw new NoSuchElementException("��ջû�и�Ԫ�أ�"); + + } + + private static void PopAndPush(MyStack s, MyStack stack) { + while (!stack.isEmpty()) { + T t = stack.pop(); + s.push(t); + } + } + + /** + * ��ջ��ȡ��len��Ԫ��, ԭ����ջ��Ԫ�ر��ֲ��� ע�⣺ֻ��ʹ��Stack�Ļ�����������push,pop,peek,isEmpty�� + * ����ʹ������һ��ջ������ + * + * @param len + * @return + */ + @SuppressWarnings("unchecked") + public static T[] getTop(MyStack s, int len) { + + if (s.isEmpty() || len > s.size()) { + return null; + } + MyStack oldStack = s; + T[] elements = (T[]) new Object[len]; + for (int i = 0; i < len; i++) { + elements[i] = s.pop(); + } + s = oldStack; + return elements; + } + + /** + * �ַ���s ���ܰ�����Щ�ַ��� ( ) [ ] { }, a,b,c... x,yz ʹ�ö�ջ����ַ���s�е������Dz��dzɶԳ��ֵġ� ����s = + * "([e{d}f])" , ����ַ����е������dzɶԳ��֣� �÷�������true ��� s = "([b{x]y})", + * ����ַ����е����Ų��dzɶԳ��ֵģ� �÷�������false; + * + * @param s + * @return + */ + public static boolean isValidPairs(String s) { + + char[] ch = s.toCharArray(); + if (ch.length < 1) { + return false; + } + + MyStack leftStack = new MyStack<>(); + MyStack rightStack = new MyStack<>(); + + for (int i = 0; i < ch.length; i++) { + + switch (ch[i]) { + case '(': + leftStack.push(String.valueOf(ch[i])); + break; + + case '[': + leftStack.push(String.valueOf(ch[i])); + break; + + case '{': + leftStack.push(String.valueOf(ch[i])); + break; + + case ')': + rightStack.push(String.valueOf(ch[i])); + break; + + case ']': + rightStack.push(String.valueOf(ch[i])); + break; + + case '}': + rightStack.push(String.valueOf(ch[i])); + break; + + default: + break; + } + } + return isPair(leftStack, rightStack); + + } + + private static boolean isPair(MyStack leftStack, + MyStack rightStack) { + + if (leftStack.size() != rightStack.size()) { + return false; + } + + reverse(rightStack); + while (!leftStack.isEmpty()) { + + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(leftStack.pop()).append(rightStack.pop()); + + String pair = stringBuilder.toString(); + if (!pair.equals("()") && !pair.equals("[]") && !pair.equals("{}")) { + return false; + } + } + return true; + } + +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/StackUtilsTest.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/StackUtilsTest.java" new file mode 100644 index 0000000000..3782d490c4 --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/StackUtilsTest.java" @@ -0,0 +1,87 @@ +package com.ralf.stack; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class StackUtilsTest { + + @Before + public void setUp() throws Exception { + } + + @Test + public void testReverse() { + + MyStack stack = new MyStack<>(); + stack.push(1); + stack.push(2); + stack.push(3); + stack.push(4); + stack.push(5); + Assert.assertEquals(5, stack.size()); + + StackUtil.reverse(stack); + Assert.assertEquals(5, stack.size()); + + Assert.assertEquals(1, stack.pop().intValue()); + Assert.assertEquals(2, stack.pop().intValue()); + Assert.assertEquals(3, stack.pop().intValue()); + Assert.assertEquals(4, stack.pop().intValue()); + Assert.assertEquals(5, stack.pop().intValue()); + } + + @Test + public void testRemove() { + + MyStack stack = new MyStack<>(); + stack.push(1); + stack.push(2); + stack.push(3); + stack.push(4); + stack.push(5); + Assert.assertEquals(5, stack.size()); + + StackUtil.remove(stack, 3); + + Assert.assertEquals(4, stack.size()); + + Assert.assertEquals(5, stack.pop().intValue()); + Assert.assertEquals(4, stack.pop().intValue()); + Assert.assertEquals(2, stack.pop().intValue()); + Assert.assertEquals(1, stack.pop().intValue()); + } + + public void testGetTop() { + + MyStack stack = new MyStack<>(); + stack.push(1); + stack.push(2); + stack.push(3); + stack.push(4); + stack.push(5); + Assert.assertEquals(5, stack.size()); + + Integer[] integerReal = StackUtil.getTop(stack, 3); + int[] intExpeted = { 1, 2, 3 }; + int[] intReal = new int[integerReal.length]; + for (int i = 0; i < integerReal.length; i++) { + intReal[i] = integerReal[i]; + } + Assert.assertEquals(5, stack.size()); + Assert.assertArrayEquals(intExpeted, intReal); + + } + + @Test + public void testIsValidPair(){ + + String stringTrue = "([e{d}f])"; + String stringFalse = "([b{x]y})"; + + Assert.assertTrue(StackUtil.isValidPairs(stringTrue)); + Assert.assertFalse(StackUtil.isValidPairs(stringFalse)); + + } + +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/clasfile/AccessFlag.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/clasfile/AccessFlag.java" new file mode 100644 index 0000000000..b1d40c20ff --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/clasfile/AccessFlag.java" @@ -0,0 +1,22 @@ +package com.coderising.jvm.clasfile; + +public class AccessFlag { + + private int flag; + + public int getFlag() { + return flag; + } + + public void setFlag(int flag) { + this.flag = flag; + } + + public boolean isPublic(){ + return (this.flag & 0x0001) != 0; + } + + public boolean isFinalClass(){ + return (this.flag & 0x0010) != 0; + } +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/clasfile/ClassFile.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/clasfile/ClassFile.java" new file mode 100644 index 0000000000..01e63c1328 --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/clasfile/ClassFile.java" @@ -0,0 +1,67 @@ +package com.coderising.jvm.clasfile; + +import com.coderising.jvm.constant.ConstantPool; + +public class ClassFile { + + private int MinorVersion; + private int MajorVersion; + private String MagicNumer; + private ConstantPool pool; + private ClassIndex classIndex; + private AccessFlag accessFlag; + + public ConstantPool getPool() { + return pool; + } + + public void setPool(ConstantPool pool) { + this.pool = pool; + } + + public String getMagicNumer() { + return MagicNumer; + } + + public void setMagicNumer(String magicNumer) { + this.MagicNumer = magicNumer; + } + + public int getMinorVersion() { + return MinorVersion; + } + + public int getMajorVersion() { + return MajorVersion; + } + + public void setMinorVersion(int minorVersion) { + this.MinorVersion = minorVersion; + } + + public void setMajorVersion(int majorVersion) { + this.MajorVersion = majorVersion; + } + + public ConstantPool getConstantPool() { + + return this.pool; + } + + public ClassIndex getClassIndex() { + return classIndex; + } + + public void setClassIndex(ClassIndex classIndex) { + this.classIndex = classIndex; + } + + public AccessFlag getAccessFlag() { + return accessFlag; + } + + public void setAccessFlag(AccessFlag accessFlag) { + this.accessFlag = accessFlag; + } + +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/clasfile/ClassIndex.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/clasfile/ClassIndex.java" new file mode 100644 index 0000000000..c98eae755f --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/clasfile/ClassIndex.java" @@ -0,0 +1,21 @@ +package com.coderising.jvm.clasfile; + +public class ClassIndex { + + private int thisClassIndex; + private int superClassIndex; + + public int getThisClassIndex() { + return thisClassIndex; + } + public void setThisClassIndex(int thisClassIndex) { + this.thisClassIndex = thisClassIndex; + } + public int getSuperClassIndex() { + return superClassIndex; + } + public void setSuperClassIndex(int superClassIndex) { + this.superClassIndex = superClassIndex; + } + +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/ClassInfo.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/ClassInfo.java" new file mode 100644 index 0000000000..4f9077cbb6 --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/ClassInfo.java" @@ -0,0 +1,29 @@ +package com.coderising.jvm.constant; + +public class ClassInfo extends ConstantInfo{ + + private int type = ConstantInfo.CLASS_INFO; + private int Utf8Index; + + public ClassInfo(ConstantPool constantPool){ + super(constantPool); + } + public int getUtf8Index() { + return Utf8Index; + } + + public void setUtf8Index(int utf8Index) { + Utf8Index = utf8Index; + } + + public String getClassName(){ + Utf8Info utf8Info = (Utf8Info) this.constantPool.getConstantInfo(Utf8Index); + return utf8Info.getValue(); + } + + @Override + public int getType() { + return this.type; + } + +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/ConstantInfo.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/ConstantInfo.java" new file mode 100644 index 0000000000..bc2acc7c6e --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/ConstantInfo.java" @@ -0,0 +1,26 @@ +package com.coderising.jvm.constant; + +public abstract class ConstantInfo { + + public static final int UTF8_INFO = 1; + public static final int FLOAT_INFO = 4; + public static final int CLASS_INFO = 7; + public static final int STRING_INFO = 8; + public static final int FIELD_INFO = 9; + public static final int METHOD_INFO = 10; + public static final int NAME_AND_TYPE_INFO = 12; + + protected ConstantPool constantPool; + + public ConstantInfo(){} + + public ConstantInfo(ConstantPool constantPool){ + this.constantPool = constantPool; + } + + public ConstantPool getConstantPool(){ + return this.constantPool; + } + public abstract int getType(); + +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/ConstantPool.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/ConstantPool.java" new file mode 100644 index 0000000000..283e93d95a --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/ConstantPool.java" @@ -0,0 +1,22 @@ +package com.coderising.jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List constantInfos = new ArrayList(); + + public int getConstantNumber() { + return this.constantInfos.size() - 1; + } + + public void addConstantInfo(ConstantInfo constantInfo){ + this.constantInfos.add(constantInfo); + } + public Object getConstantInfo(int index) { + + return this.constantInfos.get(index); + } + +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/FieldRefInfo.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/FieldRefInfo.java" new file mode 100644 index 0000000000..22a7b5c5f7 --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/FieldRefInfo.java" @@ -0,0 +1,63 @@ +package com.coderising.jvm.constant; + +public class FieldRefInfo extends ConstantInfo { + + private int tag = ConstantInfo.FIELD_INFO; + private int Index_ClassInfo; + private int Index_NameAndType; + + public FieldRefInfo(ConstantPool constantPool) { + super(constantPool); + } + + public int getIndex_ClassInfo() { + return Index_ClassInfo; + } + + public void setIndex_ClassInfo(int index_ClassInfo) { + Index_ClassInfo = index_ClassInfo; + } + + public int getIndex_NameAndType() { + return Index_NameAndType; + } + + public void setIndex_NameAndType(int index_NameAndType) { + Index_NameAndType = index_NameAndType; + } + + public String getClassName() { + + ConstantPool pool = this.getConstantPool(); + + ClassInfo classInfo = (ClassInfo) pool + .getConstantInfo(getIndex_ClassInfo()); + return classInfo.getClassName(); + } + + public String getParameterAndTypeString() { + + int index = getIndex_NameAndType(); + ConstantPool pool = this.getConstantPool(); + + NameAndTypeInfo nameAndTypeInfo = (NameAndTypeInfo) pool + .getConstantInfo(index); + return nameAndTypeInfo.getDescribeInfo(); + } + + public String getMethodName() { + + int index = getIndex_NameAndType(); + ConstantPool pool = this.getConstantPool(); + + NameAndTypeInfo nameAndTypeInfo = (NameAndTypeInfo) pool + .getConstantInfo(index); + return nameAndTypeInfo.getNameInfo(); + } + + @Override + public int getType() { + return tag; + } + +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/MethodInfo.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/MethodInfo.java" new file mode 100644 index 0000000000..81cd6c3347 --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/MethodInfo.java" @@ -0,0 +1,63 @@ +package com.coderising.jvm.constant; + +public class MethodInfo extends ConstantInfo { + + private int tag = ConstantInfo.METHOD_INFO; + private int Index_ClassInfo; + private int Index_NameAndType; + + public MethodInfo(ConstantPool constantPool) { + super(constantPool); + } + + public int getIndex_ClassInfo() { + return Index_ClassInfo; + } + + public void setIndex_ClassInfo(int index_ClassInfo) { + Index_ClassInfo = index_ClassInfo; + } + + public int getIndex_NameAndType() { + return Index_NameAndType; + } + + public void setIndex_NameAndType(int index_NameAndType) { + Index_NameAndType = index_NameAndType; + } + + public String getClassName() { + + ConstantPool pool = this.getConstantPool(); + + ClassInfo classInfo = (ClassInfo) pool + .getConstantInfo(getIndex_ClassInfo()); + return classInfo.getClassName(); + } + + public String getParameterAndTypeString() { + int index = getIndex_NameAndType(); + ConstantPool pool = this.getConstantPool(); + + NameAndTypeInfo nameAndTypeInfo = (NameAndTypeInfo) pool + .getConstantInfo(index); + return nameAndTypeInfo.getDescribeInfo(); + + } + + public String getMethodName() { + + int index = getIndex_NameAndType(); + ConstantPool pool = this.getConstantPool(); + + NameAndTypeInfo nameAndTypeInfo = (NameAndTypeInfo) pool + .getConstantInfo(index); + return nameAndTypeInfo.getNameInfo(); + } + + @Override + public int getType() { + return this.tag; + } + +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/NameAndTypeInfo.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/NameAndTypeInfo.java" new file mode 100644 index 0000000000..c8731e9216 --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/NameAndTypeInfo.java" @@ -0,0 +1,46 @@ +package com.coderising.jvm.constant; + +public class NameAndTypeInfo extends ConstantInfo { + + private int tag = ConstantInfo.NAME_AND_TYPE_INFO; + private int Index_Name; + private int Index_Describe; + + public NameAndTypeInfo(ConstantPool constantPool){ + super(constantPool); + } + public int getIndex_Name() { + return Index_Name; + } + + public void setIndex_Name(int index_Name) { + Index_Name = index_Name; + } + + public int getIndex_Describe() { + return Index_Describe; + } + + public void setIndex_Describe(int index_Describe) { + Index_Describe = index_Describe; + } + + public String getNameInfo(){ + + ConstantPool pool = this.getConstantPool(); + Utf8Info utf8Info = (Utf8Info) pool.getConstantInfo(Index_Name); + return utf8Info.getValue(); + } + public String getDescribeInfo(){ + + ConstantPool pool = this.getConstantPool(); + Utf8Info utf8Info = (Utf8Info) pool.getConstantInfo(Index_Describe); + return utf8Info.getValue(); + } + + @Override + public int getType() { + return tag; + } + +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/NullConstantInfo.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/NullConstantInfo.java" new file mode 100644 index 0000000000..3428c1ea65 --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/NullConstantInfo.java" @@ -0,0 +1,11 @@ +package com.coderising.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo(){} + @Override + public int getType() { + return -1; + } + +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/StringInfo.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/StringInfo.java" new file mode 100644 index 0000000000..83339240f5 --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/StringInfo.java" @@ -0,0 +1,32 @@ +package com.coderising.jvm.constant; + +public class StringInfo extends ConstantInfo { + + private int tag = ConstantInfo.STRING_INFO; + private int index; + + public StringInfo(ConstantPool constantPool){ + super(constantPool); + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + + public String getStringName(){ + + ConstantPool pool = this.getConstantPool(); + Utf8Info utf8Info = (Utf8Info) pool.getConstantInfo(getIndex()); + return utf8Info.getValue(); + } + + @Override + public int getType() { + return tag; + } + +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/Utf8Info.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/Utf8Info.java" new file mode 100644 index 0000000000..35b28cdafc --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/constant/Utf8Info.java" @@ -0,0 +1,31 @@ +package com.coderising.jvm.constant; + +public class Utf8Info extends ConstantInfo{ + + private int tag = ConstantInfo.UTF8_INFO; + private int length; + private String value; + + public Utf8Info(ConstantPool constantPool){ + super(constantPool); + } + public String getValue() { + + return value; + } + public void setValue(String value) { + this.value = value; + } + + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + @Override + public int getType() { + return tag; + } + +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/loader/ByteCodeIterator.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/loader/ByteCodeIterator.java" new file mode 100644 index 0000000000..761a8db37e --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/loader/ByteCodeIterator.java" @@ -0,0 +1,48 @@ +package com.coderising.jvm.loader; + +import com.coderising.jvm.utils.Util; + +public class ByteCodeIterator { + + private byte[] codes; + private int pos; + + public ByteCodeIterator(byte[] codes){ + this.codes = codes; + pos = 0; + } + public int nextByteToInt(){ + if (pos < this.codes.length) { + return Util.bytesToInt(new byte[]{codes[pos++]}); + } + return -1; + } + public int next2BytesToInt(){ + if (pos < this.codes.length) { + return Util.bytesToInt(new byte[]{codes[pos++],codes[pos++]}); + } + return -1; + } + public String next2BytesToHexString(){ + if (pos < this.codes.length) { + return Util.bytesToHexString(new byte[]{codes[pos++],codes[pos++]}); + } + return null; + } + public String next4BytesToString(){ + if (pos < this.codes.length) { + return Util.bytesToHexString(new byte[]{codes[pos++],codes[pos++],codes[pos++],codes[pos++]}); + } + return null; + } + public byte[] getBytes(int length) { + if ((pos + length) < this.codes.length) { + byte[] by = new byte[length]; + for (int i = 0; i < by.length; i++) { + by[i] = this.codes[pos++]; + } + return by; + } + return null; + } +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/loader/ClassFileLoader.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/loader/ClassFileLoader.java" new file mode 100644 index 0000000000..96b3905428 --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/loader/ClassFileLoader.java" @@ -0,0 +1,97 @@ +package com.coderising.jvm.loader; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import com.coderising.jvm.clasfile.ClassFile; + +public class ClassFileLoader { + + private List list = new ArrayList(); + + public ClassFileLoader() { + + } + + public void addClassPath(String path) { + if (list.contains(path)) { + return; + } + list.add(path); + } + + public String getClassPath() { + if (list.size() == 0 || list == null) { + return null; + } + StringBuilder stringBuilder = new StringBuilder(); + for (int i = 0; i < list.size(); i++) { + if (i == list.size() - 1) { + stringBuilder.append(list.get(i)); + } else { + stringBuilder.append(list.get(i)).append(";"); + } + + } + return stringBuilder.toString(); + } + + public byte[] readBinaryCode(String className){ + + String clzName = className.replace(".", File.separator) + ".class";; + + for(String path : list){ + String fileName = path + File.separator + clzName; + byte[] codes = loadClassFile(fileName); + if (codes != null) { + return codes; + } + } + return null; + } + + private byte[] loadClassFile(String fileName){ + + BufferedInputStream bis = null; + File classFile = new File(fileName); + try { + bis = new BufferedInputStream(new FileInputStream(classFile)); + byte[] bytes_code = new byte[1024]; + int len = 0; + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + while((len = bis.read(bytes_code)) != -1){ + baos.write(bytes_code, 0, len); + } + return baos.toByteArray(); + } catch (IOException e) { + e.printStackTrace(); + } + finally{ + if (bis != null) { + try { + bis.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return null; + } + + public ClassFile loadClass(String className) { + + byte[] codes = this.readBinaryCode(className); + ClassFileParser clzPaser = new ClassFileParser(); + return clzPaser.parse(codes); + } + + +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/loader/ClassFileParser.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/loader/ClassFileParser.java" new file mode 100644 index 0000000000..5341bbc7c3 --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/loader/ClassFileParser.java" @@ -0,0 +1,134 @@ +package com.coderising.jvm.loader; + +import java.io.UnsupportedEncodingException; + +import com.coderising.jvm.clasfile.AccessFlag; +import com.coderising.jvm.clasfile.ClassFile; +import com.coderising.jvm.clasfile.ClassIndex; +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.FieldRefInfo; +import com.coderising.jvm.constant.MethodInfo; +import com.coderising.jvm.constant.NameAndTypeInfo; +import com.coderising.jvm.constant.NullConstantInfo; +import com.coderising.jvm.constant.StringInfo; +import com.coderising.jvm.constant.Utf8Info; + +public class ClassFileParser { + + public ClassFile parse(byte[] codes) { + + ClassFile clzFile = new ClassFile(); + + ByteCodeIterator iterator = new ByteCodeIterator(codes); + + // Magic Number + String Magic = iterator.next4BytesToString(); + clzFile.setMagicNumer(Magic); + + // Version Number + int MinorVersion = iterator.next2BytesToInt(); + int MajorVersion = iterator.next2BytesToInt(); + clzFile.setMinorVersion(MinorVersion); + clzFile.setMajorVersion(MajorVersion); + + clzFile.setPool(parseConstantPool(iterator)); + clzFile.setAccessFlag(parseAccessFlag(iterator)); + clzFile.setClassIndex(parseClassIndex(iterator)); + + return clzFile; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iterator) { + AccessFlag accessFlag = new AccessFlag(); + int flagValue = iterator.next2BytesToInt(); + accessFlag.setFlag(flagValue); + + return accessFlag; + } + + private ClassIndex parseClassIndex(ByteCodeIterator iterator) { + + ClassIndex classIndex = new ClassIndex(); + int thisClassIndex = iterator.next2BytesToInt(); + int superClassIndex = iterator.next2BytesToInt(); + classIndex.setThisClassIndex(thisClassIndex); + classIndex.setSuperClassIndex(superClassIndex); + + return classIndex; + } + + private ConstantPool parseConstantPool(ByteCodeIterator iterator) { + + ConstantPool pool = new ConstantPool(); + int ConstantNumber = iterator.next2BytesToInt(); + pool.addConstantInfo(new NullConstantInfo()); + + for (int i = 1; i <= ConstantNumber - 1; i++) { + int tag = iterator.nextByteToInt(); + + if (tag == 7) { + ClassInfo clzInfo = new ClassInfo(pool); + int utf8Index = iterator.next2BytesToInt(); + clzInfo.setUtf8Index(utf8Index); + pool.addConstantInfo(clzInfo); + } + else if(tag == 1){ + Utf8Info utf8Info = new Utf8Info(pool); + int length = iterator.next2BytesToInt(); + utf8Info.setLength(length); + byte[] utf8Bytes = iterator.getBytes(length); + String value = null; + try { + value = new String(utf8Bytes, "UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + utf8Info.setValue(value); + pool.addConstantInfo(utf8Info); + } + else if(tag == 12){ + NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(pool); + + int Index_Name = iterator.next2BytesToInt(); + int Index_Describe = iterator.next2BytesToInt(); + + nameAndTypeInfo.setIndex_Name(Index_Name); + nameAndTypeInfo.setIndex_Describe(Index_Describe); + pool.addConstantInfo(nameAndTypeInfo); + } + + else if(tag == 10){ + MethodInfo methofInfo = new MethodInfo(pool); + int Index_ClassInfo = iterator.next2BytesToInt(); + int Index_NameAndType = iterator.next2BytesToInt(); + + methofInfo.setIndex_ClassInfo(Index_ClassInfo); + methofInfo.setIndex_NameAndType(Index_NameAndType); + pool.addConstantInfo(methofInfo); + + } + + else if (tag == 9) { + + FieldRefInfo fieldRefInfo = new FieldRefInfo(pool); + int Index_ClassInfo = iterator.next2BytesToInt(); + int Index_NameAndType = iterator.next2BytesToInt(); + + fieldRefInfo.setIndex_ClassInfo(Index_ClassInfo); + fieldRefInfo.setIndex_NameAndType(Index_NameAndType); + pool.addConstantInfo(fieldRefInfo); + } + else if (tag == 8) { + + StringInfo stringInfo = new StringInfo(pool); + int index = iterator.next2BytesToInt(); + + stringInfo.setIndex(index); + pool.addConstantInfo(stringInfo); + } + } + return pool; + + } +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/test/ClassFileLoaderTest.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/test/ClassFileLoaderTest.java" new file mode 100644 index 0000000000..550e0cacd9 --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/test/ClassFileLoaderTest.java" @@ -0,0 +1,197 @@ +package com.coderising.jvm.test; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.coderising.jvm.clasfile.ClassFile; +import com.coderising.jvm.clasfile.ClassIndex; +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.FieldRefInfo; +import com.coderising.jvm.constant.MethodInfo; +import com.coderising.jvm.constant.NameAndTypeInfo; +import com.coderising.jvm.constant.Utf8Info; +import com.coderising.jvm.loader.ClassFileLoader; + +public class ClassFileLoaderTest { + + private static String path1 = "D:\\MyTest\\mini-jvm\\bin"; + private static String path2 = "C:\\temp"; + private final static String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + private static ClassFile clzFile = null; + static{ + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "com.coderising.jvm.test.EmployeeV1"; + + clzFile = loader.loadClass(className); + + } + + @Before + public void setUp() throws Exception { + } + + @Test + public void test() { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + loader.addClassPath(path2); + + String clzPath = loader.getClassPath(); + + Assert.assertEquals(path1 + ";" + path2, clzPath); + } + + @Test + public void ClassFileLengthTest(){ + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + + String className = "com.coderising.jvm.test.EmployeeV1"; + byte[] bytes = loader.readBinaryCode(className); + + Assert.assertEquals(1056, bytes.length); + } + + @Test + public void MagicNumberTest(){ + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + + String className = "com.coderising.jvm.test.EmployeeV1"; + byte[] byteCodes = loader.readBinaryCode(className); + + byte[] bytes = { byteCodes[0], byteCodes[1], byteCodes[2], byteCodes[3] }; + String actualString = byteToHexString(bytes); + Assert.assertEquals("cafebabe", actualString); + } + + private String byteToHexString(byte[] bytes) { + + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < bytes.length; i++) { + byte b = bytes[i]; + int value = b & 0xFF; + String strHex = Integer.toHexString(value); + if (strHex.length() < 2) { + strHex = "0" + strHex; + } + buffer.append(strHex); + } + return buffer.toString(); + } + + @Test + public void testVersion(){ + + Assert.assertEquals(0, clzFile.getMinorVersion()); + Assert.assertEquals(51, clzFile.getMajorVersion()); + } + + @Test + public void testConstant��ool(){ + + ConstantPool pool = clzFile.getConstantPool(); + + Assert.assertEquals(53, pool.getConstantNumber()); + + { + ClassInfo clzInfo = (ClassInfo)pool.getConstantInfo(1); + Assert.assertEquals(2, clzInfo.getUtf8Index()); + + Utf8Info utf8Info = (Utf8Info)pool.getConstantInfo(2); + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, utf8Info.getValue()); + } + + { + ClassInfo clzInfo = (ClassInfo)pool.getConstantInfo(3); + Assert.assertEquals(4, clzInfo.getUtf8Index()); + + Utf8Info utf8Info = (Utf8Info)pool.getConstantInfo(4); + Assert.assertEquals("java/lang/Object", utf8Info.getValue()); + } + + { + Utf8Info utf8Info = (Utf8Info)pool.getConstantInfo(5); + Assert.assertEquals("name", utf8Info.getValue()); + + utf8Info = (Utf8Info) pool.getConstantInfo(6); + Assert.assertEquals("Ljava/lang/String;", utf8Info.getValue()); + + utf8Info = (Utf8Info) pool.getConstantInfo(7); + Assert.assertEquals("age", utf8Info.getValue()); + + utf8Info = (Utf8Info) pool.getConstantInfo(8); + Assert.assertEquals("I", utf8Info.getValue()); + + utf8Info = (Utf8Info) pool.getConstantInfo(9); + Assert.assertEquals("", utf8Info.getValue()); + + utf8Info = (Utf8Info) pool.getConstantInfo(10); + Assert.assertEquals("(Ljava/lang/String;I)V", utf8Info.getValue()); + + utf8Info = (Utf8Info) pool.getConstantInfo(11); + Assert.assertEquals("Code", utf8Info.getValue()); + } + + { + MethodInfo methodRef = (MethodInfo)pool.getConstantInfo(12); + Assert.assertEquals(3, methodRef.getIndex_ClassInfo()); + Assert.assertEquals(13, methodRef.getIndex_NameAndType()); + } + + { + NameAndTypeInfo nameAndTypeInfo = (NameAndTypeInfo) pool.getConstantInfo(13); + Assert.assertEquals(9, nameAndTypeInfo.getIndex_Name()); + Assert.assertEquals(14, nameAndTypeInfo.getIndex_Describe()); + } + + { + MethodInfo methodRef = (MethodInfo)pool.getConstantInfo(45); + Assert.assertEquals(1, methodRef.getIndex_ClassInfo()); + Assert.assertEquals(46, methodRef.getIndex_NameAndType()); + } + + { + Utf8Info utf8Info = (Utf8Info) pool.getConstantInfo(53); + Assert.assertEquals("EmployeeV1.java", utf8Info.getValue()); + } + + { + FieldRefInfo fieldRefInfo = (FieldRefInfo) pool.getConstantInfo(28); + Assert.assertEquals(29, fieldRefInfo.getIndex_ClassInfo()); + Assert.assertEquals(31, fieldRefInfo.getIndex_NameAndType()); + + } + + } + + + @Test + public void testClassIndex(){ + + ClassIndex clzIndex = clzFile.getClassIndex(); + ClassInfo thisClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getThisClassIndex()); + ClassInfo superClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getSuperClassIndex()); + + + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); + Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); + } + + + + + + + + + + + + + +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/test/EmployeeV1.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/test/EmployeeV1.java" new file mode 100644 index 0000000000..39af3b3d32 --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/test/EmployeeV1.java" @@ -0,0 +1,32 @@ +package com.coderising.jvm.test; + +public class EmployeeV1 { + + private String name; + private int age; + + public EmployeeV1(String name, int age){ + + this.name = name; + this.age = age; + } + + public void setName(String name) { + this.name = name; + } + + public void setAge(int age) { + this.age = age; + } + + public void sayHello(){ + System.out.println("Hello , this is class Employee "); + } + + public static void main(String[] args) { + + EmployeeV1 p = new EmployeeV1("Andy",29); + p.sayHello(); + } + +} diff --git "a/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/utils/Util.java" "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/utils/Util.java" new file mode 100644 index 0000000000..56648f5db9 --- /dev/null +++ "b/group20/925290009/\347\254\254\344\272\224\346\254\241\344\275\234\344\270\232/jvm/com/coderising/jvm/utils/Util.java" @@ -0,0 +1,22 @@ +package com.coderising.jvm.utils; + +public class Util { + + public static int bytesToInt(byte[] by){ + String hexString = bytesToHexString(by); + return Integer.valueOf(hexString, 16).intValue(); + } + + public static String bytesToHexString(byte[] by){ + StringBuilder stringBuilder = new StringBuilder(); + for (int i = 0; i < by.length; i++) { + int value = by[i] & 0xFF; + String strHex = Integer.toHexString(value); + if(strHex.length()< 2){ + strHex = "0" + strHex; + } + stringBuilder.append(strHex); + } + return stringBuilder.toString(); + } +} From 5f13869c3159175a4ef15e5d7af7b6a81c321a01 Mon Sep 17 00:00:00 2001 From: jy97799 <977996067@qq.com> Date: Sun, 9 Apr 2017 16:27:46 +0800 Subject: [PATCH 089/203] =?UTF-8?q?4.9=E4=BD=9C=E4=B8=9A=20JVM=20ClassPars?= =?UTF-8?q?er&StackUtil?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/task5/jvm/clz/AccessFlag.java | 25 +++ .../src/task5/jvm/clz/ClassFile.java | 72 +++++++ .../src/task5/jvm/clz/ClassIndex.java | 19 ++ .../src/task5/jvm/constant/ClassInfo.java | 24 +++ .../src/task5/jvm/constant/ConstantInfo.java | 29 +++ .../src/task5/jvm/constant/ConstantPool.java | 37 ++++ .../src/task5/jvm/constant/FieldRefInfo.java | 54 +++++ .../src/task5/jvm/constant/MethodRefInfo.java | 55 +++++ .../task5/jvm/constant/NameAndTypeInfo.java | 45 +++++ .../task5/jvm/constant/NullConstantInfo.java | 13 ++ .../src/task5/jvm/constant/StringInfo.java | 26 +++ .../src/task5/jvm/constant/UTF8Info.java | 32 +++ .../task5/jvm/loader/ByteCodeIterator.java | 43 ++++ .../src/task5/jvm/loader/ClassFileLoader.java | 126 ++++++++++++ .../src/task5/jvm/loader/ClassFileParser.java | 77 +++++++ .../task5/jvm/test/ClassFileloaderTest.java | 191 ++++++++++++++++++ .../src/task5/jvm/test/EmployeeV1.java | 29 +++ .../src/task5/jvm/util/Util.java | 23 +++ .../1507_977996067/src/task5/stack/Stack.java | 31 +++ .../src/task5/stack/StackUtil.java | 87 ++++++++ 20 files changed, 1038 insertions(+) create mode 100644 group15/1507_977996067/src/task5/jvm/clz/AccessFlag.java create mode 100644 group15/1507_977996067/src/task5/jvm/clz/ClassFile.java create mode 100644 group15/1507_977996067/src/task5/jvm/clz/ClassIndex.java create mode 100644 group15/1507_977996067/src/task5/jvm/constant/ClassInfo.java create mode 100644 group15/1507_977996067/src/task5/jvm/constant/ConstantInfo.java create mode 100644 group15/1507_977996067/src/task5/jvm/constant/ConstantPool.java create mode 100644 group15/1507_977996067/src/task5/jvm/constant/FieldRefInfo.java create mode 100644 group15/1507_977996067/src/task5/jvm/constant/MethodRefInfo.java create mode 100644 group15/1507_977996067/src/task5/jvm/constant/NameAndTypeInfo.java create mode 100644 group15/1507_977996067/src/task5/jvm/constant/NullConstantInfo.java create mode 100644 group15/1507_977996067/src/task5/jvm/constant/StringInfo.java create mode 100644 group15/1507_977996067/src/task5/jvm/constant/UTF8Info.java create mode 100644 group15/1507_977996067/src/task5/jvm/loader/ByteCodeIterator.java create mode 100644 group15/1507_977996067/src/task5/jvm/loader/ClassFileLoader.java create mode 100644 group15/1507_977996067/src/task5/jvm/loader/ClassFileParser.java create mode 100644 group15/1507_977996067/src/task5/jvm/test/ClassFileloaderTest.java create mode 100644 group15/1507_977996067/src/task5/jvm/test/EmployeeV1.java create mode 100644 group15/1507_977996067/src/task5/jvm/util/Util.java create mode 100644 group15/1507_977996067/src/task5/stack/Stack.java create mode 100644 group15/1507_977996067/src/task5/stack/StackUtil.java diff --git a/group15/1507_977996067/src/task5/jvm/clz/AccessFlag.java b/group15/1507_977996067/src/task5/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..65e98c15e6 --- /dev/null +++ b/group15/1507_977996067/src/task5/jvm/clz/AccessFlag.java @@ -0,0 +1,25 @@ +package task5.jvm.clz; + +public class AccessFlag { + private int flagValue; + + public AccessFlag(int value) { + this.flagValue = value; + } + + public int getFlagValue() { + return flagValue; + } + + public void setFlagValue(int flag) { + this.flagValue = flag; + } + + public boolean isPublicClass(){ + return (this.flagValue & 0x0001) != 0; + } + public boolean isFinalClass(){ + return (this.flagValue & 0x0010) != 0; + } + +} \ No newline at end of file diff --git a/group15/1507_977996067/src/task5/jvm/clz/ClassFile.java b/group15/1507_977996067/src/task5/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..46717e108e --- /dev/null +++ b/group15/1507_977996067/src/task5/jvm/clz/ClassFile.java @@ -0,0 +1,72 @@ +package task5.jvm.clz; + +import task5.jvm.constant.ClassInfo; +import task5.jvm.constant.ConstantPool; + +public class ClassFile { + + private int minorVersion; + private int majorVersion; + + private AccessFlag accessFlag; + private ClassIndex clzIndex; + private ConstantPool pool; + + + public ClassIndex getClzIndex() { + return clzIndex; + } + public AccessFlag getAccessFlag() { + return accessFlag; + } + public void setAccessFlag(AccessFlag accessFlag) { + this.accessFlag = accessFlag; + } + + + + public ConstantPool getConstantPool() { + return pool; + } + public int getMinorVersion() { + return minorVersion; + } + public void setMinorVersion(int minorVersion) { + this.minorVersion = minorVersion; + } + public int getMajorVersion() { + return majorVersion; + } + public void setMajorVersion(int majorVersion) { + this.majorVersion = majorVersion; + } + public void setConstPool(ConstantPool pool) { + this.pool = pool; + + } + public void setClassIndex(ClassIndex clzIndex) { + this.clzIndex = clzIndex; + } + + public void print(){ + + if(this.accessFlag.isPublicClass()){ + System.out.println("Access flag : public "); + } + System.out.println("Class Name:"+ getClassName()); + + System.out.println("Super Class Name:"+ getSuperClassName()); + + + } + + private String getClassName(){ + int thisClassIndex = this.clzIndex.getThisClassIndex(); + ClassInfo thisClass = (ClassInfo)this.getConstantPool().getConstantInfo(thisClassIndex); + return thisClass.getClassName(); + } + private String getSuperClassName(){ + ClassInfo superClass = (ClassInfo)this.getConstantPool().getConstantInfo(this.clzIndex.getSuperClassIndex()); + return superClass.getClassName(); + } +} diff --git a/group15/1507_977996067/src/task5/jvm/clz/ClassIndex.java b/group15/1507_977996067/src/task5/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..5aba6a953a --- /dev/null +++ b/group15/1507_977996067/src/task5/jvm/clz/ClassIndex.java @@ -0,0 +1,19 @@ +package task5.jvm.clz; + +public class ClassIndex { + private int thisClassIndex; + private int superClassIndex; + + public int getThisClassIndex() { + return thisClassIndex; + } + public void setThisClassIndex(int thisClassIndex) { + this.thisClassIndex = thisClassIndex; + } + public int getSuperClassIndex() { + return superClassIndex; + } + public void setSuperClassIndex(int superClassIndex) { + this.superClassIndex = superClassIndex; + } +} \ No newline at end of file diff --git a/group15/1507_977996067/src/task5/jvm/constant/ClassInfo.java b/group15/1507_977996067/src/task5/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..6f8e5229cc --- /dev/null +++ b/group15/1507_977996067/src/task5/jvm/constant/ClassInfo.java @@ -0,0 +1,24 @@ +package task5.jvm.constant; + +public class ClassInfo extends ConstantInfo { + private int type = ConstantInfo.CLASS_INFO; + private int utf8Index ; + public ClassInfo(ConstantPool pool) { + super(pool); + } + public int getUtf8Index() { + return utf8Index; + } + public void setUtf8Index(int utf8Index) { + this.utf8Index = utf8Index; + } + public int getType() { + return type; + } + + public String getClassName() { + int index = getUtf8Index(); + UTF8Info utf8Info = (UTF8Info)constantPool.getConstantInfo(index); + return utf8Info.getValue(); + } +} diff --git a/group15/1507_977996067/src/task5/jvm/constant/ConstantInfo.java b/group15/1507_977996067/src/task5/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..3e00cd378c --- /dev/null +++ b/group15/1507_977996067/src/task5/jvm/constant/ConstantInfo.java @@ -0,0 +1,29 @@ +package task5.jvm.constant; + +public abstract class ConstantInfo { + public static final int UTF8_INFO = 1; + public static final int FLOAT_INFO = 4; + public static final int CLASS_INFO = 7; + public static final int STRING_INFO = 8; + public static final int FIELD_INFO = 9; + public static final int METHOD_INFO = 10; + public static final int NAME_AND_TYPE_INFO = 12; + protected ConstantPool constantPool; + + public ConstantInfo(){ + + } + + public ConstantInfo(ConstantPool pool) { + this.constantPool = pool; + } + public abstract int getType(); + + public ConstantPool getConstantPool() { + return constantPool; + } + public ConstantInfo getConstantInfo(int index){ + return this.constantPool.getConstantInfo(index); + } + +} diff --git a/group15/1507_977996067/src/task5/jvm/constant/ConstantPool.java b/group15/1507_977996067/src/task5/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..6b0762c481 --- /dev/null +++ b/group15/1507_977996067/src/task5/jvm/constant/ConstantPool.java @@ -0,0 +1,37 @@ +package task5.jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List constantInfos; + + public ConstantPool() { + this.constantInfos = new ArrayList<>(); + } + + public ConstantPool(int size) { + this.constantInfos = new ArrayList<>(size); + + addConstantInfo(new NullConstantInfo()); + } + + public void addConstantInfo(ConstantInfo info) { + + this.constantInfos.add(info); + + } + + public ConstantInfo getConstantInfo(int index) { + return this.constantInfos.get(index); + } + + public String getUTF8String(int index) { + return ((UTF8Info) this.constantInfos.get(index)).getValue(); + } + + public Object getSize() { + return this.constantInfos.size() - 1; + } +} diff --git a/group15/1507_977996067/src/task5/jvm/constant/FieldRefInfo.java b/group15/1507_977996067/src/task5/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..957d882b7a --- /dev/null +++ b/group15/1507_977996067/src/task5/jvm/constant/FieldRefInfo.java @@ -0,0 +1,54 @@ +package task5.jvm.constant; + +public class FieldRefInfo extends ConstantInfo{ + private int type = ConstantInfo.FIELD_INFO; + private int classInfoIndex; + private int nameAndTypeIndex; + + public FieldRefInfo(ConstantPool pool) { + super(pool); + } + public int getType() { + return type; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String toString(){ + + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + + return getClassName() +" : "+ typeInfo.getName() + ":" + typeInfo.getTypeInfo() +"]"; + } + + public String getClassName(){ + + ClassInfo classInfo = (ClassInfo) this.getConstantInfo(this.getClassInfoIndex()); + + UTF8Info utf8Info = (UTF8Info)this.getConstantInfo(classInfo.getUtf8Index()); + + return utf8Info.getValue(); + + } + + public String getFieldName(){ + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getFieldType(){ + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } +} diff --git a/group15/1507_977996067/src/task5/jvm/constant/MethodRefInfo.java b/group15/1507_977996067/src/task5/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..2a25d2cbee --- /dev/null +++ b/group15/1507_977996067/src/task5/jvm/constant/MethodRefInfo.java @@ -0,0 +1,55 @@ +package task5.jvm.constant; + +public class MethodRefInfo extends ConstantInfo { + + private int type = ConstantInfo.METHOD_INFO; + + private int classInfoIndex; + private int nameAndTypeIndex; + + public MethodRefInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String toString(){ + + return getClassName() +" : "+ this.getMethodName() + " : " + this.getParamAndReturnType() ; + } + public String getClassName(){ + ConstantPool pool = this.getConstantPool(); + ClassInfo clzInfo = (ClassInfo)pool.getConstantInfo(this.getClassInfoIndex()); + return clzInfo.getClassName(); + } + + public String getMethodName(){ + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo)pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getParamAndReturnType(){ + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo)pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } + + + +} diff --git a/group15/1507_977996067/src/task5/jvm/constant/NameAndTypeInfo.java b/group15/1507_977996067/src/task5/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..e3a65591f1 --- /dev/null +++ b/group15/1507_977996067/src/task5/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,45 @@ +package task5.jvm.constant; + +public class NameAndTypeInfo extends ConstantInfo{ + public int type = ConstantInfo.NAME_AND_TYPE_INFO; + + private int index1; + private int index2; + + public NameAndTypeInfo(ConstantPool pool) { + super(pool); + } + + public int getIndex1() { + return index1; + } + public void setIndex1(int index1) { + this.index1 = index1; + } + public int getIndex2() { + return index2; + } + public void setIndex2(int index2) { + this.index2 = index2; + } + public int getType() { + return type; + } + + + public String getName(){ + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info1 = (UTF8Info)pool.getConstantInfo(index1); + return utf8Info1.getValue(); + } + + public String getTypeInfo(){ + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info2 = (UTF8Info)pool.getConstantInfo(index2); + return utf8Info2.getValue(); + } + + public String toString(){ + return "(" + getName() + "," + getTypeInfo()+")"; + } +} diff --git a/group15/1507_977996067/src/task5/jvm/constant/NullConstantInfo.java b/group15/1507_977996067/src/task5/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..a8895facd3 --- /dev/null +++ b/group15/1507_977996067/src/task5/jvm/constant/NullConstantInfo.java @@ -0,0 +1,13 @@ +package task5.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo(){ + + } + @Override + public int getType() { + return -1; + } + +} diff --git a/group15/1507_977996067/src/task5/jvm/constant/StringInfo.java b/group15/1507_977996067/src/task5/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..509a008b1d --- /dev/null +++ b/group15/1507_977996067/src/task5/jvm/constant/StringInfo.java @@ -0,0 +1,26 @@ +package task5.jvm.constant; + +public class StringInfo extends ConstantInfo{ + private int type = ConstantInfo.STRING_INFO; + private int index; + public StringInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } + + + public String toString(){ + return this.getConstantPool().getUTF8String(index); + } + +} diff --git a/group15/1507_977996067/src/task5/jvm/constant/UTF8Info.java b/group15/1507_977996067/src/task5/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..05aec836eb --- /dev/null +++ b/group15/1507_977996067/src/task5/jvm/constant/UTF8Info.java @@ -0,0 +1,32 @@ +package task5.jvm.constant; + +public class UTF8Info extends ConstantInfo{ + private int type = ConstantInfo.UTF8_INFO; + private int length ; + private String value; + public UTF8Info(ConstantPool pool) { + super(pool); + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getType() { + return type; + } + @Override + public String toString() { + return "UTF8Info [type=" + type + ", length=" + length + ", value=" + value +")]"; + } + public String getValue() { + return value; + } + public void setValue(String value) { + this.value = value; + } + + + +} diff --git a/group15/1507_977996067/src/task5/jvm/loader/ByteCodeIterator.java b/group15/1507_977996067/src/task5/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..d97ceb2d1b --- /dev/null +++ b/group15/1507_977996067/src/task5/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,43 @@ +package task5.jvm.loader; + +import task5.jvm.util.Util; + +import java.util.Arrays; + +public class ByteCodeIterator { + + private int position; + + private byte[] bytes; + + public ByteCodeIterator(byte[] bytes) { + this.bytes = bytes; + } + + public String getMagicNumber() { + position = 0; + byte[] bytes = Arrays.copyOf(this.bytes, 4); + position += 4; + return Util.byteToHexString(bytes); + } + + public int next2Bytes() { + return nextBytes(2); + } + + public int nextFlag() { + return nextBytes(1); + } + + public byte[] getBytes(int length) { + byte[] bytes = Arrays.copyOfRange(this.bytes, position, position + length); + position += length; + return bytes; + } + + private int nextBytes(int size) { + byte[] bytes = Arrays.copyOfRange(this.bytes, position, position + size); + position += size; + return Util.byteToInt(bytes); + } +} diff --git a/group15/1507_977996067/src/task5/jvm/loader/ClassFileLoader.java b/group15/1507_977996067/src/task5/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..4e0224e961 --- /dev/null +++ b/group15/1507_977996067/src/task5/jvm/loader/ClassFileLoader.java @@ -0,0 +1,126 @@ +package task5.jvm.loader; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import task5.jvm.clz.ClassFile; + +public class ClassFileLoader { + + private List clzPaths = new ArrayList(); + + public byte[] readBinaryCode(String className) { + + className = className.replace('.', File.separatorChar) + ".class"; + + for (String path : this.clzPaths) { + + String clzFileName = path + File.separatorChar + className; + byte[] codes = loadClassFile(clzFileName); + if (codes != null) { + return codes; + } + } + return null; + } + + private byte[] loadClassFile(String clzFileName) { + + File f = new File(clzFileName); + + try { + + return IOUtils.toByteArray(new FileInputStream(f)); + + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + + public void addClassPath(String path) { + if (this.clzPaths.contains(path)) { + return; + } + + this.clzPaths.add(path); + + } + + + public String getClassPath() { + return StringUtils.join(this.clzPaths, ";"); + } + + public ClassFile loadClass(String className) { + byte[] codes = this.readBinaryCode(className); + ClassFileParser parser = new ClassFileParser(); + return parser.parse(codes); + + } + + + // ------------------------------backup------------------------ + public String getClassPath_V1() { + + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < this.clzPaths.size(); i++) { + buffer.append(this.clzPaths.get(i)); + if (i < this.clzPaths.size() - 1) { + buffer.append(";"); + } + } + return buffer.toString(); + } + + private byte[] loadClassFile_V1(String clzFileName) { + + BufferedInputStream bis = null; + + try { + + File f = new File(clzFileName); + + + bis = new BufferedInputStream(new FileInputStream(f)); + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + + byte[] buffer = new byte[1024]; + int length = -1; + + while ((length = bis.read(buffer)) != -1) { + bos.write(buffer, 0, length); + } + + byte[] codes = bos.toByteArray(); + + return codes; + + } catch (IOException e) { + e.printStackTrace(); + + } finally { + if (bis != null) { + try { + bis.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return null; + + } + + +} \ No newline at end of file diff --git a/group15/1507_977996067/src/task5/jvm/loader/ClassFileParser.java b/group15/1507_977996067/src/task5/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..573d76ceff --- /dev/null +++ b/group15/1507_977996067/src/task5/jvm/loader/ClassFileParser.java @@ -0,0 +1,77 @@ +package task5.jvm.loader; + +import task5.jvm.clz.AccessFlag; +import task5.jvm.clz.ClassFile; +import task5.jvm.clz.ClassIndex; +import task5.jvm.constant.*; + +public class ClassFileParser { + + public ClassFile parse(byte[] codes) { + ClassFile classFile = new ClassFile(); + ByteCodeIterator iterator = new ByteCodeIterator(codes); + System.out.println(iterator.getMagicNumber()); + + classFile.setMinorVersion(iterator.next2Bytes()); + classFile.setMajorVersion(iterator.next2Bytes()); + + classFile.setConstPool(parseConstantPool(iterator)); + classFile.setAccessFlag(parseAccessFlag(iterator)); + classFile.setClassIndex(parseClassIndex(iterator)); + + return classFile; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + return new AccessFlag(iter.next2Bytes()); + } + + private ClassIndex parseClassIndex(ByteCodeIterator iter) { + ClassIndex clazIndex = new ClassIndex(); + clazIndex.setThisClassIndex(iter.next2Bytes()); + clazIndex.setSuperClassIndex(iter.next2Bytes()); + return clazIndex; + } + + private ConstantPool parseConstantPool(ByteCodeIterator iter) { + int poolCount = iter.next2Bytes(); + ConstantPool pool = new ConstantPool(poolCount); + for (int i = 0; i < poolCount; i++) { + int tag = iter.nextFlag(); + if (tag == ConstantInfo.UTF8_INFO) { //utf-8 + int length = iter.next2Bytes(); + byte[] bytes = iter.getBytes(length); + UTF8Info utf8Info = new UTF8Info(pool); + utf8Info.setValue(new String(bytes)); + utf8Info.setLength(length); + pool.addConstantInfo(utf8Info); + } else if (tag == ConstantInfo.STRING_INFO) { + StringInfo stringInfo = new StringInfo(pool); + stringInfo.setIndex(iter.next2Bytes()); + pool.addConstantInfo(stringInfo); + } else if (tag == ConstantInfo.CLASS_INFO) { + ClassInfo classInfo = new ClassInfo(pool); + classInfo.setUtf8Index(iter.next2Bytes()); + pool.addConstantInfo(classInfo); + } else if (tag == ConstantInfo.FIELD_INFO) { + FieldRefInfo fieldRefInfo = new FieldRefInfo(pool); + fieldRefInfo.setClassInfoIndex(iter.next2Bytes()); + fieldRefInfo.setNameAndTypeIndex(iter.next2Bytes()); + pool.addConstantInfo(fieldRefInfo); + } else if (tag == ConstantInfo.METHOD_INFO) { + MethodRefInfo methodRefInfo = new MethodRefInfo(pool); + methodRefInfo.setClassInfoIndex(iter.next2Bytes()); + methodRefInfo.setNameAndTypeIndex(iter.next2Bytes()); + pool.addConstantInfo(methodRefInfo); + } else if (tag == ConstantInfo.NAME_AND_TYPE_INFO) { + NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(pool); + nameAndTypeInfo.setIndex1(iter.next2Bytes()); + nameAndTypeInfo.setIndex2(iter.next2Bytes()); + pool.addConstantInfo(nameAndTypeInfo); + } + } + return pool; + } + + +} diff --git a/group15/1507_977996067/src/task5/jvm/test/ClassFileloaderTest.java b/group15/1507_977996067/src/task5/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..610af464ef --- /dev/null +++ b/group15/1507_977996067/src/task5/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,191 @@ +package task5.jvm.test; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import task5.jvm.clz.ClassFile; +import task5.jvm.clz.ClassIndex; +import task5.jvm.constant.*; +import task5.jvm.loader.ClassFileLoader; + +public class ClassFileloaderTest { + + + private static final String FULL_QUALIFIED_CLASS_NAME = "EmployeeV1"; + + static String path1 = "E:\\Idea\\coding2017\\group15\\1507_977996067\\out\\task5\\jvm\\test"; + static String path2 = "C:\temp"; + + static ClassFile clzFile = null; + static { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "EmployeeV1"; + + clzFile = loader.loadClass(className); +// clzFile.print(); + } + + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testClassPath() { + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + loader.addClassPath(path2); + + String clzPath = loader.getClassPath(); + + Assert.assertEquals(path1 + ";" + path2, clzPath); + + } + + @Test + public void testClassFileLength() { + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + + String className = "EmployeeV1"; + + byte[] byteCodes = loader.readBinaryCode(className); + + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + Assert.assertEquals(1038, byteCodes.length); + + } + + + @Test + public void testMagicNumber() { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "EmployeeV1"; + byte[] byteCodes = loader.readBinaryCode(className); + byte[] codes = new byte[]{byteCodes[0], byteCodes[1], byteCodes[2], byteCodes[3]}; + + String actualValue = this.byteToHexString(codes); + + Assert.assertEquals("cafebabe", actualValue); + } + + + private String byteToHexString(byte[] codes) { + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < codes.length; i++) { + byte b = codes[i]; + int value = b & 0xFF; + String strHex = Integer.toHexString(value); + if (strHex.length() < 2) { + strHex = "0" + strHex; + } + buffer.append(strHex); + } + return buffer.toString(); + } + + /** + * ---------------------------------------------------------------------- + */ + + + @Test + public void testVersion() { + + Assert.assertEquals(0, clzFile.getMinorVersion()); + Assert.assertEquals(52, clzFile.getMajorVersion()); + + } + + @Test + public void testConstantPool() { + + + ConstantPool pool = clzFile.getConstantPool(); + + Assert.assertEquals(53, pool.getSize()); + + { + ClassInfo clzInfo = (ClassInfo) pool.getConstantInfo(1); + Assert.assertEquals(2, clzInfo.getUtf8Index()); + + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(2); + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, utf8Info.getValue()); + } + { + ClassInfo clzInfo = (ClassInfo) pool.getConstantInfo(3); + Assert.assertEquals(4, clzInfo.getUtf8Index()); + + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(4); + Assert.assertEquals("java/lang/Object", utf8Info.getValue()); + } + { + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(5); + Assert.assertEquals("name", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(6); + Assert.assertEquals("Ljava/lang/String;", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(7); + Assert.assertEquals("age", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(8); + Assert.assertEquals("I", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(9); + Assert.assertEquals("", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(10); + Assert.assertEquals("(Ljava/lang/String;I)V", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(11); + Assert.assertEquals("Code", utf8Info.getValue()); + } + + { + MethodRefInfo methodRef = (MethodRefInfo) pool.getConstantInfo(12); + Assert.assertEquals(3, methodRef.getClassInfoIndex()); + Assert.assertEquals(13, methodRef.getNameAndTypeIndex()); + } + + { + NameAndTypeInfo nameAndType = (NameAndTypeInfo) pool.getConstantInfo(13); + Assert.assertEquals(9, nameAndType.getIndex1()); + Assert.assertEquals(14, nameAndType.getIndex2()); + } + //抽查几个吧 + { + MethodRefInfo methodRef = (MethodRefInfo) pool.getConstantInfo(45); + Assert.assertEquals(1, methodRef.getClassInfoIndex()); + Assert.assertEquals(46, methodRef.getNameAndTypeIndex()); + } + + { + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(53); + Assert.assertEquals("EmployeeV1.java", utf8Info.getValue()); + } + } + + @Test + public void testClassIndex() { + + ClassIndex clzIndex = clzFile.getClzIndex(); + ClassInfo thisClassInfo = (ClassInfo) clzFile.getConstantPool().getConstantInfo(clzIndex.getThisClassIndex()); + ClassInfo superClassInfo = (ClassInfo) clzFile.getConstantPool().getConstantInfo(clzIndex.getSuperClassIndex()); + + + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); + Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); + } + + +} diff --git a/group15/1507_977996067/src/task5/jvm/test/EmployeeV1.java b/group15/1507_977996067/src/task5/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..34ca61b3a8 --- /dev/null +++ b/group15/1507_977996067/src/task5/jvm/test/EmployeeV1.java @@ -0,0 +1,29 @@ +package task5.jvm.test; + +public class EmployeeV1 { + private String name; + private int age; + + public EmployeeV1(String name, int age) { + this.name = name; + this.age = age; + } + + public void setName(String name) { + this.name = name; + } + + public void setAge(int age) { + this.age = age; + } + + public void sayHello() { + System.out.println("Hello , this is class Employee "); + } + + public static void main(String[] args) { + EmployeeV1 p = new EmployeeV1("Andy", 29); + p.sayHello(); + + } +} \ No newline at end of file diff --git a/group15/1507_977996067/src/task5/jvm/util/Util.java b/group15/1507_977996067/src/task5/jvm/util/Util.java new file mode 100644 index 0000000000..0a37ea65ec --- /dev/null +++ b/group15/1507_977996067/src/task5/jvm/util/Util.java @@ -0,0 +1,23 @@ +package task5.jvm.util; + +public class Util { + public static int byteToInt(byte[] codes){ + String s1 = byteToHexString(codes); + return Integer.valueOf(s1, 16); + } + + + public static String byteToHexString(byte[] codes ){ + StringBuffer buffer = new StringBuffer(); + for(int i=0;i { + private MyLinkedList elementData = new MyLinkedList(); + + public void push(T o) { + elementData.addFirst(o); + } + + public T pop() { + return elementData.removeFirst(); + } + + public T peek() { + return elementData.get(0); + } + + public boolean isEmpty() { + return elementData.size() == 0; + } + + public int size() { + return elementData.size(); + } + +} diff --git a/group15/1507_977996067/src/task5/stack/StackUtil.java b/group15/1507_977996067/src/task5/stack/StackUtil.java new file mode 100644 index 0000000000..301399c4d5 --- /dev/null +++ b/group15/1507_977996067/src/task5/stack/StackUtil.java @@ -0,0 +1,87 @@ +package task5.stack; + +@SuppressWarnings("unchecked") +public class StackUtil { + + + /** + * 假设栈中的元素是Integer, 从栈顶到栈底是 : 5,4,3,2,1 调用该方法后, 元素次序变为: 1,2,3,4,5 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + */ + public static void reverse(Stack s) { + Stack temp1 = new Stack(); + Stack temp2 = new Stack(); + int size = s.size(); + while (size > 0) { + temp1.push(s.pop()); + size--; + } + while (size > 0) { + temp2.push(temp1.pop()); + size--; + } + while (size > 0) { + s.push(temp2.pop()); + size--; + } + } + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + */ + public static void remove(Stack s, Object o) { + Stack temp = new Stack(); + while (!s.isEmpty()) { + Object val = s.pop(); + if (val != o) + temp.push(val); + else break; + } + while (!temp.isEmpty()) { + s.push(temp.pop()); + } + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + */ + public static Object[] getTop(Stack s, int len) { + if (len > 0 && len <= s.size()) { + Object[] result = new Object[len]; + while (len > 0) { + result[len--] = s.pop(); + } + return result; + } + return null; + } + + /** + * 字符串s 可能包含这些字符: ( ) [ ] { }, a,b,c... x,yz + * 使用堆栈检查字符串s中的括号是不是成对出现的。 + * 例如s = "([e{d}f])" , 则该字符串中的括号是成对出现, 该方法返回true + * 如果 s = "([b{x]y})", 则该字符串中的括号不是成对出现的, 该方法返回false; + */ + public static boolean isValidPairs(String s) { + int length = s.length(); + int size = length / 2; + Stack temp1 = new Stack(); + Stack temp2 = new Stack(); + int position = 0; + while (position <= size) { + temp1.push(s.charAt(position)); + temp2.push(s.charAt(length - position)); + } + + int tempPosition = 0; + while (tempPosition <= size) { + if (temp1.pop() != temp2.pop()) { + return false; + } + } + return true; + } + + +} \ No newline at end of file From 173d8dd439210e3465f04f0a4e0a6455f0803f4c Mon Sep 17 00:00:00 2001 From: "songbao.yang" Date: Sun, 9 Apr 2017 16:51:10 +0800 Subject: [PATCH 090/203] =?UTF-8?q?=E9=87=8D=E6=96=B0=E6=95=B4=E7=90=86?= =?UTF-8?q?=E6=96=87=E4=BB=B6=20=E6=8F=90=E4=BA=A4miniJvm=20task1=20classl?= =?UTF-8?q?oader+LRU?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group05/578505552/578505552.iml | 16 - group05/578505552/pom.xml | 1 - .../java/com/coding/basic/LinkedList.java | 156 ------ .../src/main/java/com/coding/basic/List.java | 14 - .../com/coderising/array/ArrayUtil.java | 505 +++++++++--------- .../coderising/download/DownloadThread.java | 6 +- .../coderising/download/FileDownloader.java | 10 +- .../coderising/download/api/Connection.java | 2 +- .../download/api/ConnectionException.java | 2 +- .../download/api/ConnectionManager.java | 2 +- .../download/api/DownloadListener.java | 2 +- .../download/impl/ConnectionImpl.java | 4 +- .../download/impl/ConnectionManagerImpl.java | 8 +- .../com/coderising/litestruts/Action.java | 76 +-- .../coderising/litestruts/Configuration.java | 2 +- .../coderising/litestruts/LoginAction.java | 76 +-- .../coderising/litestruts/ReflectUtils.java | 2 +- .../com/coderising/litestruts/Struts.java | 262 ++++----- .../com/coderising/litestruts/View.java | 46 +- .../com/coding/basic/ArrayList.java | 206 +++---- .../com/coding/basic/BinaryTreeNode.java | 2 +- .../com/coding/basic/Iterator.java | 22 +- .../com/coding/basic/LinkedList.java | 390 ++++++++++++++ .../dataStruct/com/coding/basic/List.java | 14 + .../com/coding/basic/Queue.java | 180 +++---- .../com/coding/basic/Stack.java | 2 +- .../coding/basic/linklist/LRUPageFrame.java | 105 ++++ .../jvm/loader/ClassFileLoader.java | 68 +++ .../com/coderising/jvm/loader/EmployeeV1.java | 31 ++ .../578505552/src/main/resources/struts.xml | 2 +- .../com/coderising/array/ArrayUtilTest.java | 409 +++++++------- .../download/DownloadThreadTest.java | 11 +- .../download/FileDownloaderTest.java | 9 +- .../download/impl/ConnectionImplTest.java | 8 +- .../com/coderising/litestruts/StrutsTest.java | 80 +-- .../com/coding/basic/BinaryTreeNodeTest.java | 72 ++- .../com/coding/basic/ListTest.java | 198 +++---- .../com/coding/basic/QueueTest.java | 148 ++--- .../com/coding/basic/StackTest.java | 128 ++--- .../basic/linklist/LRUPageFrameTest.java | 31 ++ .../jvm/loader/ClassFileloaderTest.java | 70 +++ 41 files changed, 1957 insertions(+), 1421 deletions(-) delete mode 100644 group05/578505552/578505552.iml delete mode 100644 group05/578505552/src/main/java/com/coding/basic/LinkedList.java delete mode 100644 group05/578505552/src/main/java/com/coding/basic/List.java rename group05/578505552/src/main/java/{ => dataStruct}/com/coderising/array/ArrayUtil.java (92%) rename group05/578505552/src/main/java/{ => dataStruct}/com/coderising/download/DownloadThread.java (88%) rename group05/578505552/src/main/java/{ => dataStruct}/com/coderising/download/FileDownloader.java (82%) rename group05/578505552/src/main/java/{ => dataStruct}/com/coderising/download/api/Connection.java (90%) rename group05/578505552/src/main/java/{ => dataStruct}/com/coderising/download/api/ConnectionException.java (88%) rename group05/578505552/src/main/java/{ => dataStruct}/com/coderising/download/api/ConnectionManager.java (79%) rename group05/578505552/src/main/java/{ => dataStruct}/com/coderising/download/api/DownloadListener.java (59%) rename group05/578505552/src/main/java/{ => dataStruct}/com/coderising/download/impl/ConnectionImpl.java (89%) rename group05/578505552/src/main/java/{ => dataStruct}/com/coderising/download/impl/ConnectionManagerImpl.java (69%) rename group05/578505552/src/main/java/{ => dataStruct}/com/coderising/litestruts/Action.java (89%) rename group05/578505552/src/main/java/{ => dataStruct}/com/coderising/litestruts/Configuration.java (63%) rename group05/578505552/src/main/java/{ => dataStruct}/com/coderising/litestruts/LoginAction.java (92%) rename group05/578505552/src/main/java/{ => dataStruct}/com/coderising/litestruts/ReflectUtils.java (81%) rename group05/578505552/src/main/java/{ => dataStruct}/com/coderising/litestruts/Struts.java (96%) rename group05/578505552/src/main/java/{ => dataStruct}/com/coderising/litestruts/View.java (85%) rename group05/578505552/src/main/java/{ => dataStruct}/com/coding/basic/ArrayList.java (84%) rename group05/578505552/src/main/java/{ => dataStruct}/com/coding/basic/BinaryTreeNode.java (97%) rename group05/578505552/src/main/java/{ => dataStruct}/com/coding/basic/Iterator.java (78%) create mode 100644 group05/578505552/src/main/java/dataStruct/com/coding/basic/LinkedList.java create mode 100644 group05/578505552/src/main/java/dataStruct/com/coding/basic/List.java rename group05/578505552/src/main/java/{ => dataStruct}/com/coding/basic/Queue.java (95%) rename group05/578505552/src/main/java/{ => dataStruct}/com/coding/basic/Stack.java (97%) create mode 100644 group05/578505552/src/main/java/dataStruct/com/coding/basic/linklist/LRUPageFrame.java create mode 100644 group05/578505552/src/main/java/miniJvm/com/coderising/jvm/loader/ClassFileLoader.java create mode 100644 group05/578505552/src/main/java/miniJvm/com/coderising/jvm/loader/EmployeeV1.java rename group05/578505552/src/test/java/{ => dataStruct}/com/coderising/array/ArrayUtilTest.java (96%) rename group05/578505552/src/test/java/{ => dataStruct}/com/coderising/download/DownloadThreadTest.java (80%) rename group05/578505552/src/{main/java => test/java/dataStruct}/com/coderising/download/FileDownloaderTest.java (81%) rename group05/578505552/src/test/java/{ => dataStruct}/com/coderising/download/impl/ConnectionImplTest.java (85%) rename group05/578505552/src/test/java/{ => dataStruct}/com/coderising/litestruts/StrutsTest.java (93%) rename group05/578505552/src/test/java/{ => dataStruct}/com/coding/basic/BinaryTreeNodeTest.java (86%) rename group05/578505552/src/test/java/{ => dataStruct}/com/coding/basic/ListTest.java (94%) rename group05/578505552/src/test/java/{ => dataStruct}/com/coding/basic/QueueTest.java (75%) rename group05/578505552/src/test/java/{ => dataStruct}/com/coding/basic/StackTest.java (83%) create mode 100644 group05/578505552/src/test/java/dataStruct/com/coding/basic/linklist/LRUPageFrameTest.java create mode 100644 group05/578505552/src/test/java/miniJvm/com/coderising/jvm/loader/ClassFileloaderTest.java diff --git a/group05/578505552/578505552.iml b/group05/578505552/578505552.iml deleted file mode 100644 index 95e7551d7a..0000000000 --- a/group05/578505552/578505552.iml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/group05/578505552/pom.xml b/group05/578505552/pom.xml index 62eed92daf..ea3686ca26 100644 --- a/group05/578505552/pom.xml +++ b/group05/578505552/pom.xml @@ -7,7 +7,6 @@ 1.0-SNAPSHOT jar - basic http://maven.apache.org diff --git a/group05/578505552/src/main/java/com/coding/basic/LinkedList.java b/group05/578505552/src/main/java/com/coding/basic/LinkedList.java deleted file mode 100644 index d1fa42bf4c..0000000000 --- a/group05/578505552/src/main/java/com/coding/basic/LinkedList.java +++ /dev/null @@ -1,156 +0,0 @@ -package com.coding.basic; - -import java.util.NoSuchElementException; - -/** - * Created by songbao.yang on 2017/2/21. - * - */ -public class LinkedList implements List { - - private Node head; - private int elementCount; - - //head作为一个节点,其next的值指向List中真正的第一个节点 - public LinkedList() { - head = new Node(); - head.next = null; - head.data = null; - elementCount = 0; - } - - public void add(Object o){ - Node newNode = new Node(); - newNode.data = o; - newNode.next = null; - - Node cursor = head; - while (cursor.next != null){ - cursor = cursor.next; - } - cursor.next = newNode; - elementCount++; - } - - - public void add(int index , Object o){ - indexRangeCheck(index); - Node newNode = new Node(); - newNode.data = o; - - Node cursor = head; - for (int i = 0; i < index; i++) { - cursor = cursor.next; //将cursor移动到index-1节点处; - } - - newNode.next = cursor.next; //将新节点指向原index处的节点 - cursor.next = newNode;//将原index-1处的节点指向新节点 - elementCount++; - } - - private void indexRangeCheck(int index){ - if (index < 0 || index >= size()){ - throw new IndexOutOfBoundsException(); - } - } - - public Object get(int index){ - indexRangeCheck(index); - Node cursor = head; - for (int i = 0; i < index; i++) { - cursor = cursor.next; - } - return cursor.next.data; - } - - public Object remove(int index){ - indexRangeCheck(index); - Node cursor = head; - for (int i = 0; i < index; i++) { - cursor = cursor.next; - } - Node indexNode = cursor.next; - cursor.next = indexNode.next; - elementCount--; - return indexNode; - } - - public int size(){ - return elementCount; - } - - public void addFirst(Object o){ - Node node = new Node(); - node.data = o; - node.next = head.next; - head.next = node; - elementCount++; - } - - public void addLast(Object o){ - - Node cursor = head; - while (cursor.next != null){ - cursor = cursor.next; - } - Node newNode = new Node(); - newNode.data = o; - newNode.next = null; - cursor.next = newNode; - elementCount++; - } - - public Object removeFirst(){ - - if (size() == 0){ - throw new RuntimeException("no element in list"); - } - Node firstNode = head.next; - head.next = head.next.next; - elementCount--; - return firstNode; - } - - public Object removeLast(){ - if (size() == 0){ - throw new RuntimeException("no element in list"); - } - - Node cursor = head; - for (int i = 0; i < size() - 1; i++) { - cursor = cursor.next; - } - - Node lastNode = cursor.next; - cursor.next = null; - elementCount--; - - return lastNode; - } - - public Iterator iterator(){ - return new Itr(); - } - - private class Itr implements Iterator { - - private Node itrCursor = head; - - public boolean hasNext() { - - return itrCursor.next != null; - } - - public Object next() { - if (hasNext()){ - return itrCursor.next; - } - throw new NoSuchElementException(); - } - } - - private static class Node{ - Object data; - Node next; - } -} diff --git a/group05/578505552/src/main/java/com/coding/basic/List.java b/group05/578505552/src/main/java/com/coding/basic/List.java deleted file mode 100644 index e26fbe7c98..0000000000 --- a/group05/578505552/src/main/java/com/coding/basic/List.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.coding.basic; - -/** - * Created by songbao.yang on 2017/2/21. - * - */ -public interface List { - public void add(Object o); - public void add(int index, Object o); - public Object get(int index); - public Object remove(int index); - public int size(); - public Iterator iterator(); -} diff --git a/group05/578505552/src/main/java/com/coderising/array/ArrayUtil.java b/group05/578505552/src/main/java/dataStruct/com/coderising/array/ArrayUtil.java similarity index 92% rename from group05/578505552/src/main/java/com/coderising/array/ArrayUtil.java rename to group05/578505552/src/main/java/dataStruct/com/coderising/array/ArrayUtil.java index 2c248db331..4a034abf2c 100644 --- a/group05/578505552/src/main/java/com/coderising/array/ArrayUtil.java +++ b/group05/578505552/src/main/java/dataStruct/com/coderising/array/ArrayUtil.java @@ -1,242 +1,263 @@ -package com.coderising.array; - -public class ArrayUtil { - - /** - * 给定一个整形数组a , 对该数组的值进行置换 - 例如: a = [7, 9 , 30, 3] , 置换后为 [3, 30, 9,7] - 如果 a = [7, 9, 30, 3, 4] , 置换后为 [4,3, 30 , 9,7] - * @param origin - * @return - */ - public void reverseArray(int[] origin){ - int length = origin.length; - int i = 0; - int j = length - 1; - while (i < j){ - int tmp = origin[i]; - origin[i] = origin[j]; - origin[j] = tmp; - i++; - j--; - } - } - - /** - * 现在有如下的一个数组: int oldArr[]={1,3,4,5,0,0,6,6,0,5,4,7,6,7,0,5} - * 要求将以上数组中值为0的项去掉,将不为0的值存入一个新的数组,生成的新数组为: - * {1,3,4,5,6,6,5,4,7,6,7,5} - * @param oldArray - * @return - */ - - public int[] removeZero(int[] oldArray){ - int length = oldArray.length; - int[] newArray = new int[length]; - int j = 0; - for (int i = 0; i < length; i++) { - if (oldArray[i] != 0){ - newArray[j++] = oldArray[i]; - } - } - int[] res = new int[j]; - System.arraycopy(newArray, 0, res, 0, j); - return res; - } - - /** - * 给定两个已经排序好的整形数组, a1和a2 , 创建一个新的数组a3, 使得a3 包含a1和a2 的所有元素, 并且仍然是有序的 - * 例如 a1 = [3, 5, 7,8] a2 = [4, 5, 6,7] 则 a3 为[3,4,5,6,7,8] , 注意: 已经消除了重复 - * @param array1 - * @param array2 - * @return - */ - - public int[] merge(int[] array1, int[] array2){ - int length1 = array1.length; - int length2 = array2.length; - int i = 0; - int j = 0; - - int[] res = new int[length1 + length2]; - int k = 0; - while (i < length1 || j < length2){ - int next = Integer.MIN_VALUE; - if (i < length1 && j < length2){ - if (array1[i] == array2[j]){ - next = array1[i]; - i++; - j++; - } else if (array1[i] < array2[j]){ - next = array1[i++]; - } else { - next = array2[j++]; - } - } else if (i < length1){ - next = array1[i++]; - } else { - next = array2[j++]; - } - - if (k == 0){ - res[k++] = next; - } else if (next > res[k-1]){ - res[k++] = next; - } - } - - int[] merged = new int[k]; - System.arraycopy(res, 0, merged, 0, k); - return merged; - } - /** - * 把一个已经存满数据的数组 oldArray的容量进行扩展, 扩展后的新数据大小为oldArray.length + size - * 注意,老数组的元素在新数组中需要保持 - * 例如 oldArray = [2,3,6] , size = 3,则返回的新数组为 - * [2,3,6,0,0,0] - * @param oldArray - * @param size - * @return - */ - public int[] grow(int [] oldArray, int size){ - if (size < 0){ - throw new IllegalArgumentException("illegal size"); - } - int newLength = oldArray.length + size; - int[] newArray = new int[newLength]; - System.arraycopy(oldArray, 0, newArray, 0, oldArray.length); - return newArray; - } - - /** - * 斐波那契数列为:1,1,2,3,5,8,13,21...... ,给定一个最大值, 返回小于该值的数列 - * 例如, max = 15 , 则返回的数组应该为 [1,1,2,3,5,8,13] - * max = 1, 则返回空数组 [] - * @param max - * @return - */ - public int[] fibonacci(int max){ - - if (max <= 1){ - return new int[0]; - } - - int[] res = new int[max]; - int i = 1; - int j = 1; - int k = 0; - res[k++] = 1; - res[k++] = 1; - - int tmp = i + j; - while (tmp < max){ - res[k++] = tmp; - i = j; - j = tmp; - tmp = i + j; - } - - int[] result = new int[k]; - System.arraycopy(res, 0, result, 0, k); - return result; - } - - /** - * 返回小于给定最大值max的所有素数数组 - * 例如max = 23, 返回的数组为[2,3,5,7,11,13,17,19] - * @param max - * @return - */ - public int[] getPrimes(int max){ - if (max < 0){ - return new int[0]; - } - int[] res = new int[max]; - int k = 0; - for (int i = 2; i < max; i++) { - if (isPrime(i)){ - res[k++] = i; - } - } - int[] result = new int[k]; - System.arraycopy(res, 0, result, 0, k); - return result; - } - - private boolean isPrime(int num){ - - if (num < 1){ - return false; - } - for (int i = 2; i <= num / 2; i++) { - if (num % i == 0){ - return false; - } - - } - return true; - } - - /** - * 所谓“完数”, 是指这个数恰好等于它的因子之和,例如6=1+2+3 - * 给定一个最大值max, 返回一个数组, 数组中是小于max 的所有完数 - * @param max - * @return - */ - public int[] getPerfectNumbers(int max){ - - if (max < 0){ - return new int[0]; - } - int[] res = new int[max]; - int k = 0; - for (int i = 0; i < max; i++) { - if (isPerfectNumbers(i)){ - res[k++] = i; - } - } - int[] result = new int[k]; - System.arraycopy(res, 0, result, 0, k); - return result; - } - - private boolean isPerfectNumbers(int num){ - - return num == getFactorSum(num); - } - - private int getFactorSum(int num){ - if (num == 0 || num == 1){ - return -1; - } - int sum = 0; - for (int i = 1; i <= num / 2; i++) { - if (num % i == 0){ - sum += i; - } - } - return sum; - } - /** - * 用seperator 把数组 array给连接起来 - * 例如array= [3,8,9], seperator = "-" - * 则返回值为"3-8-9" - * @param array - * @param separator - * @return - */ - public String join(int[] array, String separator){ - - if (array.length <= 0){ - return ""; - } - - StringBuffer stringBuffer = new StringBuffer(); - for (int i = 0; i < array.length - 1; i++) { - stringBuffer.append(String.valueOf(array[i])).append(separator); - } - stringBuffer.append(String.valueOf(array[array.length-1])); - return stringBuffer.toString(); - } - -} +package dataStruct.com.coderising.array; + +public class ArrayUtil { + + /** + * 给定一个整形数组a , 对该数组的值进行置换 + 例如: a = [7, 9 , 30, 3] , 置换后为 [3, 30, 9,7] + 如果 a = [7, 9, 30, 3, 4] , 置换后为 [4,3, 30 , 9,7] + * @param origin + * @return + */ + public void reverseArray(int[] origin){ + + if(origin == null){ + return; + } + int length = origin.length; + int i = 0; + int j = length - 1; + while (i < j){ + int tmp = origin[i]; + origin[i] = origin[j]; + origin[j] = tmp; + i++; + j--; + } + } + + /** + * 现在有如下的一个数组: int oldArr[]={1,3,4,5,0,0,6,6,0,5,4,7,6,7,0,5} + * 要求将以上数组中值为0的项去掉,将不为0的值存入一个新的数组,生成的新数组为: + * {1,3,4,5,6,6,5,4,7,6,7,5} + * @param oldArray + * @return + */ + + public int[] removeZero(int[] oldArray){ + int length = oldArray.length; + int[] newArray = new int[length]; + int j = 0; + for (int i = 0; i < length; i++) { + if (oldArray[i] != 0){ + newArray[j++] = oldArray[i]; + } + } + int[] res = new int[j]; + System.arraycopy(newArray, 0, res, 0, j); + return res; + } + + /** + * 给定两个已经排序好的整形数组, a1和a2 , 创建一个新的数组a3, 使得a3 包含a1和a2 的所有元素, 并且仍然是有序的 + * 例如 a1 = [3, 5, 7,8] a2 = [4, 5, 6,7] 则 a3 为[3,4,5,6,7,8] , 注意: 已经消除了重复 + * @param array1 + * @param array2 + * @return + */ + + public int[] merge(int[] array1, int[] array2){ + + if(array1 == null && array2 == null){ + return new int[0]; + } + + if (array1 == null){ + return array2; + } + + if (array2 == null){ + return array1; + } + + int length1 = array1.length; + int length2 = array2.length; + int i = 0; + int j = 0; + + int[] res = new int[length1 + length2]; + int k = 0; + while (i < length1 || j < length2){ + int next = Integer.MIN_VALUE; + if (i < length1 && j < length2){ + if (array1[i] == array2[j]){ + next = array1[i]; + i++; + j++; + } else if (array1[i] < array2[j]){ + next = array1[i++]; + } else { + next = array2[j++]; + } + } else if (i < length1){ + next = array1[i++]; + } else { + next = array2[j++]; + } + + if (k == 0){ + res[k++] = next; + } else if (next > res[k-1]){ + res[k++] = next; + } + } + + int[] merged = new int[k]; + System.arraycopy(res, 0, merged, 0, k); + return merged; + } + /** + * 把一个已经存满数据的数组 oldArray的容量进行扩展, 扩展后的新数据大小为oldArray.length + size + * 注意,老数组的元素在新数组中需要保持 + * 例如 oldArray = [2,3,6] , size = 3,则返回的新数组为 + * [2,3,6,0,0,0] + * @param oldArray + * @param size + * @return + */ + public int[] grow(int [] oldArray, int size){ + if (size < 0){ + throw new IllegalArgumentException("illegal size"); + } + int newLength = oldArray.length + size; + int[] newArray = new int[newLength]; + System.arraycopy(oldArray, 0, newArray, 0, oldArray.length); + return newArray; + } + + /** + * 斐波那契数列为:1,1,2,3,5,8,13,21...... ,给定一个最大值, 返回小于该值的数列 + * 例如, max = 15 , 则返回的数组应该为 [1,1,2,3,5,8,13] + * max = 1, 则返回空数组 [] + * @param max + * @return + */ + public int[] fibonacci(int max){ + + if (max <= 1){ + return new int[0]; + } + + int[] res = new int[max]; + int i = 1; + int j = 1; + int k = 0; + res[k++] = 1; + res[k++] = 1; + + int tmp = i + j; + while (tmp < max){ + res[k++] = tmp; + i = j; + j = tmp; + tmp = i + j; + } + + int[] result = new int[k]; + System.arraycopy(res, 0, result, 0, k); + return result; + } + + /** + * 返回小于给定最大值max的所有素数数组 + * 例如max = 23, 返回的数组为[2,3,5,7,11,13,17,19] + * @param max + * @return + */ + public int[] getPrimes(int max){ + if (max < 3){ + return new int[0]; + } + int[] res = new int[max]; + int k = 0; + for (int i = 2; i < max; i++) { + if (isPrime(i)){ + res[k++] = i; + } + } + int[] result = new int[k]; + System.arraycopy(res, 0, result, 0, k); + return result; + } + + private boolean isPrime(int num){ + + if (num < 1){ + return false; + } + for (int i = 2; i <= num / 2; i++) { + if (num % i == 0){ + return false; + } + + } + return true; + } + + /** + * 所谓“完数”, 是指这个数恰好等于它的因子之和,例如6=1+2+3 + * 给定一个最大值max, 返回一个数组, 数组中是小于max 的所有完数 + * @param max + * @return + */ + public int[] getPerfectNumbers(int max){ + + if (max < 0){ + return new int[0]; + } + int[] res = new int[max]; + int k = 0; + for (int i = 0; i < max; i++) { + if (isPerfectNumbers(i)){ + res[k++] = i; + } + } + int[] result = new int[k]; + System.arraycopy(res, 0, result, 0, k); + return result; + } + + private boolean isPerfectNumbers(int num){ + + return num == getFactorSum(num); + } + + private int getFactorSum(int num){ + if (num == 0 || num == 1){ + return -1; + } + int sum = 0; + for (int i = 1; i <= num / 2; i++) { + if (num % i == 0){ + sum += i; + } + } + return sum; + } + /** + * 用seperator 把数组 array给连接起来 + * 例如array= [3,8,9], seperator = "-" + * 则返回值为"3-8-9" + * @param array + * @param separator + * @return + */ + public String join(int[] array, String separator){ + + if (array == null || array.length <= 0){ + return ""; + } + + StringBuffer stringBuffer = new StringBuffer(); + for (int i = 0; i < array.length - 1; i++) { + stringBuffer.append(String.valueOf(array[i])).append(separator); + } + stringBuffer.append(String.valueOf(array[array.length-1])); + return stringBuffer.toString(); + } + + public static void main(String[] args) { + ArrayUtil arrayUtil = new ArrayUtil(); + System.out.println("-------------------------"); + } +} diff --git a/group05/578505552/src/main/java/com/coderising/download/DownloadThread.java b/group05/578505552/src/main/java/dataStruct/com/coderising/download/DownloadThread.java similarity index 88% rename from group05/578505552/src/main/java/com/coderising/download/DownloadThread.java rename to group05/578505552/src/main/java/dataStruct/com/coderising/download/DownloadThread.java index feefc27cfc..c837e08f8b 100644 --- a/group05/578505552/src/main/java/com/coderising/download/DownloadThread.java +++ b/group05/578505552/src/main/java/dataStruct/com/coderising/download/DownloadThread.java @@ -1,7 +1,7 @@ -package com.coderising.download; +package dataStruct.com.coderising.download; -import com.coderising.download.api.Connection; -import com.coderising.download.api.DownloadListener; +import dataStruct.com.coderising.download.api.Connection; +import dataStruct.com.coderising.download.api.DownloadListener; import java.io.File; import java.io.IOException; diff --git a/group05/578505552/src/main/java/com/coderising/download/FileDownloader.java b/group05/578505552/src/main/java/dataStruct/com/coderising/download/FileDownloader.java similarity index 82% rename from group05/578505552/src/main/java/com/coderising/download/FileDownloader.java rename to group05/578505552/src/main/java/dataStruct/com/coderising/download/FileDownloader.java index d399381a7a..324ba4d29d 100644 --- a/group05/578505552/src/main/java/com/coderising/download/FileDownloader.java +++ b/group05/578505552/src/main/java/dataStruct/com/coderising/download/FileDownloader.java @@ -1,9 +1,9 @@ -package com.coderising.download; +package dataStruct.com.coderising.download; -import com.coderising.download.api.Connection; -import com.coderising.download.api.ConnectionException; -import com.coderising.download.api.ConnectionManager; -import com.coderising.download.api.DownloadListener; +import dataStruct.com.coderising.download.api.Connection; +import dataStruct.com.coderising.download.api.ConnectionException; +import dataStruct.com.coderising.download.api.ConnectionManager; +import dataStruct.com.coderising.download.api.DownloadListener; import java.io.File; diff --git a/group05/578505552/src/main/java/com/coderising/download/api/Connection.java b/group05/578505552/src/main/java/dataStruct/com/coderising/download/api/Connection.java similarity index 90% rename from group05/578505552/src/main/java/com/coderising/download/api/Connection.java rename to group05/578505552/src/main/java/dataStruct/com/coderising/download/api/Connection.java index 494c713b27..da33f7360c 100644 --- a/group05/578505552/src/main/java/com/coderising/download/api/Connection.java +++ b/group05/578505552/src/main/java/dataStruct/com/coderising/download/api/Connection.java @@ -1,4 +1,4 @@ -package com.coderising.download.api; +package dataStruct.com.coderising.download.api; import java.io.IOException; diff --git a/group05/578505552/src/main/java/com/coderising/download/api/ConnectionException.java b/group05/578505552/src/main/java/dataStruct/com/coderising/download/api/ConnectionException.java similarity index 88% rename from group05/578505552/src/main/java/com/coderising/download/api/ConnectionException.java rename to group05/578505552/src/main/java/dataStruct/com/coderising/download/api/ConnectionException.java index 5954d22409..2efc59eec6 100644 --- a/group05/578505552/src/main/java/com/coderising/download/api/ConnectionException.java +++ b/group05/578505552/src/main/java/dataStruct/com/coderising/download/api/ConnectionException.java @@ -1,4 +1,4 @@ -package com.coderising.download.api; +package dataStruct.com.coderising.download.api; public class ConnectionException extends Exception { diff --git a/group05/578505552/src/main/java/com/coderising/download/api/ConnectionManager.java b/group05/578505552/src/main/java/dataStruct/com/coderising/download/api/ConnectionManager.java similarity index 79% rename from group05/578505552/src/main/java/com/coderising/download/api/ConnectionManager.java rename to group05/578505552/src/main/java/dataStruct/com/coderising/download/api/ConnectionManager.java index ce045393b1..2ac9aa5ac9 100644 --- a/group05/578505552/src/main/java/com/coderising/download/api/ConnectionManager.java +++ b/group05/578505552/src/main/java/dataStruct/com/coderising/download/api/ConnectionManager.java @@ -1,4 +1,4 @@ -package com.coderising.download.api; +package dataStruct.com.coderising.download.api; public interface ConnectionManager { /** diff --git a/group05/578505552/src/main/java/com/coderising/download/api/DownloadListener.java b/group05/578505552/src/main/java/dataStruct/com/coderising/download/api/DownloadListener.java similarity index 59% rename from group05/578505552/src/main/java/com/coderising/download/api/DownloadListener.java rename to group05/578505552/src/main/java/dataStruct/com/coderising/download/api/DownloadListener.java index bf9807b307..8daca6846c 100644 --- a/group05/578505552/src/main/java/com/coderising/download/api/DownloadListener.java +++ b/group05/578505552/src/main/java/dataStruct/com/coderising/download/api/DownloadListener.java @@ -1,4 +1,4 @@ -package com.coderising.download.api; +package dataStruct.com.coderising.download.api; public interface DownloadListener { public void notifyFinished(); diff --git a/group05/578505552/src/main/java/com/coderising/download/impl/ConnectionImpl.java b/group05/578505552/src/main/java/dataStruct/com/coderising/download/impl/ConnectionImpl.java similarity index 89% rename from group05/578505552/src/main/java/com/coderising/download/impl/ConnectionImpl.java rename to group05/578505552/src/main/java/dataStruct/com/coderising/download/impl/ConnectionImpl.java index 0561318d7a..c9b1c7c103 100644 --- a/group05/578505552/src/main/java/com/coderising/download/impl/ConnectionImpl.java +++ b/group05/578505552/src/main/java/dataStruct/com/coderising/download/impl/ConnectionImpl.java @@ -1,6 +1,6 @@ -package com.coderising.download.impl; +package dataStruct.com.coderising.download.impl; -import com.coderising.download.api.Connection; +import dataStruct.com.coderising.download.api.Connection; import java.io.IOException; import java.io.InputStream; diff --git a/group05/578505552/src/main/java/com/coderising/download/impl/ConnectionManagerImpl.java b/group05/578505552/src/main/java/dataStruct/com/coderising/download/impl/ConnectionManagerImpl.java similarity index 69% rename from group05/578505552/src/main/java/com/coderising/download/impl/ConnectionManagerImpl.java rename to group05/578505552/src/main/java/dataStruct/com/coderising/download/impl/ConnectionManagerImpl.java index 3ea9a95517..e8e5a85aeb 100644 --- a/group05/578505552/src/main/java/com/coderising/download/impl/ConnectionManagerImpl.java +++ b/group05/578505552/src/main/java/dataStruct/com/coderising/download/impl/ConnectionManagerImpl.java @@ -1,8 +1,8 @@ -package com.coderising.download.impl; +package dataStruct.com.coderising.download.impl; -import com.coderising.download.api.Connection; -import com.coderising.download.api.ConnectionException; -import com.coderising.download.api.ConnectionManager; +import dataStruct.com.coderising.download.api.Connection; +import dataStruct.com.coderising.download.api.ConnectionException; +import dataStruct.com.coderising.download.api.ConnectionManager; import java.net.HttpURLConnection; import java.net.URL; diff --git a/group05/578505552/src/main/java/com/coderising/litestruts/Action.java b/group05/578505552/src/main/java/dataStruct/com/coderising/litestruts/Action.java similarity index 89% rename from group05/578505552/src/main/java/com/coderising/litestruts/Action.java rename to group05/578505552/src/main/java/dataStruct/com/coderising/litestruts/Action.java index 743f452030..1c9ad259ad 100644 --- a/group05/578505552/src/main/java/com/coderising/litestruts/Action.java +++ b/group05/578505552/src/main/java/dataStruct/com/coderising/litestruts/Action.java @@ -1,38 +1,38 @@ -package com.coderising.litestruts; - - -import java.util.Map; - -/** - * Created by songbao.yang on 2017/3/1. - * - */ -public class Action { - private String name; - private String className; - private Map results; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getClassName() { - return className; - } - - public void setClassName(String className) { - this.className = className; - } - - public Map getResults() { - return results; - } - - public void setResults(Map results) { - this.results = results; - } -} +package dataStruct.com.coderising.litestruts; + + +import java.util.Map; + +/** + * Created by songbao.yang on 2017/3/1. + * + */ +public class Action { + private String name; + private String className; + private Map results; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getClassName() { + return className; + } + + public void setClassName(String className) { + this.className = className; + } + + public Map getResults() { + return results; + } + + public void setResults(Map results) { + this.results = results; + } +} diff --git a/group05/578505552/src/main/java/com/coderising/litestruts/Configuration.java b/group05/578505552/src/main/java/dataStruct/com/coderising/litestruts/Configuration.java similarity index 63% rename from group05/578505552/src/main/java/com/coderising/litestruts/Configuration.java rename to group05/578505552/src/main/java/dataStruct/com/coderising/litestruts/Configuration.java index 90d8a0c6a1..c85b40029f 100644 --- a/group05/578505552/src/main/java/com/coderising/litestruts/Configuration.java +++ b/group05/578505552/src/main/java/dataStruct/com/coderising/litestruts/Configuration.java @@ -1,4 +1,4 @@ -package com.coderising.litestruts; +package dataStruct.com.coderising.litestruts; /** * Created by songbao.yang on 2017/3/10. diff --git a/group05/578505552/src/main/java/com/coderising/litestruts/LoginAction.java b/group05/578505552/src/main/java/dataStruct/com/coderising/litestruts/LoginAction.java similarity index 92% rename from group05/578505552/src/main/java/com/coderising/litestruts/LoginAction.java rename to group05/578505552/src/main/java/dataStruct/com/coderising/litestruts/LoginAction.java index b74dfa425d..b7789abf28 100644 --- a/group05/578505552/src/main/java/com/coderising/litestruts/LoginAction.java +++ b/group05/578505552/src/main/java/dataStruct/com/coderising/litestruts/LoginAction.java @@ -1,38 +1,38 @@ -package com.coderising.litestruts; - -/** - * 这是一个用来展示登录的业务类, 其中的用户名和密码都是硬编码的。 - * - */ -public class LoginAction{ - private String name ; - private String password; - private String message; - - public String getName() { - return name; - } - - public String getPassword() { - return password; - } - - public String execute(){ - if("test".equals(name) && "1234".equals(password)){ - this.message = "login successful"; - return "success"; - } - this.message = "login failed,please check your user/pwd"; - return "fail"; - } - - public void setName(String name){ - this.name = name; - } - public void setPassword(String password){ - this.password = password; - } - public String getMessage(){ - return this.message; - } -} +package dataStruct.com.coderising.litestruts; + +/** + * 这是一个用来展示登录的业务类, 其中的用户名和密码都是硬编码的。 + * + */ +public class LoginAction{ + private String name ; + private String password; + private String message; + + public String getName() { + return name; + } + + public String getPassword() { + return password; + } + + public String execute(){ + if("test".equals(name) && "1234".equals(password)){ + this.message = "login successful"; + return "success"; + } + this.message = "login failed,please check your user/pwd"; + return "fail"; + } + + public void setName(String name){ + this.name = name; + } + public void setPassword(String password){ + this.password = password; + } + public String getMessage(){ + return this.message; + } +} diff --git a/group05/578505552/src/main/java/com/coderising/litestruts/ReflectUtils.java b/group05/578505552/src/main/java/dataStruct/com/coderising/litestruts/ReflectUtils.java similarity index 81% rename from group05/578505552/src/main/java/com/coderising/litestruts/ReflectUtils.java rename to group05/578505552/src/main/java/dataStruct/com/coderising/litestruts/ReflectUtils.java index c11c5632f3..cb35e59963 100644 --- a/group05/578505552/src/main/java/com/coderising/litestruts/ReflectUtils.java +++ b/group05/578505552/src/main/java/dataStruct/com/coderising/litestruts/ReflectUtils.java @@ -1,4 +1,4 @@ -package com.coderising.litestruts; +package dataStruct.com.coderising.litestruts; import java.lang.reflect.Method; diff --git a/group05/578505552/src/main/java/com/coderising/litestruts/Struts.java b/group05/578505552/src/main/java/dataStruct/com/coderising/litestruts/Struts.java similarity index 96% rename from group05/578505552/src/main/java/com/coderising/litestruts/Struts.java rename to group05/578505552/src/main/java/dataStruct/com/coderising/litestruts/Struts.java index 95b4d37a52..00bc5a446f 100644 --- a/group05/578505552/src/main/java/com/coderising/litestruts/Struts.java +++ b/group05/578505552/src/main/java/dataStruct/com/coderising/litestruts/Struts.java @@ -1,131 +1,131 @@ -package com.coderising.litestruts; - -import org.dom4j.Document; -import org.dom4j.DocumentException; -import org.dom4j.Element; -import org.dom4j.io.SAXReader; - -import java.beans.IntrospectionException; -import java.beans.PropertyDescriptor; -import java.io.InputStream; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -public class Struts { - - public static View runAction(String actionName, Map parameters) { - -// 0. 读取配置文件struts.xml - Action action = matchAction(parseXml("/struts.xml"), actionName); - try { - -// 1. 根据actionName找到相对应的class, 通过反射实例化(创建对象), -// 根据parameters中的数据,调用对象的setter方法 - Class clazz = Class.forName(action.getClassName()); - Object instance = clazz.newInstance(); - for (String key : parameters.keySet()){ - try { - PropertyDescriptor propertyDescriptor = new PropertyDescriptor(key, clazz); - Method setMethod = propertyDescriptor.getWriteMethod(); - setMethod.invoke(instance, parameters.get(key)); - } catch (IntrospectionException e) { - e.printStackTrace(); - } - } - -// 2. 通过反射调用对象的exectue 方法, 并获得返回值,例如"success" - Method exectueMethod = null; - String result = null; - try { - exectueMethod = clazz.getMethod("execute"); - result = (String)exectueMethod.invoke(instance); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } - -// 3. 通过反射找到对象的所有getter方法(例如 getMessage), -// 通过反射来调用, 把值和属性形成一个HashMap , 例如 {"message": "登录成功"} , -// 放到View对象的parameters - Map hashMap = new HashMap(); - Field[] declaredFields = clazz.getDeclaredFields(); - for (Field field : declaredFields){ - String name = field.getName(); - try { - PropertyDescriptor propertyDescriptor = new PropertyDescriptor(name, clazz); - Method getMethod = propertyDescriptor.getReadMethod(); - Object res = getMethod.invoke(instance); - hashMap.put(name, res); - } catch (IntrospectionException e) { - e.printStackTrace(); - } - } - -// 4. 根据struts.xml中的 配置,以及execute的返回值, 确定哪一个jsp, -// 放到View对象的jsp字段中。 - View view = new View(); - view.setJsp((String)action.getResults().get(result)); - view.setParameters(hashMap); - return view; - - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } - - return null; - } - - private static Element parseXml(String resourcePath){ - - InputStream resourceAsStream = Struts.class.getResourceAsStream(resourcePath); - SAXReader saxReader = new SAXReader(); - try { - Document document = saxReader.read(resourceAsStream); - Element rootElement = document.getRootElement(); - return rootElement; - } catch (DocumentException e) { - e.printStackTrace(); - } - - throw new RuntimeException("fail to parse xml"); - } - - private static Action matchAction(Element rootElement, String actionName){ - - List actions = rootElement.elements("action"); - Iterator iterator = actions.iterator(); - Action action = new Action(); - while (iterator.hasNext()){ - Element actionElement = (Element) iterator.next(); - String nameAttributeValue = actionElement.attributeValue("name"); - if (actionName.equals(nameAttributeValue)){ - action.setName(nameAttributeValue); - action.setClassName(actionElement.attributeValue("class")); - List results = actionElement.elements("result"); - Map resultMap = new HashMap(); - Iterator it = results.iterator(); - while (it.hasNext()){ - Element resultElement = (Element)it.next(); - resultMap.put(resultElement.attributeValue("name"), (String)resultElement.getData()); - } - action.setResults(resultMap); - } - } - - return action; - } - - - - -} +package dataStruct.com.coderising.litestruts; + +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.Element; +import org.dom4j.io.SAXReader; + +import java.beans.IntrospectionException; +import java.beans.PropertyDescriptor; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +public class Struts { + + public static View runAction(String actionName, Map parameters) { + +// 0. 读取配置文件struts.xml + Action action = matchAction(parseXml("/struts.xml"), actionName); + try { + +// 1. 根据actionName找到相对应的class, 通过反射实例化(创建对象), +// 根据parameters中的数据,调用对象的setter方法 + Class clazz = Class.forName(action.getClassName()); + Object instance = clazz.newInstance(); + for (String key : parameters.keySet()){ + try { + PropertyDescriptor propertyDescriptor = new PropertyDescriptor(key, clazz); + Method setMethod = propertyDescriptor.getWriteMethod(); + setMethod.invoke(instance, parameters.get(key)); + } catch (IntrospectionException e) { + e.printStackTrace(); + } + } + +// 2. 通过反射调用对象的exectue 方法, 并获得返回值,例如"success" + Method exectueMethod = null; + String result = null; + try { + exectueMethod = clazz.getMethod("execute"); + result = (String)exectueMethod.invoke(instance); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } + +// 3. 通过反射找到对象的所有getter方法(例如 getMessage), +// 通过反射来调用, 把值和属性形成一个HashMap , 例如 {"message": "登录成功"} , +// 放到View对象的parameters + Map hashMap = new HashMap(); + Field[] declaredFields = clazz.getDeclaredFields(); + for (Field field : declaredFields){ + String name = field.getName(); + try { + PropertyDescriptor propertyDescriptor = new PropertyDescriptor(name, clazz); + Method getMethod = propertyDescriptor.getReadMethod(); + Object res = getMethod.invoke(instance); + hashMap.put(name, res); + } catch (IntrospectionException e) { + e.printStackTrace(); + } + } + +// 4. 根据struts.xml中的 配置,以及execute的返回值, 确定哪一个jsp, +// 放到View对象的jsp字段中。 + View view = new View(); + view.setJsp((String)action.getResults().get(result)); + view.setParameters(hashMap); + return view; + + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + + return null; + } + + private static Element parseXml(String resourcePath){ + + InputStream resourceAsStream = Struts.class.getResourceAsStream(resourcePath); + SAXReader saxReader = new SAXReader(); + try { + Document document = saxReader.read(resourceAsStream); + Element rootElement = document.getRootElement(); + return rootElement; + } catch (DocumentException e) { + e.printStackTrace(); + } + + throw new RuntimeException("fail to parse xml"); + } + + private static Action matchAction(Element rootElement, String actionName){ + + List actions = rootElement.elements("action"); + Iterator iterator = actions.iterator(); + Action action = new Action(); + while (iterator.hasNext()){ + Element actionElement = (Element) iterator.next(); + String nameAttributeValue = actionElement.attributeValue("name"); + if (actionName.equals(nameAttributeValue)){ + action.setName(nameAttributeValue); + action.setClassName(actionElement.attributeValue("class")); + List results = actionElement.elements("result"); + Map resultMap = new HashMap(); + Iterator it = results.iterator(); + while (it.hasNext()){ + Element resultElement = (Element)it.next(); + resultMap.put(resultElement.attributeValue("name"), (String)resultElement.getData()); + } + action.setResults(resultMap); + } + } + + return action; + } + + + + +} diff --git a/group05/578505552/src/main/java/com/coderising/litestruts/View.java b/group05/578505552/src/main/java/dataStruct/com/coderising/litestruts/View.java similarity index 85% rename from group05/578505552/src/main/java/com/coderising/litestruts/View.java rename to group05/578505552/src/main/java/dataStruct/com/coderising/litestruts/View.java index 0194c681f6..bb6f39e9a9 100644 --- a/group05/578505552/src/main/java/com/coderising/litestruts/View.java +++ b/group05/578505552/src/main/java/dataStruct/com/coderising/litestruts/View.java @@ -1,23 +1,23 @@ -package com.coderising.litestruts; - -import java.util.Map; - -public class View { - private String jsp; - private Map parameters; - - public String getJsp() { - return jsp; - } - public View setJsp(String jsp) { - this.jsp = jsp; - return this; - } - public Map getParameters() { - return parameters; - } - public View setParameters(Map parameters) { - this.parameters = parameters; - return this; - } -} +package dataStruct.com.coderising.litestruts; + +import java.util.Map; + +public class View { + private String jsp; + private Map parameters; + + public String getJsp() { + return jsp; + } + public View setJsp(String jsp) { + this.jsp = jsp; + return this; + } + public Map getParameters() { + return parameters; + } + public View setParameters(Map parameters) { + this.parameters = parameters; + return this; + } +} diff --git a/group05/578505552/src/main/java/com/coding/basic/ArrayList.java b/group05/578505552/src/main/java/dataStruct/com/coding/basic/ArrayList.java similarity index 84% rename from group05/578505552/src/main/java/com/coding/basic/ArrayList.java rename to group05/578505552/src/main/java/dataStruct/com/coding/basic/ArrayList.java index 54d8f05f02..cdbb1107a0 100644 --- a/group05/578505552/src/main/java/com/coding/basic/ArrayList.java +++ b/group05/578505552/src/main/java/dataStruct/com/coding/basic/ArrayList.java @@ -1,103 +1,103 @@ -package com.coding.basic; - -import java.util.NoSuchElementException; - -/** - * Created by songbao.yang on 2017/2/21. - * - */ -public class ArrayList implements List { - - private int size = 0; - private Object[] elementData; - private static final int MIN_CAPACITY = 10; - - public ArrayList(int size) { - if (size < 0){ - throw new IllegalArgumentException("illega size: " + size); - } - this.elementData = new Object[size]; - } - - public ArrayList() { - this.elementData = new Object[0]; - } - - public void add(Object o){ - ensureCapacity(size + 1); - elementData[size++] = o; - } - - private void ensureCapacity(int minCapacity){ - if (minCapacity < 0 ){ - throw new OutOfMemoryError(); - } - - int newCapcity = size; - if(minCapacity < MIN_CAPACITY){ - newCapcity = MIN_CAPACITY; - } else if(minCapacity > elementData.length){ - int tmp = elementData.length << 1; - newCapcity = tmp > elementData.length ? tmp : Integer.MAX_VALUE; - } - - newCapcity = minCapacity; - Object[] newData = new Object[newCapcity]; - System.arraycopy(elementData, 0, newData, 0, size); - elementData = newData; - } - - public void add(int index, Object o){ - indexCheck(index); - ensureCapacity(size+1); - System.arraycopy(elementData, index, elementData, index+1, size-index); - elementData[index] = o; - size++; - } - - public Object get(int index){ - indexCheck(index); - return elementData[index]; - } - - private void indexCheck(int index){ - if(index < 0){ - throw new IllegalArgumentException("illegal index: " + index); - } - if(index >= size){ - throw new IndexOutOfBoundsException(); - } - } - - public Object remove(int index){ - indexCheck(index); - Object rm = elementData[index]; - System.arraycopy(elementData, index+1, elementData, index, size-index-1); - size--; - return rm; - } - - public int size(){ - return size; - } - - public Iterator iterator(){ - return new Itr(); - } - - //静态内部类的访问权限不同有何区别?? - private class Itr implements Iterator{ - private int cursor = 0; - - public boolean hasNext() { - return cursor != size; - } - - public Object next() { - if (hasNext()){ - return elementData[cursor++]; - } - throw new NoSuchElementException(); - } - } -} +package dataStruct.com.coding.basic; + +import java.util.NoSuchElementException; + +/** + * Created by songbao.yang on 2017/2/21. + * + */ +public class ArrayList implements List { + + private int size = 0; + private Object[] elementData; + private static final int MIN_CAPACITY = 10; + + public ArrayList(int size) { + if (size < 0){ + throw new IllegalArgumentException("illega size: " + size); + } + this.elementData = new Object[size]; + } + + public ArrayList() { + this.elementData = new Object[0]; + } + + public void add(T o){ + ensureCapacity(size + 1); + elementData[size++] = o; + } + + private void ensureCapacity(int minCapacity){ + if (minCapacity < 0 ){ + throw new OutOfMemoryError(); + } + + int newCapcity = size; + if(minCapacity < MIN_CAPACITY){ + newCapcity = MIN_CAPACITY; + } else if(minCapacity > elementData.length){ + int tmp = elementData.length << 1; + newCapcity = tmp > elementData.length ? tmp : Integer.MAX_VALUE; + } + + newCapcity = minCapacity; + Object[] newData = new Object[newCapcity]; + System.arraycopy(elementData, 0, newData, 0, size); + elementData = newData; + } + + public void add(int index, T o){ + indexCheck(index); + ensureCapacity(size+1); + System.arraycopy(elementData, index, elementData, index+1, size-index); + elementData[index] = o; + size++; + } + + public T get(int index){ + indexCheck(index); + return (T) elementData[index]; + } + + private void indexCheck(int index){ + if(index < 0){ + throw new IllegalArgumentException("illegal index: " + index); + } + if(index >= size){ + throw new IndexOutOfBoundsException(); + } + } + + public T remove(int index){ + indexCheck(index); + Object rm = elementData[index]; + System.arraycopy(elementData, index+1, elementData, index, size-index-1); + size--; + return (T) rm; + } + + public int size(){ + return size; + } + + public Iterator iterator(){ + return new Itr(); + } + + //静态内部类的访问权限不同有何区别?? + private class Itr implements Iterator { + private int cursor = 0; + + public boolean hasNext() { + return cursor != size; + } + + public Object next() { + if (hasNext()){ + return elementData[cursor++]; + } + throw new NoSuchElementException(); + } + } +} diff --git a/group05/578505552/src/main/java/com/coding/basic/BinaryTreeNode.java b/group05/578505552/src/main/java/dataStruct/com/coding/basic/BinaryTreeNode.java similarity index 97% rename from group05/578505552/src/main/java/com/coding/basic/BinaryTreeNode.java rename to group05/578505552/src/main/java/dataStruct/com/coding/basic/BinaryTreeNode.java index 3a36db4031..ee0351da07 100644 --- a/group05/578505552/src/main/java/com/coding/basic/BinaryTreeNode.java +++ b/group05/578505552/src/main/java/dataStruct/com/coding/basic/BinaryTreeNode.java @@ -1,4 +1,4 @@ -package com.coding.basic; +package dataStruct.com.coding.basic; /** * Created by songbao.yang on 2017/2/21. diff --git a/group05/578505552/src/main/java/com/coding/basic/Iterator.java b/group05/578505552/src/main/java/dataStruct/com/coding/basic/Iterator.java similarity index 78% rename from group05/578505552/src/main/java/com/coding/basic/Iterator.java rename to group05/578505552/src/main/java/dataStruct/com/coding/basic/Iterator.java index 6765eae519..1755e82202 100644 --- a/group05/578505552/src/main/java/com/coding/basic/Iterator.java +++ b/group05/578505552/src/main/java/dataStruct/com/coding/basic/Iterator.java @@ -1,11 +1,11 @@ -package com.coding.basic; - -/** - * Created by songbao.yang on 2017/2/21. - * - */ -public interface Iterator { - public boolean hasNext(); - public Object next(); - -} +package dataStruct.com.coding.basic; + +/** + * Created by songbao.yang on 2017/2/21. + * + */ +public interface Iterator { + public boolean hasNext(); + public Object next(); + +} diff --git a/group05/578505552/src/main/java/dataStruct/com/coding/basic/LinkedList.java b/group05/578505552/src/main/java/dataStruct/com/coding/basic/LinkedList.java new file mode 100644 index 0000000000..9238a5c7a0 --- /dev/null +++ b/group05/578505552/src/main/java/dataStruct/com/coding/basic/LinkedList.java @@ -0,0 +1,390 @@ +package dataStruct.com.coding.basic; + +import java.util.NoSuchElementException; + +/** + * Created by songbao.yang on 2017/2/21. + * + */ +public class LinkedList implements List { + + private Node head; + private int elementCount; + + //head作为一个节点,其next的值指向List中真正的第一个节点 + public LinkedList() { + head = new Node(); + head.next = null; + head.data = null; + elementCount = 0; + } + + public void add(T o){ + Node newNode = new Node(); + newNode.data = o; + newNode.next = null; + + Node cursor = head; + while (cursor.next != null){ + cursor = cursor.next; + } + cursor.next = newNode; + elementCount++; + } + + + public void add(int index , T o){ + indexRangeCheck(index); + Node newNode = new Node(); + newNode.data = o; + + Node cursor = head; + for (int i = 0; i < index; i++) { + cursor = cursor.next; //将cursor移动到index-1节点处; + } + + newNode.next = cursor.next; //将新节点指向原index处的节点 + cursor.next = newNode;//将原index-1处的节点指向新节点 + elementCount++; + } + + private void indexRangeCheck(int index){ + if (index < 0 || index >= size()){ + throw new IndexOutOfBoundsException(); + } + } + + public T get(int index){ + indexRangeCheck(index); + Node cursor = head; + for (int i = 0; i < index; i++) { + cursor = cursor.next; + } + return (T) cursor.next.data; + } + + public T remove(int index){ + indexRangeCheck(index); + Node cursor = head; + for (int i = 0; i < index; i++) { + cursor = cursor.next; + } + Node indexNode = cursor.next; + cursor.next = indexNode.next; + elementCount--; + return (T) indexNode; + } + + public int size(){ + return elementCount; + } + + public void addFirst(T o){ + Node node = new Node(); + node.data = o; + node.next = head.next; + head.next = node; + elementCount++; + } + + public void addLast(T o){ + + Node cursor = head; + while (cursor.next != null){ + cursor = cursor.next; + } + Node newNode = new Node(); + newNode.data = o; + newNode.next = null; + cursor.next = newNode; + elementCount++; + } + + public T removeFirst(){ + + if (size() == 0){ + throw new RuntimeException("no element in list"); + } + Node firstNode = head.next; + head.next = head.next.next; + elementCount--; + return (T) firstNode; + } + + public T removeLast(){ + if (size() == 0){ + throw new RuntimeException("no element in list"); + } + + Node cursor = head; + for (int i = 0; i < size() - 1; i++) { + cursor = cursor.next; + } + + Node lastNode = cursor.next; + cursor.next = null; + elementCount--; + + return (T) lastNode; + } + + public Iterator iterator(){ + return new Itr(); + } + + private class Itr implements Iterator { + + private Node itrCursor = head; + + public boolean hasNext() { + + return itrCursor.next != null; + } + + public Object next() { + if (hasNext()){ + return itrCursor.next; + } + throw new NoSuchElementException(); + } + } + + private static class Node{ + T data; + Node next; + } + + /** + * 把该链表逆置 + * 例如链表为 3->7->10 , 逆置后变为 10->7->3 + */ + public void reverse(){ + if (elementCount <= 1){ + return; + } + + Node first = head.next; + Node second = head.next.next; + + first.next = null; + while (second != null){ + Node temp = second.next; + second.next = first; + first = second; + second = temp; + } + head.next = first; + } + + /** + * 删除一个单链表的前半部分 + * 例如:list = 2->5->7->8 , 删除以后的值为 7->8 + * 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10 + + */ + public void removeFirstHalf(){ + + Node cousor = head.next; + for (int i = 0; i < elementCount / 2; i++) { + Node temp = cousor; + cousor = cousor.next; + temp.data = null; + temp.next = null; + } + head.next = cousor; + } + + /** + * 从第i个元素开始, 删除length 个元素 , 注意i从0开始 + * @param i + * @param length + */ + public void remove(int i, int length){ + if (i < 0 || length < 0){ + return; + } + if (i > elementCount - 1){ + throw new IndexOutOfBoundsException("index i is too big"); + } + + Node beforei = head; + for (int j = 0; j < i; j++) { + beforei = beforei.next; + } + Node cursor = beforei.next; + for (int j = 0; j < length; j++) { + if (cursor != null){ + Node temp = cursor; + cursor = cursor.next; + temp.data = null; + temp.next = null; + }else { + break; + } + } + beforei.next = cursor; + } + /** + * 假定当前链表和listB均包含已升序排列的整数 + * 从当前链表中取出那些listB所指定的元素 + * 例如当前链表 = 11->101->201->301->401->501->601->701 + * listB = 1->3->4->6 + * 返回的结果应该是[101,301,401,601] + * @param list + */ + public int[] getElements(LinkedList list){ + + int[] result = new int[list.size()]; + int i = 0; + int pre = 0; + Node cousor = head.next; + Iterator YIterator = list.iterator(); + while (YIterator.hasNext()){ + int index = (Integer) YIterator.next(); + if (index > elementCount - 1){ + break; + } + moveForwardNIndex(cousor, index - pre); + result[i++] = (Integer) cousor.data; + pre = index; + } + + int[] ints = new int[result.length]; + System.arraycopy(result, 0, ints, 0, result.length); + return ints; + } + + private void moveForwardNIndex(Node index, int n){ + for (int i = 0; i < n; i++) { + if (index == null){ + break; + } + index = index.next; + } + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 从当前链表中中删除在listB中出现的元素 + + * @param list + */ + + public void subtract(LinkedList list){ + + Node pre = head; + Node node = head.next; + while (node != null){ + if (list.contains(node.data)){ + pre.next = node.next; + node = node.next; + } else { + pre = node; + node = node.next; + } + } + } + + public boolean contains(T data){ + + Node cursor = this.head.next; + while (cursor != null){ + if (cursor.data.equals(data)){ + return true; + } + } + return false; + } + + /** + * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) + */ + public void removeDuplicateValues(){ + + if (elementCount <= 1){ + return; + } + Node pre = head.next; + Node node = pre.next; + while (node != null){ + if (node.data.equals(pre.data)){ + pre.next = node.next; + node = node.next; + } else { + pre = node; + node = node.next; + } + } + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 试写一高效的算法,删除表中所有值大于min且小于max的元素(若表中存在这样的元素) + * @param min + * @param max + */ + //TODO 这个泛型的比较没搞明白, 为什么会出现cast的问题,不应该都是T类型吗 + public void removeRange(T min, T max){ + if (min.compareTo(max) > 0){ + return; + } + if (size() == 0){ + return; + } + Node beforeMin = head; + //泛型化 + while (beforeMin.next != null && beforeMin.next.data.compareTo(min) <= 0){ + beforeMin = beforeMin.next; + } + Node afterMax = beforeMin.next; + while (afterMax != null && afterMax.data.compareTo(max) < 0){ + afterMax = afterMax.next; + } + beforeMin.next = afterMax; + } + + /** + * 假设当前链表和参数list指定的链表均以元素依值递增有序排列(同一表中的元素值各不相同) + * 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列 + * @param list + */ + public LinkedList intersection(LinkedList list){ + + if (list == null || list.size() == 0 || this.size() == 0){ + return new LinkedList(); + } + + Node cursorA = this.head.next; + Node cursorB = list.head.next; + LinkedList listC = new LinkedList(); + + while (cursorA != null && cursorB != null){ + if (cursorA.data.compareTo(cursorB.data) == 0){ + listC.add((T)cursorA.data); + } else if (cursorA.data.compareTo(cursorB.data) < 0){ + cursorA = cursorA.next; + } else { + cursorB = cursorB.next; + } + } + return listC; + } + + public void addAfter(Node node, T o){ + if (node == null){ + return; + } + Node newNode = new Node(); + newNode.data = o; + addAfter(node, newNode); + } + + public void addAfter(Node node, Node newNode){ + if (node == null || newNode == null){ + return; + } + newNode.next = node.next; + node.next = newNode; + } +} diff --git a/group05/578505552/src/main/java/dataStruct/com/coding/basic/List.java b/group05/578505552/src/main/java/dataStruct/com/coding/basic/List.java new file mode 100644 index 0000000000..20d7a6daf9 --- /dev/null +++ b/group05/578505552/src/main/java/dataStruct/com/coding/basic/List.java @@ -0,0 +1,14 @@ +package dataStruct.com.coding.basic; + +/** + * Created by songbao.yang on 2017/2/21. + * + */ +public interface List { + public void add(T o); + public void add(int index, T o); + public T get(int index); + public T remove(int index); + public int size(); + public Iterator iterator(); +} diff --git a/group05/578505552/src/main/java/com/coding/basic/Queue.java b/group05/578505552/src/main/java/dataStruct/com/coding/basic/Queue.java similarity index 95% rename from group05/578505552/src/main/java/com/coding/basic/Queue.java rename to group05/578505552/src/main/java/dataStruct/com/coding/basic/Queue.java index ec31573ee7..2b3a62a5d3 100644 --- a/group05/578505552/src/main/java/com/coding/basic/Queue.java +++ b/group05/578505552/src/main/java/dataStruct/com/coding/basic/Queue.java @@ -1,90 +1,90 @@ -package com.coding.basic; - -import java.util.NoSuchElementException; - -/** - * Created by songbao.yang on 2017/2/22. - * - */ -public class Queue { - - private Object[] elementData; - private int head; //对头的位置 - private int tail; //队尾的位置 - private int size; //队列中元素的个数 - private static final int MIN_INITIAL_CAPACITY = 10; - - public Queue() { - this.elementData = new Object[MIN_INITIAL_CAPACITY]; - this.head = 0; - this.tail = 0; - this.size = 0; - } - - public Queue(int initCapcacity) { - if (initCapcacity < MIN_INITIAL_CAPACITY){ - initCapcacity = MIN_INITIAL_CAPACITY; - } - this.elementData = new Object[initCapcacity]; - this.head = 0; - this.tail = 0; - this.size = 0; - } - - public void enQueue(Object o){ - ensureCapacity(size+1); - if(size != 0){ - tail++; - } - if(tail == elementData.length){ - tail = 0; - } - elementData[tail] = o; - size++; - } - - private void ensureCapacity(int minCapcacity){ - if(minCapcacity <= elementData.length){ - return; - } - - int newCapcacity = elementData.length << 1; - if (newCapcacity < elementData.length){ - newCapcacity = Integer.MAX_VALUE; - } - - Object[] newData = new Object[newCapcacity]; - if(size != 0){ - if(tail >= head){ - System.arraycopy(elementData, head, newData, 0, size); - } else { - System.arraycopy(elementData, head, newData, 0, elementData.length - head); - System.arraycopy(elementData, 0, newData, elementData.length - head, tail + 1); - } - elementData = newData; - head = 0; - tail = this.size - 1; - } - } - - public Object deQueue(){ - if (isEmpty()){ - throw new NoSuchElementException("empty queue"); - } - Object ele = elementData[head]; - size--; - head++; - if(head == elementData.length){ - head = 0; - } - return ele; - } - - public boolean isEmpty(){ - return size == 0; - } - - public int size(){ - return size; - } -} +package dataStruct.com.coding.basic; + +import java.util.NoSuchElementException; + +/** + * Created by songbao.yang on 2017/2/22. + * + */ +public class Queue { + + private Object[] elementData; + private int head; //对头的位置 + private int tail; //队尾的位置 + private int size; //队列中元素的个数 + private static final int MIN_INITIAL_CAPACITY = 10; + + public Queue() { + this.elementData = new Object[MIN_INITIAL_CAPACITY]; + this.head = 0; + this.tail = 0; + this.size = 0; + } + + public Queue(int initCapcacity) { + if (initCapcacity < MIN_INITIAL_CAPACITY){ + initCapcacity = MIN_INITIAL_CAPACITY; + } + this.elementData = new Object[initCapcacity]; + this.head = 0; + this.tail = 0; + this.size = 0; + } + + public void enQueue(Object o){ + ensureCapacity(size+1); + if(size != 0){ + tail++; + } + if(tail == elementData.length){ + tail = 0; + } + elementData[tail] = o; + size++; + } + + private void ensureCapacity(int minCapcacity){ + if(minCapcacity <= elementData.length){ + return; + } + + int newCapcacity = elementData.length << 1; + if (newCapcacity < elementData.length){ + newCapcacity = Integer.MAX_VALUE; + } + + Object[] newData = new Object[newCapcacity]; + if(size != 0){ + if(tail >= head){ + System.arraycopy(elementData, head, newData, 0, size); + } else { + System.arraycopy(elementData, head, newData, 0, elementData.length - head); + System.arraycopy(elementData, 0, newData, elementData.length - head, tail + 1); + } + elementData = newData; + head = 0; + tail = this.size - 1; + } + } + + public Object deQueue(){ + if (isEmpty()){ + throw new NoSuchElementException("empty queue"); + } + Object ele = elementData[head]; + size--; + head++; + if(head == elementData.length){ + head = 0; + } + return ele; + } + + public boolean isEmpty(){ + return size == 0; + } + + public int size(){ + return size; + } +} diff --git a/group05/578505552/src/main/java/com/coding/basic/Stack.java b/group05/578505552/src/main/java/dataStruct/com/coding/basic/Stack.java similarity index 97% rename from group05/578505552/src/main/java/com/coding/basic/Stack.java rename to group05/578505552/src/main/java/dataStruct/com/coding/basic/Stack.java index ffc4915bef..4f41c69a9e 100644 --- a/group05/578505552/src/main/java/com/coding/basic/Stack.java +++ b/group05/578505552/src/main/java/dataStruct/com/coding/basic/Stack.java @@ -1,4 +1,4 @@ -package com.coding.basic; +package dataStruct.com.coding.basic; import java.util.EmptyStackException; diff --git a/group05/578505552/src/main/java/dataStruct/com/coding/basic/linklist/LRUPageFrame.java b/group05/578505552/src/main/java/dataStruct/com/coding/basic/linklist/LRUPageFrame.java new file mode 100644 index 0000000000..cebc4bc739 --- /dev/null +++ b/group05/578505552/src/main/java/dataStruct/com/coding/basic/linklist/LRUPageFrame.java @@ -0,0 +1,105 @@ +package dataStruct.com.coding.basic.linklist; + +/** + * 用双向链表实现LRU算法 + * @author songbao.yang + * + */ +public class LRUPageFrame { + + private static class Node { + + Node prev; + Node next; + int pageNum; + + Node() { + } + } + + private int capacity; + private int size; + + private Node first;// 链表头 + private Node last;// 链表尾 + + + public LRUPageFrame(int capacity) { + + this.capacity = capacity; + this.size = 0; + first = null; + last = null; + } + + /** + * 获取缓存中对象 + * + * @param pageNum + * @return + */ + public void access(int pageNum) { + + Node newNode = new Node(); + newNode.pageNum = pageNum; + + //往链表头部加入元素 + if (size == 0){ + first = newNode; + last = newNode; + } else { + newNode.next = first; + if (first == null){ + System.out.println("fuck"); + } + first.prev = newNode; + first = newNode; + } + size++; + + //去重 + Node node = first.next; + while (node != null){ + if (node.pageNum == pageNum){ + node.prev.next = node.next; + + if (node == last){ + last = node.prev; + } else { + node.next.prev = node.prev; + } + + Node tmp = node; + node = node.next; + tmp.next = null; + tmp.prev = null; + size--; + } else { + node = node.next; + } + } + + //调整容量 + if (size > capacity){ + last = last.prev; + last.next.prev = null; + last.next = null; + size--; + } + } + + public String toString(){ + StringBuilder buffer = new StringBuilder(); + Node node = first; + while(node != null){ + buffer.append(node.pageNum); + + node = node.next; + if(node != null){ + buffer.append(","); + } + } + return buffer.toString(); + } + +} diff --git a/group05/578505552/src/main/java/miniJvm/com/coderising/jvm/loader/ClassFileLoader.java b/group05/578505552/src/main/java/miniJvm/com/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..97dc361c12 --- /dev/null +++ b/group05/578505552/src/main/java/miniJvm/com/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,68 @@ +package miniJvm.com.coderising.jvm.loader; + +import java.io.*; +import java.util.ArrayList; +import java.util.List; + +public class ClassFileLoader { + + private List clzPaths = new ArrayList(); + + public byte[] readBinaryCode(String className) { + + String fullClassName = className.replace(".", "\\") + ".class"; + for (String clzpath : clzPaths){ + byte[] binaryCode = readBinaryCode(clzpath, fullClassName); + if (binaryCode != null){ + return binaryCode; + } + } + return null; + } + + private byte[] readBinaryCode(String clzPath, String fullClassName){ + + String filePath = clzPath + "\\" + fullClassName; + File classFile = new File(filePath); + if (!classFile.exists()){ + return null; + } + try { + FileInputStream fileInputStream = new FileInputStream(classFile); + DataInputStream dataInputStream = new DataInputStream(fileInputStream); + List bytes = new ArrayList(); + int b; + while ((b = dataInputStream.read()) != -1){ + bytes.add((byte)b); + } + byte[] res = new byte[bytes.size()]; + for (int i = 0; i < bytes.size(); i++){ + res[i] = bytes.get(i); + } + return res; + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + public void addClassPath(String path) { + + if (path == null){ + return; + } + clzPaths.add(path); + } + + public String getClassPath(){ + + StringBuffer stringBuffer = new StringBuffer(); + for (String path : clzPaths){ + stringBuffer.append(path).append(";"); + } + return stringBuffer.substring(0, stringBuffer.length() - 1); + } + +} diff --git a/group05/578505552/src/main/java/miniJvm/com/coderising/jvm/loader/EmployeeV1.java b/group05/578505552/src/main/java/miniJvm/com/coderising/jvm/loader/EmployeeV1.java new file mode 100644 index 0000000000..edae33a2aa --- /dev/null +++ b/group05/578505552/src/main/java/miniJvm/com/coderising/jvm/loader/EmployeeV1.java @@ -0,0 +1,31 @@ +package miniJvm.com.coderising.jvm.loader; + +public class EmployeeV1 { + + + private String name; + private int age; + + public EmployeeV1() { + } + + public EmployeeV1(String name, int age) { + this.name = name; + this.age = age; + } + + public void setName(String name) { + this.name = name; + } + public void setAge(int age){ + this.age = age; + } + public void sayHello() { + System.out.println("Hello , this is class Employee "); + } + public static void main(String[] args){ + EmployeeV1 p = new EmployeeV1("Andy",29); + p.sayHello(); + + } +} \ No newline at end of file diff --git a/group05/578505552/src/main/resources/struts.xml b/group05/578505552/src/main/resources/struts.xml index 0a44e0927e..0dc7b6de98 100644 --- a/group05/578505552/src/main/resources/struts.xml +++ b/group05/578505552/src/main/resources/struts.xml @@ -1,6 +1,6 @@ - + /jsp/homepage.jsp /jsp/showLogin.jsp diff --git a/group05/578505552/src/test/java/com/coderising/array/ArrayUtilTest.java b/group05/578505552/src/test/java/dataStruct/com/coderising/array/ArrayUtilTest.java similarity index 96% rename from group05/578505552/src/test/java/com/coderising/array/ArrayUtilTest.java rename to group05/578505552/src/test/java/dataStruct/com/coderising/array/ArrayUtilTest.java index 607f4fed5b..b09f2efcd0 100644 --- a/group05/578505552/src/test/java/com/coderising/array/ArrayUtilTest.java +++ b/group05/578505552/src/test/java/dataStruct/com/coderising/array/ArrayUtilTest.java @@ -1,206 +1,205 @@ -package com.coderising.array; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.Arrays; - -/** - * Created by songbao.yang on 2017/3/2. - * - */ -public class ArrayUtilTest { - - private ArrayUtil arrayUtil; - - @Before - public void setUp() throws Exception { - arrayUtil = new ArrayUtil(); - } - - @After - public void tearDown() throws Exception { - - } - - @Test - public void reverseArray() throws Exception { - - int[][] actualAndExpected = { - {}, {}, {0}, {0}, - {1,2,3,4,5,6}, {6,5,4,3,2,1}, - {7,9,30,3,4}, {4,3,30,9,7} - }; - - for (int i = 0; i < actualAndExpected.length; i += 2) { - int[] acutal = actualAndExpected[i]; - int[] expected = actualAndExpected[i+1]; - arrayUtil.reverseArray(acutal); - Assert.assertTrue("wrong index: " + String.valueOf(i), isArrayEqual(expected, acutal)); - } - } - - @Test - public void removeZero() throws Exception { - int[][] actualAndExpected = { - {}, {}, {0}, {}, - {1,0,3,0,5,0}, {1,3,5}, - {1,3,4,5,0,0,6,6,0,5,4,7,6,7,0,5}, {1,3,4,5,6,6,5,4,7,6,7,5} - }; - - for (int i = 0; i < actualAndExpected.length; i += 2) { - int[] acutal = actualAndExpected[i]; - int[] expected = actualAndExpected[i+1]; - int[] ints = arrayUtil.removeZero(acutal); - Assert.assertTrue("wrong index: " + String.valueOf(i), isArrayEqual(expected, ints)); - } - } - - @Test - public void merge() throws Exception { - int[][] actualAndExpected = { - {}, {}, {}, - {}, {0}, {0}, - {3,5,7,8}, {4,5,6,7},{3,4,5,6,7,8}, - {1,2,3,4,5,}, {6,7,8,9,10}, {1,2,3,4,5,6,7,8,9,10} - }; - - for (int i = 0; i < actualAndExpected.length; i += 3) { - int[] array1 = actualAndExpected[i]; - int[] array2 = actualAndExpected[i+1]; - int[] expected = actualAndExpected[i+2]; - int[] result = arrayUtil.merge(array1, array2); - Assert.assertTrue("wrong index: " + String.valueOf(i), isArrayEqual(expected, result)); - } - - } - - @Test - public void grow() throws Exception { - int[][] actualAndExpected = { - {}, {}, - {1}, {}, - {5}, {0,0,0,0,0}, - {0},{2,3,6}, - {3}, {2,3,6,0,0,0} - }; - - for (int i = 0; i < actualAndExpected.length; i += 3) { - int[] oldArray = actualAndExpected[i]; - int size = actualAndExpected[i+1][0]; - int[] expected = actualAndExpected[i+2]; - int[] newArray = arrayUtil.grow(oldArray, size); - Assert.assertTrue("wrong index: " + String.valueOf(i), isArrayEqual(expected, newArray)); - } - } - - @Test - public void fibonacci() throws Exception { - int[][] actualAndExpected = { - {0}, {}, - {1}, {}, - {2}, {1,1}, - {3}, {1,1,2}, - {4}, {1,1,2,3}, - {15}, {1,1,2,3,5,8,13}, - }; - - for (int i = 0; i < actualAndExpected.length; i += 2) { - int max = actualAndExpected[i][0]; - int[] expected = actualAndExpected[i+1]; - int[] actual = arrayUtil.fibonacci(max); - Assert.assertTrue("wrong index: " + String.valueOf(i), isArrayEqual(expected, actual)); - } - } - - @Test - public void getPrimes() throws Exception { - int[][] actualAndExpected = { - {-1}, {}, - {0}, {}, - {1}, {}, - {2}, {}, - {3}, {2}, - {4}, {2,3}, - {23}, {2,3,5,7,11,13,17,19}, - }; - - for (int i = 0; i < actualAndExpected.length; i += 2) { - int max = actualAndExpected[i][0]; - int[] expected = actualAndExpected[i+1]; - int[] actual = arrayUtil.getPrimes(max); - Assert.assertTrue("wrong index: " + String.valueOf(i), isArrayEqual(expected, actual)); - } - } - - @Test - public void getPerfectNumbers() throws Exception { - int[][] actualAndExpected = { - {-1}, {}, - {0}, {}, - {1}, {}, - {2}, {}, - {7}, {6}, - {30}, {6,28}, - {500}, {6,28,496}, - {10000}, {6,28,496,8128} - }; - - for (int i = 0; i < actualAndExpected.length; i += 2) { - int max = actualAndExpected[i][0]; - int[] expected = actualAndExpected[i+1]; - int[] actual = arrayUtil.getPerfectNumbers(max); - Assert.assertTrue("wrong index: " + String.valueOf(i), isArrayEqual(expected, actual)); - } - } - - @Test - public void join() throws Exception { - int[][] arrays = { - {}, - {3,8,9}, - {1}, - {0,0,0,0,0}, - {1,2,3,4,5} - }; - String[] separators = {"", "-", "+", "*", "00"}; - String[] expecteds = { - "", - "3-8-9", - "1", - "0*0*0*0*0", - "1002003004005" - }; - for (int i = 0; i < arrays.length; i++) { - int[] array = arrays[i]; - String separator = separators[i]; - String expected = expecteds[i]; - String actual = arrayUtil.join(array, separator); - Assert.assertTrue("wrong index: " + String.valueOf(i), expected.equals(actual)); - } - } - - private boolean isArrayEqual(int[] expected, int[] actual){ - if (expected.length != actual.length){ - System.out.println("expected.length != actual.length"); - System.out.println("expected: " + Arrays.toString(expected)); - System.out.println("actual: " + Arrays.toString(actual)); - return false; - } - - for (int i = 0; i < expected.length; i++) { - if (expected[i] != actual[i]){ - System.out.println("expected[i] != actual[i]"); - System.out.println("expected: " + Arrays.toString(expected)); - System.out.println("actual: " + Arrays.toString(actual)); - return false; - } - } - - return true; - } - +package dataStruct.com.coderising.array; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; + +/** + * Created by songbao.yang on 2017/3/2. + * + */ +public class ArrayUtilTest { + + private ArrayUtil arrayUtil; + + @Before + public void setUp() throws Exception { + arrayUtil = new ArrayUtil(); + } + + @After + public void tearDown() throws Exception { + + } + + @Test + public void reverseArray() throws Exception { + + int[][] actualAndExpected = { + {}, {}, {0}, {0}, + {1,2,3,4,5,6}, {6,5,4,3,2,1}, + {7,9,30,3,4}, {4,3,30,9,7} + }; + + for (int i = 0; i < actualAndExpected.length; i += 2) { + int[] acutal = actualAndExpected[i]; + int[] expected = actualAndExpected[i+1]; + arrayUtil.reverseArray(acutal); + Assert.assertTrue("wrong index: " + String.valueOf(i), isArrayEqual(expected, acutal)); + } + } + + @Test + public void removeZero() throws Exception { + int[][] actualAndExpected = { + {}, {}, {0}, {}, + {1,0,3,0,5,0}, {1,3,5}, + {1,3,4,5,0,0,6,6,0,5,4,7,6,7,0,5}, {1,3,4,5,6,6,5,4,7,6,7,5} + }; + + for (int i = 0; i < actualAndExpected.length; i += 2) { + int[] acutal = actualAndExpected[i]; + int[] expected = actualAndExpected[i+1]; + int[] ints = arrayUtil.removeZero(acutal); + Assert.assertTrue("wrong index: " + String.valueOf(i), isArrayEqual(expected, ints)); + } + } + + @Test + public void merge() throws Exception { + int[][] actualAndExpected = { + {}, {}, {}, + {}, {0}, {0}, + {3,5,7,8}, {4,5,6,7},{3,4,5,6,7,8}, + {1,2,3,4,5,}, {6,7,8,9,10}, {1,2,3,4,5,6,7,8,9,10} + }; + + for (int i = 0; i < actualAndExpected.length; i += 3) { + int[] array1 = actualAndExpected[i]; + int[] array2 = actualAndExpected[i+1]; + int[] expected = actualAndExpected[i+2]; + int[] result = arrayUtil.merge(array1, array2); + Assert.assertTrue("wrong index: " + String.valueOf(i), isArrayEqual(expected, result)); + } + + } + + @Test + public void grow() throws Exception { + int[][] actualAndExpected = { + {}, {}, + {1}, {}, + {5}, {0,0,0,0,0}, + {0},{2,3,6}, + {3}, {2,3,6,0,0,0} + }; + + for (int i = 0; i < actualAndExpected.length; i += 3) { + int[] oldArray = actualAndExpected[i]; + int size = actualAndExpected[i+1][0]; + int[] expected = actualAndExpected[i+2]; + int[] newArray = arrayUtil.grow(oldArray, size); + Assert.assertTrue("wrong index: " + String.valueOf(i), isArrayEqual(expected, newArray)); + } + } + + @Test + public void fibonacci() throws Exception { + int[][] actualAndExpected = { + {0}, {}, + {1}, {}, + {2}, {1,1}, + {3}, {1,1,2}, + {4}, {1,1,2,3}, + {15}, {1,1,2,3,5,8,13}, + }; + + for (int i = 0; i < actualAndExpected.length; i += 2) { + int max = actualAndExpected[i][0]; + int[] expected = actualAndExpected[i+1]; + int[] actual = arrayUtil.fibonacci(max); + Assert.assertTrue("wrong index: " + String.valueOf(i), isArrayEqual(expected, actual)); + } + } + + @Test + public void getPrimes() throws Exception { + int[][] actualAndExpected = { + {-1}, {}, + {0}, {}, + {1}, {}, + {2}, {}, + {3}, {2}, + {4}, {2,3}, + {23}, {2,3,5,7,11,13,17,19}, + }; + + for (int i = 0; i < actualAndExpected.length; i += 2) { + int max = actualAndExpected[i][0]; + int[] expected = actualAndExpected[i+1]; + int[] actual = arrayUtil.getPrimes(max); + Assert.assertTrue("wrong index: " + String.valueOf(i), isArrayEqual(expected, actual)); + } + } + + @Test + public void getPerfectNumbers() throws Exception { + int[][] actualAndExpected = { + {-1}, {}, + {0}, {}, + {1}, {}, + {2}, {}, + {7}, {6}, + {30}, {6,28}, + {500}, {6,28,496}, + {10000}, {6,28,496,8128} + }; + + for (int i = 0; i < actualAndExpected.length; i += 2) { + int max = actualAndExpected[i][0]; + int[] expected = actualAndExpected[i+1]; + int[] actual = arrayUtil.getPerfectNumbers(max); + Assert.assertTrue("wrong index: " + String.valueOf(i), isArrayEqual(expected, actual)); + } + } + + @Test + public void join() throws Exception { + int[][] arrays = { + {}, + {3,8,9}, + {1}, + {0,0,0,0,0}, + {1,2,3,4,5} + }; + String[] separators = {"", "-", "+", "*", "00"}; + String[] expecteds = { + "", + "3-8-9", + "1", + "0*0*0*0*0", + "1002003004005" + }; + for (int i = 0; i < arrays.length; i++) { + int[] array = arrays[i]; + String separator = separators[i]; + String expected = expecteds[i]; + String actual = arrayUtil.join(array, separator); + Assert.assertTrue("wrong index: " + String.valueOf(i), expected.equals(actual)); + } + } + + private boolean isArrayEqual(int[] expected, int[] actual){ + if (expected.length != actual.length){ + System.out.println("expected.length != actual.length"); + System.out.println("expected: " + Arrays.toString(expected)); + System.out.println("actual: " + Arrays.toString(actual)); + return false; + } + + for (int i = 0; i < expected.length; i++) { + if (expected[i] != actual[i]){ + System.out.println("expected[i] != actual[i]"); + System.out.println("expected: " + Arrays.toString(expected)); + System.out.println("actual: " + Arrays.toString(actual)); + return false; + } + } + + return true; + } + } \ No newline at end of file diff --git a/group05/578505552/src/test/java/com/coderising/download/DownloadThreadTest.java b/group05/578505552/src/test/java/dataStruct/com/coderising/download/DownloadThreadTest.java similarity index 80% rename from group05/578505552/src/test/java/com/coderising/download/DownloadThreadTest.java rename to group05/578505552/src/test/java/dataStruct/com/coderising/download/DownloadThreadTest.java index eaa651776c..dbbb80a91a 100644 --- a/group05/578505552/src/test/java/com/coderising/download/DownloadThreadTest.java +++ b/group05/578505552/src/test/java/dataStruct/com/coderising/download/DownloadThreadTest.java @@ -1,16 +1,15 @@ -package com.coderising.download; +package dataStruct.com.coderising.download; -import com.coderising.download.api.Connection; -import com.coderising.download.api.DownloadListener; -import com.coderising.download.impl.ConnectionManagerImpl; +import dataStruct.com.coderising.download.DownloadThread; +import dataStruct.com.coderising.download.api.Connection; +import dataStruct.com.coderising.download.api.DownloadListener; +import dataStruct.com.coderising.download.impl.ConnectionManagerImpl; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.io.File; -import static org.junit.Assert.*; - /** * Created by songbao.yang on 2017/3/11. */ diff --git a/group05/578505552/src/main/java/com/coderising/download/FileDownloaderTest.java b/group05/578505552/src/test/java/dataStruct/com/coderising/download/FileDownloaderTest.java similarity index 81% rename from group05/578505552/src/main/java/com/coderising/download/FileDownloaderTest.java rename to group05/578505552/src/test/java/dataStruct/com/coderising/download/FileDownloaderTest.java index 6f740c3882..cb5748f4e6 100644 --- a/group05/578505552/src/main/java/com/coderising/download/FileDownloaderTest.java +++ b/group05/578505552/src/test/java/dataStruct/com/coderising/download/FileDownloaderTest.java @@ -1,13 +1,12 @@ -package com.coderising.download; +package dataStruct.com.coderising.download; +import dataStruct.com.coderising.download.api.ConnectionManager; +import dataStruct.com.coderising.download.api.DownloadListener; +import dataStruct.com.coderising.download.impl.ConnectionManagerImpl; import org.junit.After; import org.junit.Before; import org.junit.Test; -import com.coderising.download.api.ConnectionManager; -import com.coderising.download.api.DownloadListener; -import com.coderising.download.impl.ConnectionManagerImpl; - public class FileDownloaderTest { boolean downloadFinished = false; diff --git a/group05/578505552/src/test/java/com/coderising/download/impl/ConnectionImplTest.java b/group05/578505552/src/test/java/dataStruct/com/coderising/download/impl/ConnectionImplTest.java similarity index 85% rename from group05/578505552/src/test/java/com/coderising/download/impl/ConnectionImplTest.java rename to group05/578505552/src/test/java/dataStruct/com/coderising/download/impl/ConnectionImplTest.java index 142540943e..967b4520a2 100644 --- a/group05/578505552/src/test/java/com/coderising/download/impl/ConnectionImplTest.java +++ b/group05/578505552/src/test/java/dataStruct/com/coderising/download/impl/ConnectionImplTest.java @@ -1,13 +1,11 @@ -package com.coderising.download.impl; +package dataStruct.com.coderising.download.impl; -import com.coderising.download.api.Connection; -import com.coderising.download.api.ConnectionManager; +import dataStruct.com.coderising.download.api.Connection; +import dataStruct.com.coderising.download.impl.ConnectionManagerImpl; import org.junit.After; import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.*; - /** * Created by songbao.yang on 2017/3/11. */ diff --git a/group05/578505552/src/test/java/com/coderising/litestruts/StrutsTest.java b/group05/578505552/src/test/java/dataStruct/com/coderising/litestruts/StrutsTest.java similarity index 93% rename from group05/578505552/src/test/java/com/coderising/litestruts/StrutsTest.java rename to group05/578505552/src/test/java/dataStruct/com/coderising/litestruts/StrutsTest.java index 6df05450b6..bdb0334ae5 100644 --- a/group05/578505552/src/test/java/com/coderising/litestruts/StrutsTest.java +++ b/group05/578505552/src/test/java/dataStruct/com/coderising/litestruts/StrutsTest.java @@ -1,40 +1,40 @@ -package com.coderising.litestruts; - -import org.junit.Assert; -import org.junit.Test; - -import java.util.HashMap; -import java.util.Map; - - -public class StrutsTest { - - @Test - public void testLoginActionSuccess() { - - String actionName = "login"; - - Map params = new HashMap(); - params.put("name","test"); - params.put("password","1234"); - - - View view = Struts.runAction(actionName,params); - - Assert.assertEquals("/jsp/homepage.jsp", view.getJsp()); - Assert.assertEquals("login successful", view.getParameters().get("message")); - } - - @Test - public void testLoginActionFailed() { - String actionName = "login"; - Map params = new HashMap(); - params.put("name","test"); - params.put("password","123456"); //密码和预设的不一致 - - View view = Struts.runAction(actionName,params); - - Assert.assertEquals("/jsp/showLogin.jsp", view.getJsp()); - Assert.assertEquals("login failed,please check your user/pwd", view.getParameters().get("message")); - } -} +package dataStruct.com.coderising.litestruts; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + + +public class StrutsTest { + + @Test + public void testLoginActionSuccess() { + + String actionName = "login"; + + Map params = new HashMap(); + params.put("name","test"); + params.put("password","1234"); + + + View view = Struts.runAction(actionName,params); + + Assert.assertEquals("/jsp/homepage.jsp", view.getJsp()); + Assert.assertEquals("login successful", view.getParameters().get("message")); + } + + @Test + public void testLoginActionFailed() { + String actionName = "login"; + Map params = new HashMap(); + params.put("name","test"); + params.put("password","123456"); //密码和预设的不一致 + + View view = Struts.runAction(actionName,params); + + Assert.assertEquals("/jsp/showLogin.jsp", view.getJsp()); + Assert.assertEquals("login failed,please check your user/pwd", view.getParameters().get("message")); + } +} diff --git a/group05/578505552/src/test/java/com/coding/basic/BinaryTreeNodeTest.java b/group05/578505552/src/test/java/dataStruct/com/coding/basic/BinaryTreeNodeTest.java similarity index 86% rename from group05/578505552/src/test/java/com/coding/basic/BinaryTreeNodeTest.java rename to group05/578505552/src/test/java/dataStruct/com/coding/basic/BinaryTreeNodeTest.java index d1e408554e..ee7ecd6e36 100644 --- a/group05/578505552/src/test/java/com/coding/basic/BinaryTreeNodeTest.java +++ b/group05/578505552/src/test/java/dataStruct/com/coding/basic/BinaryTreeNodeTest.java @@ -1,38 +1,36 @@ -package com.coding.basic; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * Created by songbao.yang on 2017/2/28. - * - */ -public class BinaryTreeNodeTest { - - private BinaryTreeNode node; - - @Before - public void setUp() throws Exception { - node = new BinaryTreeNode(); - node.setData(100); - node.setLeft(null); - node.setRight(null); - } - - @After - public void tearDown() throws Exception { - - } - - @Test - public void insert() throws Exception { - - for (int i = 0; i < 100; i++) { - int ele = (int)Math.floor(Math.random() * 200); - node.insert(ele); - } - } +package dataStruct.com.coding.basic; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Created by songbao.yang on 2017/2/28. + * + */ +public class BinaryTreeNodeTest { + + private BinaryTreeNode node; + + @Before + public void setUp() throws Exception { + node = new BinaryTreeNode(); + node.setData(100); + node.setLeft(null); + node.setRight(null); + } + + @After + public void tearDown() throws Exception { + + } + + @Test + public void insert() throws Exception { + + for (int i = 0; i < 100; i++) { + int ele = (int)Math.floor(Math.random() * 200); + node.insert(ele); + } + } } \ No newline at end of file diff --git a/group05/578505552/src/test/java/com/coding/basic/ListTest.java b/group05/578505552/src/test/java/dataStruct/com/coding/basic/ListTest.java similarity index 94% rename from group05/578505552/src/test/java/com/coding/basic/ListTest.java rename to group05/578505552/src/test/java/dataStruct/com/coding/basic/ListTest.java index 0c786de96c..9196c37f4c 100644 --- a/group05/578505552/src/test/java/com/coding/basic/ListTest.java +++ b/group05/578505552/src/test/java/dataStruct/com/coding/basic/ListTest.java @@ -1,100 +1,100 @@ -package com.coding.basic; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -/** - * Created by songbao.yang on 2017/2/21. - * - */ -public class ListTest { - - private List list; - - public static final int SIZE = 10000; - - @Before - public void setUp() throws Exception { - -// list = new ArrayList(); - list = new LinkedList(); - } - - @After - public void tearDown() throws Exception { - - } - - @Test - public void add() throws Exception { - - for (int i = 0; i < SIZE; i++) { - list.add(i); - Assert.assertEquals(i+1, list.size()); - } - } - - @Test - public void add1() throws Exception { - - add(); - for (int i = 0; i < 1000; i++) { - int oldSize = list.size(); - int randomIndex = (int)Math.floor(Math.random() * oldSize); - - list.add(randomIndex, randomIndex); - int newSize = list.size(); - - Assert.assertEquals(newSize, oldSize+1); - Assert.assertEquals(list.get(randomIndex), randomIndex); - } - } - - @Test - public void get() throws Exception { - - add(); - for (int i = 0; i < SIZE * 100; i++) { - int randomIndex = (int)Math.floor(Math.random() * list.size()); - if(randomIndex < 0 || randomIndex >= SIZE){ - System.out.println("illegal index: " + randomIndex); - throw new RuntimeException(); - } - int o = (Integer) list.get(randomIndex); - Assert.assertEquals(randomIndex, o); - } - } - - @Test - public void remove() throws Exception { - - add(); - for (int i = 0; i < SIZE; i++) { - int oldSize = list.size(); - int randomIndex = (int)Math.floor(Math.random() * oldSize); - list.remove(randomIndex); - int newSize = list.size(); - Assert.assertEquals(newSize, oldSize-1); - } - } - - @Test - public void size() throws Exception { - - } - - @Test - public void iterator() throws Exception { - add(); - Iterator iterator1 = list.iterator(); - int i = 0; - while (iterator1.hasNext()){ - Object next = iterator1.next(); - Assert.assertEquals(i, next); - i++; - } - } - +package dataStruct.com.coding.basic; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * Created by songbao.yang on 2017/2/21. + * + */ +public class ListTest { + + private List list; + + public static final int SIZE = 10000; + + @Before + public void setUp() throws Exception { + +// list = new ArrayList(); + list = new LinkedList(); + } + + @After + public void tearDown() throws Exception { + + } + + @Test + public void add() throws Exception { + + for (int i = 0; i < SIZE; i++) { + list.add(i); + Assert.assertEquals(i+1, list.size()); + } + } + + @Test + public void add1() throws Exception { + + add(); + for (int i = 0; i < 1000; i++) { + int oldSize = list.size(); + int randomIndex = (int)Math.floor(Math.random() * oldSize); + + list.add(randomIndex, randomIndex); + int newSize = list.size(); + + Assert.assertEquals(newSize, oldSize+1); + Assert.assertEquals(list.get(randomIndex), randomIndex); + } + } + + @Test + public void get() throws Exception { + + add(); + for (int i = 0; i < SIZE * 100; i++) { + int randomIndex = (int)Math.floor(Math.random() * list.size()); + if(randomIndex < 0 || randomIndex >= SIZE){ + System.out.println("illegal index: " + randomIndex); + throw new RuntimeException(); + } + int o = (Integer) list.get(randomIndex); + Assert.assertEquals(randomIndex, o); + } + } + + @Test + public void remove() throws Exception { + + add(); + for (int i = 0; i < SIZE; i++) { + int oldSize = list.size(); + int randomIndex = (int)Math.floor(Math.random() * oldSize); + list.remove(randomIndex); + int newSize = list.size(); + Assert.assertEquals(newSize, oldSize-1); + } + } + + @Test + public void size() throws Exception { + + } + + @Test + public void iterator() throws Exception { + add(); + Iterator iterator1 = list.iterator(); + int i = 0; + while (iterator1.hasNext()){ + Object next = iterator1.next(); + Assert.assertEquals(i, next); + i++; + } + } + } \ No newline at end of file diff --git a/group05/578505552/src/test/java/com/coding/basic/QueueTest.java b/group05/578505552/src/test/java/dataStruct/com/coding/basic/QueueTest.java similarity index 75% rename from group05/578505552/src/test/java/com/coding/basic/QueueTest.java rename to group05/578505552/src/test/java/dataStruct/com/coding/basic/QueueTest.java index 905054670d..856258a713 100644 --- a/group05/578505552/src/test/java/com/coding/basic/QueueTest.java +++ b/group05/578505552/src/test/java/dataStruct/com/coding/basic/QueueTest.java @@ -1,75 +1,75 @@ -package com.coding.basic; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * Created by songbao.yang on 2017/2/24. - */ -public class QueueTest { - - private static final int SIZE = 2000; - private Queue queue; - - @Before - public void setUp() throws Exception { - queue = new Queue(); - } - - @After - public void tearDown() throws Exception { - - } - - @Test - public void enQueue() throws Exception { - for (int i = 0; i < SIZE; i++) { - queue.enQueue(i); - Assert.assertEquals(i+1, queue.size()); - } - } - - @Test - public void deQueue1() throws Exception { - enQueue(); - - int i = 0; - int startSize = queue.size(); - while (!queue.isEmpty()) { - Assert.assertEquals(startSize - i, queue.size()); - Object o = queue.deQueue(); - Assert.assertEquals(SIZE - i - 1, queue.size()); - Assert.assertEquals(i, o); - i++; - } - } - - @Test - public void deQueue2() throws Exception { - enQueue(); - int startSize = queue.size(); - - for (int i = 0; i < startSize; i++) { - queue.deQueue(); - Assert.assertEquals(startSize - 1, queue.size()); - queue.enQueue(i+1000); - Assert.assertEquals(startSize, queue.size()); - } - - } - - @Test - public void isEmpty() throws Exception { - - } - - @Test - public void size() throws Exception { - - } - +package dataStruct.com.coding.basic; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Created by songbao.yang on 2017/2/24. + */ +public class QueueTest { + + private static final int SIZE = 2000; + private Queue queue; + + @Before + public void setUp() throws Exception { + queue = new Queue(); + } + + @After + public void tearDown() throws Exception { + + } + + @Test + public void enQueue() throws Exception { + for (int i = 0; i < SIZE; i++) { + queue.enQueue(i); + assertEquals(i+1, queue.size()); + } + } + + @Test + public void deQueue1() throws Exception { + enQueue(); + + int i = 0; + int startSize = queue.size(); + while (!queue.isEmpty()) { + assertEquals(startSize - i, queue.size()); + Object o = queue.deQueue(); + assertEquals(SIZE - i - 1, queue.size()); + Assert.assertEquals(i, o); + i++; + } + } + + @Test + public void deQueue2() throws Exception { + enQueue(); + int startSize = queue.size(); + + for (int i = 0; i < startSize; i++) { + queue.deQueue(); + assertEquals(startSize - 1, queue.size()); + queue.enQueue(i+1000); + assertEquals(startSize, queue.size()); + } + + } + + @Test + public void isEmpty() throws Exception { + + } + + @Test + public void size() throws Exception { + + } + } \ No newline at end of file diff --git a/group05/578505552/src/test/java/com/coding/basic/StackTest.java b/group05/578505552/src/test/java/dataStruct/com/coding/basic/StackTest.java similarity index 83% rename from group05/578505552/src/test/java/com/coding/basic/StackTest.java rename to group05/578505552/src/test/java/dataStruct/com/coding/basic/StackTest.java index b65d446c97..c58643c31a 100644 --- a/group05/578505552/src/test/java/com/coding/basic/StackTest.java +++ b/group05/578505552/src/test/java/dataStruct/com/coding/basic/StackTest.java @@ -1,65 +1,65 @@ -package com.coding.basic; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * Created by songbao.yang on 2017/2/24. - * - */ -public class StackTest { - - private Stack stack; - - public static final int SIZE = 100; - - @Before - public void setUp() throws Exception { - stack = new Stack(); - } - - @After - public void tearDown() throws Exception { - - } - - @Test - public void push() throws Exception { - for (int i = 0; i < SIZE; i++) { - stack.push(i); - Assert.assertEquals(i+1, stack.size()); - } - System.out.println(); - } - - @Test - public void pop() throws Exception { - push(); - int beginSize = stack.size(); - for (int i = 0; i < beginSize; i++) { - Object ele = stack.pop(); - Assert.assertEquals(beginSize-i-1, stack.size()); - Assert.assertEquals(beginSize-i-1, ele); - } - } - - @Test - public void peek() throws Exception { - - } - - @Test - public void isEmpty() throws Exception { - - } - - @Test - public void size() throws Exception { - - } - +package dataStruct.com.coding.basic; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Created by songbao.yang on 2017/2/24. + * + */ +public class StackTest { + + private Stack stack; + + public static final int SIZE = 100; + + @Before + public void setUp() throws Exception { + stack = new Stack(); + } + + @After + public void tearDown() throws Exception { + + } + + @Test + public void push() throws Exception { + for (int i = 0; i < SIZE; i++) { + stack.push(i); + assertEquals(i+1, stack.size()); + } + System.out.println(); + } + + @Test + public void pop() throws Exception { + push(); + int beginSize = stack.size(); + for (int i = 0; i < beginSize; i++) { + Object ele = stack.pop(); + assertEquals(beginSize-i-1, stack.size()); + Assert.assertEquals(beginSize-i-1, ele); + } + } + + @Test + public void peek() throws Exception { + + } + + @Test + public void isEmpty() throws Exception { + + } + + @Test + public void size() throws Exception { + + } + } \ No newline at end of file diff --git a/group05/578505552/src/test/java/dataStruct/com/coding/basic/linklist/LRUPageFrameTest.java b/group05/578505552/src/test/java/dataStruct/com/coding/basic/linklist/LRUPageFrameTest.java new file mode 100644 index 0000000000..ffeaa4a747 --- /dev/null +++ b/group05/578505552/src/test/java/dataStruct/com/coding/basic/linklist/LRUPageFrameTest.java @@ -0,0 +1,31 @@ +package dataStruct.com.coding.basic.linklist; + +import org.junit.Assert; + +import org.junit.Test; + + +public class LRUPageFrameTest { + + @Test + public void testAccess() { + LRUPageFrame frame = new LRUPageFrame(3); + frame.access(7); + frame.access(0); + frame.access(1); + Assert.assertEquals("1,0,7", frame.toString()); + frame.access(2); + Assert.assertEquals("2,1,0", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(3); + Assert.assertEquals("3,0,2", frame.toString()); + frame.access(0); + Assert.assertEquals("0,3,2", frame.toString()); + frame.access(4); + Assert.assertEquals("4,0,3", frame.toString()); + } + +} diff --git a/group05/578505552/src/test/java/miniJvm/com/coderising/jvm/loader/ClassFileloaderTest.java b/group05/578505552/src/test/java/miniJvm/com/coderising/jvm/loader/ClassFileloaderTest.java new file mode 100644 index 0000000000..97410772aa --- /dev/null +++ b/group05/578505552/src/test/java/miniJvm/com/coderising/jvm/loader/ClassFileloaderTest.java @@ -0,0 +1,70 @@ +package miniJvm.com.coderising.jvm.loader; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class ClassFileloaderTest { + + static String path1 = "D:\\project\\Learn\\coding2017\\group05\\578505552\\target\\classes"; + static String path2 = "C:\\temp"; + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testClassPath(){ + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + loader.addClassPath(path2); + String clzPath = loader.getClassPath(); + Assert.assertEquals(path1+";"+path2,clzPath); + } + + @Test + public void testClassFileLength() { + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "miniJvm.com.coderising.jvm.loader.EmployeeV1"; + byte[] byteCodes = loader.readBinaryCode(className); + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + Assert.assertEquals(1141, byteCodes.length); + + } + + + @Test + public void testMagicNumber(){ + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "miniJvm.com.coderising.jvm.loader.EmployeeV1"; + byte[] byteCodes = loader.readBinaryCode(className); + byte[] codes = new byte[]{byteCodes[0],byteCodes[1],byteCodes[2],byteCodes[3]}; + String acctualValue = this.byteToHexString(codes); + Assert.assertEquals("cafebabe", acctualValue); + } + + private String byteToHexString(byte[] codes ){ + StringBuffer buffer = new StringBuffer(); + for(int i=0;i Date: Sun, 9 Apr 2017 17:11:23 +0800 Subject: [PATCH 091/203] finish the constant pool loading --- .../src/main/java/jvm/ClassFileLoader.java | 19 ++-- .../main/java/jvm/classfile/AccessFlag.java | 9 ++ .../main/java/jvm/classfile/ClassFile.java | 12 +++ .../main/java/jvm/classfile/ClassIndex.java | 12 +++ .../main/java/jvm/classfile/ClassParser.java | 99 +++++++++++++++++++ .../main/java/jvm/classfile/ConstantPool.java | 14 +++ .../jvm/classfile/constant/item/Constant.java | 9 ++ .../constant/item/impl/ClassInfo.java | 24 +++++ .../constant/item/impl/CountConstant.java | 24 +++++ .../constant/item/impl/DoubleInfo.java | 30 ++++++ .../constant/item/impl/FieldRefInfo.java | 30 ++++++ .../constant/item/impl/FloatInfo.java | 24 +++++ .../constant/item/impl/IntegerInfo.java | 25 +++++ .../item/impl/InterfaceMethodRefInfo.java | 30 ++++++ .../constant/item/impl/InvokeDynamicInfo.java | 30 ++++++ .../constant/item/impl/LongInfo.java | 30 ++++++ .../constant/item/impl/MethodHandleInfo.java | 30 ++++++ .../constant/item/impl/MethodRefInfo.java | 30 ++++++ .../constant/item/impl/MethodTypeInfo.java | 24 +++++ .../constant/item/impl/NameAndTypeInfo.java | 30 ++++++ .../constant/item/impl/StringInfo.java | 24 +++++ .../constant/item/impl/Utf8Info.java | 30 ++++++ .../constant/parser/ConstantParser.java | 14 +++ .../parser/ConstantParserFactory.java | 62 ++++++++++++ .../constant/parser/impl/ClassInfoParser.java | 24 +++++ .../parser/impl/DoubleInfoParser.java | 28 ++++++ .../parser/impl/FieldRefInfoParser.java | 26 +++++ .../constant/parser/impl/FloatInfoParser.java | 24 +++++ .../parser/impl/IntegerInfoParser.java | 24 +++++ .../impl/InterfaceMethodRefInfoParser.java | 27 +++++ .../parser/impl/InvokeDynamicInfoParser.java | 26 +++++ .../constant/parser/impl/LongInfoParser.java | 29 ++++++ .../parser/impl/MethodHandleInfoParser.java | 26 +++++ .../parser/impl/MethodRefInfoParser.java | 27 +++++ .../parser/impl/MethodTypeInfoParser.java | 24 +++++ .../parser/impl/NameAndTypeInfoParser.java | 26 +++++ .../parser/impl/StringInfoParser.java | 24 +++++ .../constant/parser/impl/Utf8InfoParser.java | 32 ++++++ .../src/main/java/jvm/util/ByteUtils.java | 19 ++++ .../test/java/jvm/ClassFileLoaderTest.java | 14 ++- 40 files changed, 1056 insertions(+), 9 deletions(-) create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/AccessFlag.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/ClassFile.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/ClassIndex.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/ClassParser.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/ConstantPool.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/item/Constant.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/ClassInfo.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/CountConstant.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/DoubleInfo.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/FieldRefInfo.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/FloatInfo.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/IntegerInfo.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/InterfaceMethodRefInfo.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/InvokeDynamicInfo.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/LongInfo.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/MethodHandleInfo.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/MethodRefInfo.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/MethodTypeInfo.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/NameAndTypeInfo.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/StringInfo.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/Utf8Info.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/parser/ConstantParser.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/parser/ConstantParserFactory.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/ClassInfoParser.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/DoubleInfoParser.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/FieldRefInfoParser.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/FloatInfoParser.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/IntegerInfoParser.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/InterfaceMethodRefInfoParser.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/InvokeDynamicInfoParser.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/LongInfoParser.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/MethodHandleInfoParser.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/MethodRefInfoParser.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/MethodTypeInfoParser.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/NameAndTypeInfoParser.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/StringInfoParser.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/Utf8InfoParser.java create mode 100644 group01/895457260/code/src/main/java/jvm/util/ByteUtils.java diff --git a/group01/895457260/code/src/main/java/jvm/ClassFileLoader.java b/group01/895457260/code/src/main/java/jvm/ClassFileLoader.java index 53e401c119..28a4ff0b30 100644 --- a/group01/895457260/code/src/main/java/jvm/ClassFileLoader.java +++ b/group01/895457260/code/src/main/java/jvm/ClassFileLoader.java @@ -1,9 +1,12 @@ package jvm; +import jvm.classfile.ClassFile; +import jvm.classfile.ClassParser; import jvm.exception.ClassDuplicateException; import jvm.exception.ClassNotExistsException; import jvm.exception.ReadClassException; import jvm.util.ArrayUtils; +import jvm.util.ByteUtils; import java.io.*; import java.util.ArrayList; @@ -69,12 +72,16 @@ public String getClassPath() { } boolean checkMagicNumber(byte[] bytes) { - String magicNumber = "CAFEBABE"; - String str = ""; - int byteNum = 4; - for (int i = 0; i < byteNum; ++i) { - str += Integer.toHexString(Byte.toUnsignedInt(bytes[i])); + String magicNumber = "cafebabe"; + String str = ByteUtils.toHexString(bytes, 0, 4); + return magicNumber.equals(str.toLowerCase()); + } + + ClassFile load(String className) throws ReadClassException { + byte[] bytes = readBinaryCode(className); + if (checkMagicNumber(bytes)) { + return ClassParser.parse(bytes); } - return magicNumber.equals(str.toUpperCase()); + return null; } } diff --git a/group01/895457260/code/src/main/java/jvm/classfile/AccessFlag.java b/group01/895457260/code/src/main/java/jvm/classfile/AccessFlag.java new file mode 100644 index 0000000000..f9b14f9d6f --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/AccessFlag.java @@ -0,0 +1,9 @@ +package jvm.classfile; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class AccessFlag { + int flags; +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/ClassFile.java b/group01/895457260/code/src/main/java/jvm/classfile/ClassFile.java new file mode 100644 index 0000000000..f7b84d5185 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/ClassFile.java @@ -0,0 +1,12 @@ +package jvm.classfile; + + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class ClassFile { + ClassIndex classIndex; + AccessFlag accessFlag; + ConstantPool constantPool; +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/ClassIndex.java b/group01/895457260/code/src/main/java/jvm/classfile/ClassIndex.java new file mode 100644 index 0000000000..0078e10b10 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/ClassIndex.java @@ -0,0 +1,12 @@ +package jvm.classfile; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class ClassIndex { + int minorVersion; + int majorVersion; + int thisClass; + int superClass; +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/ClassParser.java b/group01/895457260/code/src/main/java/jvm/classfile/ClassParser.java new file mode 100644 index 0000000000..41365714a7 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/ClassParser.java @@ -0,0 +1,99 @@ +package jvm.classfile; + +import jvm.classfile.constant.item.Constant; +import jvm.classfile.constant.item.impl.CountConstant; +import jvm.classfile.constant.parser.ConstantParser; +import jvm.classfile.constant.parser.ConstantParserFactory; +import jvm.util.ByteUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class ClassParser { + private static class StartIndex { + int magicNumber = 0; + int minorVersion = 4; + int majorVersion = 6; + int constantPoolCount = 8; + Map constantIndexMap = new HashMap<>(); + int accessFlags; + int thisClass; + int superClass; + int interfacesCount; + Map interfaceIndexMap = new HashMap<>(); + int fieldsCount; + Map fieldIndexMap = new HashMap<>(); + int methodsCount; + Map methodIndexMap = new HashMap<>(); + int attributesCount; + Map attributeIndexMap = new HashMap<>(); + } + + private static StartIndex index = new StartIndex(); + + public static ClassFile parse(byte[] bytes) { + ClassFile classFile = new ClassFile(); + classFile.constantPool = parseConstantPool(bytes, index); + classFile.classIndex = parseClassIndex(bytes, index); + classFile.accessFlag = parseAccessFlag(bytes, index); + restore(classFile); + return classFile; + } + + private static void restore(ClassFile classFile) { + + } + + private static ConstantPool parseConstantPool(byte[] bytes, StartIndex index) { + final int COUNT_LEN = 2; + + ConstantPool constantPool = new ConstantPool(); + int currentIndex = index.constantPoolCount; + + index.constantIndexMap.put(1, currentIndex); + int count = ByteUtils.toInt(bytes, currentIndex, COUNT_LEN); + constantPool.constantMap.put(1, new CountConstant(count)); + currentIndex += COUNT_LEN; + + Map parserMap = new HashMap<>(); + for (int i = 2; i <= count; ++i) { + ConstantParser parser = ConstantParserFactory.get( + ByteUtils.toInt(bytes, currentIndex, ConstantParser.TAG_LEN), + bytes, currentIndex); + parserMap.put(i, parser); + index.constantIndexMap.put(i, currentIndex); + currentIndex += parser.length(); + } + for (int i = 2; i <= count; ++i) { + ConstantParser parser = parserMap.get(i); + int startIndex = index.constantIndexMap.get(i); + Constant constant = parser.parse(bytes, startIndex); + constantPool.constantMap.put(i, constant); + } + + index.accessFlags = currentIndex; + index.thisClass = index.accessFlags + 2; + index.superClass = index.thisClass + 2; + index.interfacesCount = index.superClass + 2; + return constantPool; + } + + private static ClassIndex parseClassIndex(byte[] bytes, StartIndex index) { + ClassIndex classIndex = new ClassIndex(); + classIndex.minorVersion = ByteUtils.toInt(bytes, index.minorVersion, 2); + classIndex.majorVersion = ByteUtils.toInt(bytes, index.majorVersion, 2); + classIndex.thisClass = ByteUtils.toInt(bytes, index.thisClass, 2); + classIndex.superClass = ByteUtils.toInt(bytes, index.superClass, 2); + return classIndex; + } + + private static AccessFlag parseAccessFlag(byte[] bytes, StartIndex index) { + AccessFlag accessFlag = new AccessFlag(); + accessFlag.flags = ByteUtils.toInt(bytes, index.accessFlags, 2); + return accessFlag; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/ConstantPool.java b/group01/895457260/code/src/main/java/jvm/classfile/ConstantPool.java new file mode 100644 index 0000000000..1595685533 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/ConstantPool.java @@ -0,0 +1,14 @@ +package jvm.classfile; + +import jvm.classfile.constant.item.Constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class ConstantPool { + Map constantMap = new HashMap<>(); +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/Constant.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/Constant.java new file mode 100644 index 0000000000..6c10479d4c --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/Constant.java @@ -0,0 +1,9 @@ +package jvm.classfile.constant.item; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public interface Constant { + int length(); +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/ClassInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/ClassInfo.java new file mode 100644 index 0000000000..0b5ad448f9 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/ClassInfo.java @@ -0,0 +1,24 @@ +package jvm.classfile.constant.item.impl; + +import jvm.classfile.constant.item.Constant; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class ClassInfo implements Constant { + private int nameIndex; + + public ClassInfo(int nameIndex) { + this.nameIndex = nameIndex; + } + + @Override + public int length() { + return 3; + } + + public int getNameIndex() { + return nameIndex; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/CountConstant.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/CountConstant.java new file mode 100644 index 0000000000..32ac16daf6 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/CountConstant.java @@ -0,0 +1,24 @@ +package jvm.classfile.constant.item.impl; + +import jvm.classfile.constant.item.Constant; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class CountConstant implements Constant { + private int count; + + public CountConstant(int count) { + this.count = count; + } + + @Override + public int length() { + return 2; + } + + public int getCount() { + return count; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/DoubleInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/DoubleInfo.java new file mode 100644 index 0000000000..873d416fbf --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/DoubleInfo.java @@ -0,0 +1,30 @@ +package jvm.classfile.constant.item.impl; + +import jvm.classfile.constant.item.Constant; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class DoubleInfo implements Constant { + private byte[] highBytes; + private byte[] lowBytes; + + public DoubleInfo(byte[] highBytes, byte[] lowBytes) { + this.highBytes = highBytes; + this.lowBytes = lowBytes; + } + + @Override + public int length() { + return 9; + } + + public byte[] getHighBytes() { + return highBytes; + } + + public byte[] getLowBytes() { + return lowBytes; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/FieldRefInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/FieldRefInfo.java new file mode 100644 index 0000000000..004f079e43 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/FieldRefInfo.java @@ -0,0 +1,30 @@ +package jvm.classfile.constant.item.impl; + +import jvm.classfile.constant.item.Constant; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class FieldRefInfo implements Constant { + private int classIndex; + private int nameAndTypeindex; + + public FieldRefInfo(int classIndex, int nameAndTypeIndex) { + this.classIndex = classIndex; + this.nameAndTypeindex = nameAndTypeIndex; + } + + @Override + public int length() { + return 5; + } + + public int getClassIndex() { + return classIndex; + } + + public int getNameAndTypeindex() { + return nameAndTypeindex; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/FloatInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/FloatInfo.java new file mode 100644 index 0000000000..57ac51a72b --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/FloatInfo.java @@ -0,0 +1,24 @@ +package jvm.classfile.constant.item.impl; + +import jvm.classfile.constant.item.Constant; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class FloatInfo implements Constant { + private byte[] bytes; + + public FloatInfo(byte[] bytes) { + this.bytes = bytes; + } + + @Override + public int length() { + return 5; + } + + public byte[] getBytes() { + return bytes; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/IntegerInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/IntegerInfo.java new file mode 100644 index 0000000000..0c544b0525 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/IntegerInfo.java @@ -0,0 +1,25 @@ +package jvm.classfile.constant.item.impl; + +import jvm.classfile.constant.item.Constant; +import jvm.util.ByteUtils; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class IntegerInfo implements Constant { + private byte[] bytes; + + public IntegerInfo(byte[] bytes) { + this.bytes = bytes; + } + + @Override + public int length() { + return 5; + } + + public byte[] getBytes() { + return bytes; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/InterfaceMethodRefInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/InterfaceMethodRefInfo.java new file mode 100644 index 0000000000..1cae4dc82e --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/InterfaceMethodRefInfo.java @@ -0,0 +1,30 @@ +package jvm.classfile.constant.item.impl; + +import jvm.classfile.constant.item.Constant; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class InterfaceMethodRefInfo implements Constant { + private int classIndex; + private int nameAndTypeindex; + + public InterfaceMethodRefInfo(int classIndex, int nameAndTypeIndex) { + this.classIndex = classIndex; + this.nameAndTypeindex = nameAndTypeIndex; + } + + @Override + public int length() { + return 5; + } + + public int getClassIndex() { + return classIndex; + } + + public int getNameAndTypeindex() { + return nameAndTypeindex; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/InvokeDynamicInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/InvokeDynamicInfo.java new file mode 100644 index 0000000000..66f98ed4c6 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/InvokeDynamicInfo.java @@ -0,0 +1,30 @@ +package jvm.classfile.constant.item.impl; + +import jvm.classfile.constant.item.Constant; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class InvokeDynamicInfo implements Constant { + private int bootstrapMethodAttrIndex; + private int nameAndTypeIndex; + + public InvokeDynamicInfo(int bootstrapMethodAttrIndex, int nameAndTypeIndex) { + this.bootstrapMethodAttrIndex = bootstrapMethodAttrIndex; + this.nameAndTypeIndex = nameAndTypeIndex; + } + + @Override + public int length() { + return 5; + } + + public int getBootstrapMethodAttrIndex() { + return bootstrapMethodAttrIndex; + } + + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/LongInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/LongInfo.java new file mode 100644 index 0000000000..a2ce9b9cbe --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/LongInfo.java @@ -0,0 +1,30 @@ +package jvm.classfile.constant.item.impl; + +import jvm.classfile.constant.item.Constant; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class LongInfo implements Constant { + private byte[] highBytes; + private byte[] lowBytes; + + public LongInfo(byte[] highBytes, byte[] lowBytes) { + this.highBytes = highBytes; + this.lowBytes = lowBytes; + } + + @Override + public int length() { + return 9; + } + + public byte[] getHighBytes() { + return highBytes; + } + + public byte[] getLowBytes() { + return lowBytes; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/MethodHandleInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/MethodHandleInfo.java new file mode 100644 index 0000000000..165682bf2e --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/MethodHandleInfo.java @@ -0,0 +1,30 @@ +package jvm.classfile.constant.item.impl; + +import jvm.classfile.constant.item.Constant; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class MethodHandleInfo implements Constant { + private int referenceKind; + private int referenceIndex; + + public MethodHandleInfo(int referenceKind, int referenceIndex) { + this.referenceKind = referenceKind; + this.referenceIndex = referenceIndex; + } + + @Override + public int length() { + return 4; + } + + public int getReferenceKind() { + return referenceKind; + } + + public int getReferenceIndex() { + return referenceIndex; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/MethodRefInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/MethodRefInfo.java new file mode 100644 index 0000000000..a311ec0821 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/MethodRefInfo.java @@ -0,0 +1,30 @@ +package jvm.classfile.constant.item.impl; + +import jvm.classfile.constant.item.Constant; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class MethodRefInfo implements Constant { + private int classIndex; + private int nameAndTypeindex; + + public MethodRefInfo(int classIndex, int nameAndTypeIndex) { + this.classIndex = classIndex; + this.nameAndTypeindex = nameAndTypeIndex; + } + + @Override + public int length() { + return 5; + } + + public int getClassIndex() { + return classIndex; + } + + public int getNameAndTypeindex() { + return nameAndTypeindex; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/MethodTypeInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/MethodTypeInfo.java new file mode 100644 index 0000000000..4a7e59ada4 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/MethodTypeInfo.java @@ -0,0 +1,24 @@ +package jvm.classfile.constant.item.impl; + +import jvm.classfile.constant.item.Constant; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class MethodTypeInfo implements Constant { + private int descriptorIndex; + + public MethodTypeInfo(int descriptorIndex) { + this.descriptorIndex = descriptorIndex; + } + + @Override + public int length() { + return 3; + } + + public int getDescriptorIndex() { + return descriptorIndex; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/NameAndTypeInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/NameAndTypeInfo.java new file mode 100644 index 0000000000..712b7761a3 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/NameAndTypeInfo.java @@ -0,0 +1,30 @@ +package jvm.classfile.constant.item.impl; + +import jvm.classfile.constant.item.Constant; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class NameAndTypeInfo implements Constant { + private int nameIndex; + private int descriptorIndex; + + public NameAndTypeInfo(int nameIndex, int descriptorIndex) { + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + } + + @Override + public int length() { + return 5; + } + + public int getNameIndex() { + return nameIndex; + } + + public int getDescriptorIndex() { + return descriptorIndex; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/StringInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/StringInfo.java new file mode 100644 index 0000000000..59a2a89336 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/StringInfo.java @@ -0,0 +1,24 @@ +package jvm.classfile.constant.item.impl; + +import jvm.classfile.constant.item.Constant; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class StringInfo implements Constant { + private int stringIndex; + + public StringInfo(int stringIndex) { + this.stringIndex = stringIndex; + } + + @Override + public int length() { + return 3; + } + + public int getStringIndex() { + return stringIndex; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/Utf8Info.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/Utf8Info.java new file mode 100644 index 0000000000..dbc983af45 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/Utf8Info.java @@ -0,0 +1,30 @@ +package jvm.classfile.constant.item.impl; + +import jvm.classfile.constant.item.Constant; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class Utf8Info implements Constant { + private int length; + private byte[] bytes; + + public Utf8Info(int length, byte[] bytes) { + this.length = length; + this.bytes = bytes; + } + + @Override + public int length() { + return 3 + length; + } + + public int getLength() { + return length; + } + + public byte[] getBytes() { + return bytes; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/ConstantParser.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/ConstantParser.java new file mode 100644 index 0000000000..cadf5104d3 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/ConstantParser.java @@ -0,0 +1,14 @@ +package jvm.classfile.constant.parser; + +import jvm.classfile.constant.item.Constant; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public interface ConstantParser { + int TAG_LEN = 1; + + Constant parse(byte[] bytes, int startIndex); + int length(); +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/ConstantParserFactory.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/ConstantParserFactory.java new file mode 100644 index 0000000000..95b4de56ff --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/ConstantParserFactory.java @@ -0,0 +1,62 @@ +package jvm.classfile.constant.parser; + +import jvm.classfile.constant.parser.impl.*; +import jvm.util.ByteUtils; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class ConstantParserFactory { + private static final int CONSTANT_CLASS = 7; + private static final int CONSTANT_FIELD_REF = 9; + private static final int CONSTANT_METHOD_REF = 10; + private static final int CONSTANT_INTERFACE_METHOD_REF = 11; + private static final int CONSTANT_STRING = 8; + private static final int CONSTANT_INTEGER = 3; + private static final int CONSTANT_FLOAT = 4; + private static final int CONSTANT_LONG = 5; + private static final int CONSTANT_DOUBLE = 6; + private static final int CONSTANT_NAME_AND_TYPE = 12; + private static final int CONSTANT_UTF8 = 1; + private static final int CONSTANT_METHOD_HANDLE = 15; + private static final int CONSTANT_METHOD_TYPE = 16; + private static final int CONSTANT_INVOKE_DYNAMIC = 18; + + public static ConstantParser get(int type, byte[] bytes, int startIndex) { + switch (type) { + case CONSTANT_CLASS: + return new ClassInfoParser(); + case CONSTANT_FIELD_REF: + return new FieldRefInfoParser(); + case CONSTANT_METHOD_REF: + return new MethodRefInfoParser(); + case CONSTANT_INTERFACE_METHOD_REF: + return new InterfaceMethodRefInfoParser(); + case CONSTANT_STRING: + return new StringInfoParser(); + case CONSTANT_INTEGER: + return new IntegerInfoParser(); + case CONSTANT_FLOAT: + return new FloatInfoParser(); + case CONSTANT_LONG: + return new LongInfoParser(); + case CONSTANT_DOUBLE: + return new DoubleInfoParser(); + case CONSTANT_NAME_AND_TYPE: + return new NameAndTypeInfoParser(); + case CONSTANT_UTF8: + startIndex += ConstantParser.TAG_LEN; + int length = ByteUtils.toInt(bytes, startIndex, 2); + return new Utf8InfoParser(length); + case CONSTANT_METHOD_HANDLE: + return new MethodHandleInfoParser(); + case CONSTANT_METHOD_TYPE: + return new MethodTypeInfoParser(); + case CONSTANT_INVOKE_DYNAMIC: + return new InvokeDynamicInfoParser(); + default: + return null; + } + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/ClassInfoParser.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/ClassInfoParser.java new file mode 100644 index 0000000000..2723ce61c4 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/ClassInfoParser.java @@ -0,0 +1,24 @@ +package jvm.classfile.constant.parser.impl; + +import jvm.classfile.constant.item.Constant; +import jvm.classfile.constant.item.impl.ClassInfo; +import jvm.classfile.constant.parser.ConstantParser; +import jvm.util.ByteUtils; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class ClassInfoParser implements ConstantParser { + @Override + public Constant parse(byte[] bytes, int startIndex) { + startIndex += TAG_LEN; + int nameIndex = ByteUtils.toInt(bytes, startIndex, 2); + return new ClassInfo(nameIndex); + } + + @Override + public int length() { + return 3; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/DoubleInfoParser.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/DoubleInfoParser.java new file mode 100644 index 0000000000..18a5bda426 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/DoubleInfoParser.java @@ -0,0 +1,28 @@ +package jvm.classfile.constant.parser.impl; + +import jvm.classfile.constant.item.Constant; +import jvm.classfile.constant.item.impl.DoubleInfo; +import jvm.classfile.constant.parser.ConstantParser; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class DoubleInfoParser implements ConstantParser { + @Override + public Constant parse(byte[] bytes, int startIndex) { + startIndex += TAG_LEN; + byte[] high = new byte[4]; + byte[] low = new byte[4]; + for (int i = 0; i < 4; ++i) { + high[i] = bytes[startIndex + i]; + low[i] = bytes[startIndex + i + 4]; + } + return new DoubleInfo(high, low); + } + + @Override + public int length() { + return 9; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/FieldRefInfoParser.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/FieldRefInfoParser.java new file mode 100644 index 0000000000..13c262d392 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/FieldRefInfoParser.java @@ -0,0 +1,26 @@ +package jvm.classfile.constant.parser.impl; + +import jvm.classfile.constant.item.Constant; +import jvm.classfile.constant.item.impl.FieldRefInfo; +import jvm.classfile.constant.parser.ConstantParser; +import jvm.util.ByteUtils; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class FieldRefInfoParser implements ConstantParser { + @Override + public Constant parse(byte[] bytes, int startIndex) { + startIndex += TAG_LEN; + int classIndex = ByteUtils.toInt(bytes, startIndex, 2); + startIndex += 2; + int nameAndTypeIndex = ByteUtils.toInt(bytes, startIndex, 2); + return new FieldRefInfo(classIndex, nameAndTypeIndex); + } + + @Override + public int length() { + return 5; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/FloatInfoParser.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/FloatInfoParser.java new file mode 100644 index 0000000000..b099cc4cfe --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/FloatInfoParser.java @@ -0,0 +1,24 @@ +package jvm.classfile.constant.parser.impl; + +import jvm.classfile.constant.item.Constant; +import jvm.classfile.constant.item.impl.FloatInfo; +import jvm.classfile.constant.parser.ConstantParser; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class FloatInfoParser implements ConstantParser { + @Override + public Constant parse(byte[] bytes, int startIndex) { + startIndex += TAG_LEN; + byte[] array = new byte[4]; + System.arraycopy(bytes, startIndex, array, 0, 4); + return new FloatInfo(array); + } + + @Override + public int length() { + return 5; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/IntegerInfoParser.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/IntegerInfoParser.java new file mode 100644 index 0000000000..9de454a3f8 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/IntegerInfoParser.java @@ -0,0 +1,24 @@ +package jvm.classfile.constant.parser.impl; + +import jvm.classfile.constant.item.Constant; +import jvm.classfile.constant.item.impl.IntegerInfo; +import jvm.classfile.constant.parser.ConstantParser; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class IntegerInfoParser implements ConstantParser { + @Override + public Constant parse(byte[] bytes, int startIndex) { + startIndex += TAG_LEN; + byte[] array = new byte[4]; + System.arraycopy(bytes, startIndex, array, 0, 4); + return new IntegerInfo(array); + } + + @Override + public int length() { + return 5; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/InterfaceMethodRefInfoParser.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/InterfaceMethodRefInfoParser.java new file mode 100644 index 0000000000..cc379cc7e6 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/InterfaceMethodRefInfoParser.java @@ -0,0 +1,27 @@ +package jvm.classfile.constant.parser.impl; + +import jvm.classfile.constant.item.Constant; +import jvm.classfile.constant.item.impl.FieldRefInfo; +import jvm.classfile.constant.item.impl.InterfaceMethodRefInfo; +import jvm.classfile.constant.parser.ConstantParser; +import jvm.util.ByteUtils; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class InterfaceMethodRefInfoParser implements ConstantParser { + @Override + public Constant parse(byte[] bytes, int startIndex) { + startIndex += TAG_LEN; + int classIndex = ByteUtils.toInt(bytes, startIndex, 2); + startIndex += 2; + int nameAndTypeIndex = ByteUtils.toInt(bytes, startIndex, 2); + return new InterfaceMethodRefInfo(classIndex, nameAndTypeIndex); + } + + @Override + public int length() { + return 5; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/InvokeDynamicInfoParser.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/InvokeDynamicInfoParser.java new file mode 100644 index 0000000000..f77afe553b --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/InvokeDynamicInfoParser.java @@ -0,0 +1,26 @@ +package jvm.classfile.constant.parser.impl; + +import jvm.classfile.constant.item.Constant; +import jvm.classfile.constant.item.impl.InvokeDynamicInfo; +import jvm.classfile.constant.parser.ConstantParser; +import jvm.util.ByteUtils; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class InvokeDynamicInfoParser implements ConstantParser { + @Override + public Constant parse(byte[] bytes, int startIndex) { + startIndex += TAG_LEN; + int bootstrapMethodAttrIndex = ByteUtils.toInt(bytes, startIndex, 2); + startIndex += 2; + int nameAndTypeIndex = ByteUtils.toInt(bytes, startIndex, 2); + return new InvokeDynamicInfo(bootstrapMethodAttrIndex, nameAndTypeIndex); + } + + @Override + public int length() { + return 5; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/LongInfoParser.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/LongInfoParser.java new file mode 100644 index 0000000000..aa963a4dc0 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/LongInfoParser.java @@ -0,0 +1,29 @@ +package jvm.classfile.constant.parser.impl; + +import jvm.classfile.constant.item.Constant; +import jvm.classfile.constant.item.impl.DoubleInfo; +import jvm.classfile.constant.item.impl.LongInfo; +import jvm.classfile.constant.parser.ConstantParser; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class LongInfoParser implements ConstantParser { + @Override + public Constant parse(byte[] bytes, int startIndex) { + startIndex += TAG_LEN; + byte[] high = new byte[4]; + byte[] low = new byte[4]; + for (int i = 0; i < 4; ++i) { + high[i] = bytes[startIndex + i]; + low[i] = bytes[startIndex + i + 4]; + } + return new LongInfo(high, low); + } + + @Override + public int length() { + return 9; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/MethodHandleInfoParser.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/MethodHandleInfoParser.java new file mode 100644 index 0000000000..9e41aceec5 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/MethodHandleInfoParser.java @@ -0,0 +1,26 @@ +package jvm.classfile.constant.parser.impl; + +import jvm.classfile.constant.item.Constant; +import jvm.classfile.constant.item.impl.MethodHandleInfo; +import jvm.classfile.constant.parser.ConstantParser; +import jvm.util.ByteUtils; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class MethodHandleInfoParser implements ConstantParser { + @Override + public Constant parse(byte[] bytes, int startIndex) { + startIndex += TAG_LEN; + int referenceKind = ByteUtils.toInt(bytes, startIndex, 1); + startIndex += 1; + int referenceIndex = ByteUtils.toInt(bytes, startIndex, 2); + return new MethodHandleInfo(referenceKind, referenceIndex); + } + + @Override + public int length() { + return 4; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/MethodRefInfoParser.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/MethodRefInfoParser.java new file mode 100644 index 0000000000..ade7f94940 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/MethodRefInfoParser.java @@ -0,0 +1,27 @@ +package jvm.classfile.constant.parser.impl; + +import jvm.classfile.constant.item.Constant; +import jvm.classfile.constant.item.impl.FieldRefInfo; +import jvm.classfile.constant.item.impl.MethodRefInfo; +import jvm.classfile.constant.parser.ConstantParser; +import jvm.util.ByteUtils; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class MethodRefInfoParser implements ConstantParser { + @Override + public Constant parse(byte[] bytes, int startIndex) { + startIndex += TAG_LEN; + int classIndex = ByteUtils.toInt(bytes, startIndex, 2); + startIndex += 2; + int nameAndTypeIndex = ByteUtils.toInt(bytes, startIndex, 2); + return new MethodRefInfo(classIndex, nameAndTypeIndex); + } + + @Override + public int length() { + return 5; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/MethodTypeInfoParser.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/MethodTypeInfoParser.java new file mode 100644 index 0000000000..d4af9c86e2 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/MethodTypeInfoParser.java @@ -0,0 +1,24 @@ +package jvm.classfile.constant.parser.impl; + +import jvm.classfile.constant.item.Constant; +import jvm.classfile.constant.item.impl.MethodTypeInfo; +import jvm.classfile.constant.parser.ConstantParser; +import jvm.util.ByteUtils; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class MethodTypeInfoParser implements ConstantParser { + @Override + public Constant parse(byte[] bytes, int startIndex) { + startIndex += TAG_LEN; + int descriptorIndex = ByteUtils.toInt(bytes, startIndex, 2); + return new MethodTypeInfo(descriptorIndex); + } + + @Override + public int length() { + return 3; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/NameAndTypeInfoParser.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/NameAndTypeInfoParser.java new file mode 100644 index 0000000000..47ab719db8 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/NameAndTypeInfoParser.java @@ -0,0 +1,26 @@ +package jvm.classfile.constant.parser.impl; + +import jvm.classfile.constant.item.Constant; +import jvm.classfile.constant.item.impl.NameAndTypeInfo; +import jvm.classfile.constant.parser.ConstantParser; +import jvm.util.ByteUtils; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class NameAndTypeInfoParser implements ConstantParser { + @Override + public Constant parse(byte[] bytes, int startIndex) { + startIndex += TAG_LEN; + int nameIndex = ByteUtils.toInt(bytes, startIndex, 2); + startIndex += 2; + int descriptorIndex = ByteUtils.toInt(bytes, startIndex, 2); + return new NameAndTypeInfo(nameIndex, descriptorIndex); + } + + @Override + public int length() { + return 5; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/StringInfoParser.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/StringInfoParser.java new file mode 100644 index 0000000000..508beca537 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/StringInfoParser.java @@ -0,0 +1,24 @@ +package jvm.classfile.constant.parser.impl; + +import jvm.classfile.constant.item.Constant; +import jvm.classfile.constant.item.impl.StringInfo; +import jvm.classfile.constant.parser.ConstantParser; +import jvm.util.ByteUtils; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class StringInfoParser implements ConstantParser { + @Override + public Constant parse(byte[] bytes, int startIndex) { + startIndex += TAG_LEN; + int stringIndex = ByteUtils.toInt(bytes, startIndex, 2); + return new StringInfo(stringIndex); + } + + @Override + public int length() { + return 3; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/Utf8InfoParser.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/Utf8InfoParser.java new file mode 100644 index 0000000000..5853db1817 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/Utf8InfoParser.java @@ -0,0 +1,32 @@ +package jvm.classfile.constant.parser.impl; + +import jvm.classfile.constant.item.Constant; +import jvm.classfile.constant.item.impl.Utf8Info; +import jvm.classfile.constant.parser.ConstantParser; +import jvm.util.ByteUtils; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class Utf8InfoParser implements ConstantParser { + private int length; + + public Utf8InfoParser(int length) { + this.length = length; + } + + @Override + public Constant parse(byte[] bytes, int startIndex) { + startIndex += TAG_LEN; + startIndex += 2; + byte[] array = new byte[length]; + System.arraycopy(bytes, startIndex, array, 0, length); + return new Utf8Info(length, array); + } + + @Override + public int length() { + return 3 + length; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/util/ByteUtils.java b/group01/895457260/code/src/main/java/jvm/util/ByteUtils.java new file mode 100644 index 0000000000..3a0e1fc0b6 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/util/ByteUtils.java @@ -0,0 +1,19 @@ +package jvm.util; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public class ByteUtils { + public static String toHexString(byte[] bytes, int off, int len) { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < len; ++i) { + builder.append(Integer.toHexString(Byte.toUnsignedInt(bytes[off + i]))); + } + return builder.toString(); + } + + public static int toInt(byte[] bytes, int off, int len) { + return Integer.parseInt(toHexString(bytes, off, len), 16); + } +} diff --git a/group01/895457260/code/src/test/java/jvm/ClassFileLoaderTest.java b/group01/895457260/code/src/test/java/jvm/ClassFileLoaderTest.java index ac48c1a4d6..f30ee57de9 100644 --- a/group01/895457260/code/src/test/java/jvm/ClassFileLoaderTest.java +++ b/group01/895457260/code/src/test/java/jvm/ClassFileLoaderTest.java @@ -1,5 +1,6 @@ package jvm; +import jvm.classfile.ClassFile; import jvm.exception.ReadClassException; import org.junit.After; import org.junit.Assert; @@ -41,9 +42,16 @@ public void testMagicNumber() throws ReadClassException { String className = "jvm.EmployeeV1"; byte[] byteCodes = loader.readBinaryCode(className); byte[] codes = new byte[] {byteCodes[0], byteCodes[1], byteCodes[2], byteCodes[3]}; - - String actualValue = this.byteToHexString(codes); - Assert.assertEquals("cafebabe", actualValue); + + boolean check = loader.checkMagicNumber(codes); + Assert.assertTrue(check); + } + + @Test + public void testLoad() throws ReadClassException { + String className = "jvm.EmployeeV1"; + ClassFile classFile = loader.load(className); + System.out.println("done"); } private String byteToHexString(byte[] codes) { From 680b56b3bc51ea6de6453d81422738e22026cef1 Mon Sep 17 00:00:00 2001 From: Patrick Date: Sun, 9 Apr 2017 18:47:56 +0800 Subject: [PATCH 092/203] =?UTF-8?q?stackutil=E5=8F=8Ajvm=E8=AF=BB=E5=8F=96?= =?UTF-8?q?=E5=B8=B8=E9=87=8F=E6=B1=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group24/121111914/.classpath | 10 ++ group24/121111914/.project | 17 ++ .../coding2017/basic/{ => stack}/Stack.java | 74 +++++---- .../coding2017/basic/stack/StackUtil.java | 133 ++++++++++++++++ .../coding2017/basic/test/StackTest.java | 2 +- .../coding2017/basic/test/StackUtilTest.java | 73 +++++++++ .../coding2017/minijvm/clz/AccessFlag.java | 37 +++++ .../coding2017/minijvm/clz/ClassFile.java | 75 +++++++++ .../coding2017/minijvm/clz/ClassIndex.java | 21 +++ .../minijvm/constant/ClassInfo.java | 26 +++ .../minijvm/constant/ConstantInfo.java | 29 ++++ .../minijvm/constant/ConstantPool.java | 29 ++++ .../minijvm/constant/FieldRefInfo.java | 54 +++++++ .../minijvm/constant/MethodRefInfo.java | 55 +++++++ .../minijvm/constant/NameAndTypeInfo.java | 45 ++++++ .../minijvm/constant/NullConstantInfo.java | 13 ++ .../minijvm/constant/StringInfo.java | 26 +++ .../coding2017/minijvm/constant/UTF8Info.java | 32 ++++ .../minijvm/loader/ByteCodeIterator.java | 28 ++++ .../minijvm/loader/ClassFileLoader.java | 141 ++++++++++++---- .../minijvm/loader/ClassFileLoader1.java | 125 +++++++++++++++ .../minijvm/loader/ClassFileParser.java | 149 +++++++++++++++++ .../minijvm/test/ClassFileloaderTest.java | 150 +++++++++++++++--- .../ipk2015/coding2017/minijvm/util/Util.java | 26 +++ 24 files changed, 1283 insertions(+), 87 deletions(-) create mode 100644 group24/121111914/.classpath create mode 100644 group24/121111914/.project rename group24/121111914/src/com/github/ipk2015/coding2017/basic/{ => stack}/Stack.java (60%) create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/basic/stack/StackUtil.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/basic/test/StackUtilTest.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/clz/AccessFlag.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/clz/ClassFile.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/clz/ClassIndex.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/ClassInfo.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/ConstantInfo.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/ConstantPool.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/FieldRefInfo.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/MethodRefInfo.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/NameAndTypeInfo.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/NullConstantInfo.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/StringInfo.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/UTF8Info.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ByteCodeIterator.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ClassFileLoader1.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ClassFileParser.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/util/Util.java diff --git a/group24/121111914/.classpath b/group24/121111914/.classpath new file mode 100644 index 0000000000..3e9442280c --- /dev/null +++ b/group24/121111914/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/group24/121111914/.project b/group24/121111914/.project new file mode 100644 index 0000000000..5fb6378a67 --- /dev/null +++ b/group24/121111914/.project @@ -0,0 +1,17 @@ + + + JavaImp2017 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/basic/Stack.java b/group24/121111914/src/com/github/ipk2015/coding2017/basic/stack/Stack.java similarity index 60% rename from group24/121111914/src/com/github/ipk2015/coding2017/basic/Stack.java rename to group24/121111914/src/com/github/ipk2015/coding2017/basic/stack/Stack.java index 4dae60e12b..ddb9b62dda 100644 --- a/group24/121111914/src/com/github/ipk2015/coding2017/basic/Stack.java +++ b/group24/121111914/src/com/github/ipk2015/coding2017/basic/stack/Stack.java @@ -1,32 +1,42 @@ -package com.github.ipk2015.coding2017.basic; - -import java.util.EmptyStackException; - -public class Stack { - private ArrayList elementData = new ArrayList(); - - public void push(Object o){ - elementData.add(o); - } - - public Object pop(){ - if(isEmpty()){ - throw new EmptyStackException(); - } - Object data=elementData.remove(size()-1); - return data; - } - - public Object peek(){ - if(isEmpty()){ - throw new EmptyStackException(); - } - return elementData.get(size()-1); - } - public boolean isEmpty(){ - return size()==0; - } - public int size(){ - return elementData.size(); - } -} +package com.github.ipk2015.coding2017.basic.stack; + +import java.util.EmptyStackException; + +import com.github.ipk2015.coding2017.basic.ArrayList; + +public class Stack { + private ArrayList elementData = new ArrayList(); + + public void push(Object o){ + elementData.add(o); + } + + public Object pop(){ + if(isEmpty()){ + throw new EmptyStackException(); + } + Object data=elementData.remove(size()-1); + return data; + } + + public Object peek(){ + if(isEmpty()){ + throw new EmptyStackException(); + } + return elementData.get(size()-1); + } + public boolean isEmpty(){ + return size()==0; + } + public int size(){ + return elementData.size(); + } + public String toString(){ + StringBuffer buffer=new StringBuffer(); + int size=elementData.size(); + for(int i=0;is.size()){ + throw new RuntimeException("len超出范围"); + } + Stack tempStack=new Stack(); + for(int i=0;i0){ + stack.push(flag); + }else if(flag<0){ + if(stack.size()==0){ + return false; + } + Integer peek = (Integer)stack.peek(); + if(peek+flag==0){ + stack.pop(); + }else{ + return false; + } + } + } + if(stack.size()>0){ + return false; + } + return true; + } + private static int switchChar(char c){ + int result=0; + switch(c){ + case '(': + result=1; + break; + case ')': + result=-1; + break; + case '[': + result=2; + break; + case ']': + result=-2; + break; + case '{': + result=3; + break; + case '}': + result=-3; + break; + default: + break; + } + return result; + } + +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/basic/test/StackTest.java b/group24/121111914/src/com/github/ipk2015/coding2017/basic/test/StackTest.java index 7cc10b77df..dbb28a9df2 100644 --- a/group24/121111914/src/com/github/ipk2015/coding2017/basic/test/StackTest.java +++ b/group24/121111914/src/com/github/ipk2015/coding2017/basic/test/StackTest.java @@ -5,7 +5,7 @@ import org.junit.Before; import org.junit.Test; -import com.github.ipk2015.coding2017.basic.Stack; +import com.github.ipk2015.coding2017.basic.stack.Stack; public class StackTest { Stack stack; diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/basic/test/StackUtilTest.java b/group24/121111914/src/com/github/ipk2015/coding2017/basic/test/StackUtilTest.java new file mode 100644 index 0000000000..e1a2b7e42c --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/basic/test/StackUtilTest.java @@ -0,0 +1,73 @@ +package com.github.ipk2015.coding2017.basic.test; + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; + +import com.github.ipk2015.coding2017.basic.stack.Stack; +import com.github.ipk2015.coding2017.basic.stack.StackUtil; + +public class StackUtilTest { + Stack stack=null; + @Before + public void setUp() throws Exception { + stack=new Stack(); + } + + @Test + public void testReverse() { + stack.push(1); + stack.push(2); + stack.push(3); + stack.push(4); + StackUtil.reverse(stack); + assertEquals("4,3,2,1,", stack.toString()); + } + + @Test + public void testRemove() { + stack.push(1); + stack.push(2); + stack.push(3); + stack.push(4); + StackUtil.remove(stack, 2); + assertEquals("1,3,4,", stack.toString()); + StackUtil.remove(stack, 5); + assertEquals("1,3,4,", stack.toString()); + } + + @Test + public void testGetTop() { + stack.push(1); + stack.push(2); + stack.push(3); + stack.push(4); + Object[] array=StackUtil.getTop(stack, 3); + assertEquals("1,2,3,4,", stack.toString()); + StringBuffer buffer=new StringBuffer(); + for(int i=0;i constantInfos = new ArrayList(); + + + public ConstantPool(){ + + } + public void addConstantInfo(ConstantInfo info){ + + this.constantInfos.add(info); + + } + + public ConstantInfo getConstantInfo(int index){ + return this.constantInfos.get(index); + } + public String getUTF8String(int index){ + return ((UTF8Info)this.constantInfos.get(index)).getValue(); + } + public Object getSize() { + return this.constantInfos.size() -1; + } +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/FieldRefInfo.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..b74fb427ba --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/FieldRefInfo.java @@ -0,0 +1,54 @@ +package com.github.ipk2015.coding2017.minijvm.constant; + +public class FieldRefInfo extends ConstantInfo{ + private int type = ConstantInfo.FIELD_INFO; + private int classInfoIndex; + private int nameAndTypeIndex; + + public FieldRefInfo(ConstantPool pool) { + super(pool); + } + public int getType() { + return type; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String toString(){ + + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + + return getClassName() +" : "+ typeInfo.getName() + ":" + typeInfo.getTypeInfo() +"]"; + } + + public String getClassName(){ + + ClassInfo classInfo = (ClassInfo) this.getConstantInfo(this.getClassInfoIndex()); + + UTF8Info utf8Info = (UTF8Info)this.getConstantInfo(classInfo.getUtf8Index()); + + return utf8Info.getValue(); + + } + + public String getFieldName(){ + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getFieldType(){ + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/MethodRefInfo.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..cc5352db6e --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/MethodRefInfo.java @@ -0,0 +1,55 @@ +package com.github.ipk2015.coding2017.minijvm.constant; + +public class MethodRefInfo extends ConstantInfo { + + private int type = ConstantInfo.METHOD_INFO; + + private int classInfoIndex; + private int nameAndTypeIndex; + + public MethodRefInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String toString(){ + + return getClassName() +" : "+ this.getMethodName() + " : " + this.getParamAndReturnType() ; + } + public String getClassName(){ + ConstantPool pool = this.getConstantPool(); + ClassInfo clzInfo = (ClassInfo)pool.getConstantInfo(this.getClassInfoIndex()); + return clzInfo.getClassName(); + } + + public String getMethodName(){ + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo)pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getParamAndReturnType(){ + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo)pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } + + + +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/NameAndTypeInfo.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..d1cd005111 --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/NameAndTypeInfo.java @@ -0,0 +1,45 @@ +package com.github.ipk2015.coding2017.minijvm.constant; + +public class NameAndTypeInfo extends ConstantInfo{ + public int type = ConstantInfo.NAME_AND_TYPE_INFO; + + private int index1; + private int index2; + + public NameAndTypeInfo(ConstantPool pool) { + super(pool); + } + + public int getIndex1() { + return index1; + } + public void setIndex1(int index1) { + this.index1 = index1; + } + public int getIndex2() { + return index2; + } + public void setIndex2(int index2) { + this.index2 = index2; + } + public int getType() { + return type; + } + + + public String getName(){ + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info1 = (UTF8Info)pool.getConstantInfo(index1); + return utf8Info1.getValue(); + } + + public String getTypeInfo(){ + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info2 = (UTF8Info)pool.getConstantInfo(index2); + return utf8Info2.getValue(); + } + + public String toString(){ + return "(" + getName() + "," + getTypeInfo()+")"; + } +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/NullConstantInfo.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..38eef91f32 --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/NullConstantInfo.java @@ -0,0 +1,13 @@ +package com.github.ipk2015.coding2017.minijvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo(){ + + } + @Override + public int getType() { + return -1; + } + +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/StringInfo.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/StringInfo.java new file mode 100644 index 0000000000..8f23231e72 --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/StringInfo.java @@ -0,0 +1,26 @@ +package com.github.ipk2015.coding2017.minijvm.constant; + +public class StringInfo extends ConstantInfo{ + private int type = ConstantInfo.STRING_INFO; + private int index; + public StringInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } + + + public String toString(){ + return this.getConstantPool().getUTF8String(index); + } + +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/UTF8Info.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/UTF8Info.java new file mode 100644 index 0000000000..d94a267bbc --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/UTF8Info.java @@ -0,0 +1,32 @@ +package com.github.ipk2015.coding2017.minijvm.constant; + +public class UTF8Info extends ConstantInfo{ + private int type = ConstantInfo.UTF8_INFO; + private int length ; + private String value; + public UTF8Info(ConstantPool pool) { + super(pool); + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getType() { + return type; + } + @Override + public String toString() { + return "UTF8Info [type=" + type + ", length=" + length + ", value=" + value +")]"; + } + public String getValue() { + return value; + } + public void setValue(String value) { + this.value = value; + } + + + +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ByteCodeIterator.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..85e970c64a --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ByteCodeIterator.java @@ -0,0 +1,28 @@ +package com.github.ipk2015.coding2017.minijvm.loader; + +import java.util.Arrays; + +import com.github.ipk2015.coding2017.minijvm.util.Util; + +public class ByteCodeIterator { + private byte[] byteArray; + int pos=0; + + public ByteCodeIterator(byte[] codes){ + this.byteArray=codes; + } + + public int nextUNToInt(int n){ + return Util.byteToInt(nextUNToArray(n)); + } + + public String nextUNToHexString(int n){ + return Util.byteToHexString(nextUNToArray(n)); + } + + public byte[] nextUNToArray(int n){ + byte[] bytes=Arrays.copyOfRange(byteArray, pos, pos+n); + pos=pos+n; + return bytes; + } +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ClassFileLoader.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ClassFileLoader.java index ab7f54a796..2f854174dd 100644 --- a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ClassFileLoader.java +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ClassFileLoader.java @@ -6,67 +6,138 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; + +import com.github.ipk2015.coding2017.minijvm.clz.ClassFile; + + + + + public class ClassFileLoader { private List clzPaths = new ArrayList(); - public byte[] readBinaryCode(String className) throws IOException { - className=getCompleteClassName(className); - File file=null; - for(String path:clzPaths){ - file=new File(path+"\\"+className); - if(file.exists()){ - break; - } + public byte[] readBinaryCode(String className) { + + className = className.replace('.', File.separatorChar) +".class"; + + for(String path : this.clzPaths){ + + String clzFileName = path + File.separatorChar + className; + byte[] codes = loadClassFile(clzFileName); + if(codes != null){ + return codes; + } } - if(null==file){ - throw new FileNotFoundException(className); - } - ByteArrayOutputStream bos=new ByteArrayOutputStream((int)file.length()); - BufferedInputStream in=new BufferedInputStream(new FileInputStream(file)); - int size=1024; - byte[] buffer=new byte[size]; - int length=0; - while((length=in.read(buffer, 0, size))!=-1){ - bos.write(buffer,0,length); + + return null; + + + + } + + private byte[] loadClassFile(String clzFileName) { + + File f = new File(clzFileName); + + try { + + return IOUtils.toByteArray(new FileInputStream(f)); + + } catch (IOException e) { + e.printStackTrace(); + return null; } - return bos.toByteArray(); } + public void addClassPath(String path) { - clzPaths.add(path); + if(this.clzPaths.contains(path)){ + return; + } + + this.clzPaths.add(path); + } public String getClassPath(){ - StringBuffer buffer=new StringBuffer(); - for(String path:clzPaths){ - buffer.append(path+";"); - } - buffer.deleteCharAt(buffer.length()-1); - return buffer.toString(); + return StringUtils.join(this.clzPaths,";"); } - private String getCompleteClassName(String name){ - if(!name.endsWith(".class")){ - name=name+".class"; + public ClassFile loadClass(String className) { + byte[] codes = this.readBinaryCode(className); + ClassFileParser parser = new ClassFileParser(); + return parser.parse(codes); + } + + + + // ------------------------------backup------------------------ + public String getClassPath_V1(){ + + StringBuffer buffer = new StringBuffer(); + for(int i=0;i-1){ - name=name.substring(pointPos+1); + return buffer.toString(); + } + + private byte[] loadClassFile_V1(String clzFileName) { + + BufferedInputStream bis = null; + + try { + + File f = new File(clzFileName); + + + bis = new BufferedInputStream(new FileInputStream(f)); + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + + byte[] buffer = new byte[1024]; + int length = -1; + + while((length = bis.read(buffer)) != -1){ + bos.write(buffer, 0, length); + } + + byte [] codes = bos.toByteArray(); + + return codes; + + } catch(IOException e){ + e.printStackTrace(); + + } finally{ + if(bis != null){ + try { + bis.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } } - return name; + return null; + } + -} +} \ No newline at end of file diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ClassFileLoader1.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ClassFileLoader1.java new file mode 100644 index 0000000000..6f5e68c4a3 --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ClassFileLoader1.java @@ -0,0 +1,125 @@ +package com.github.ipk2015.coding2017.minijvm.loader; + + + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + + + +public class ClassFileLoader1 { + + private List clzPaths = new ArrayList(); + + public byte[] readBinaryCode(String className) throws IOException { + className=getCompleteClassName(className); + File file=null; + for(String path:clzPaths){ + file=new File(path+"\\"+className); + if(file.exists()){ + break; + } + } + if(null==file){ + throw new FileNotFoundException(className); + } + ByteArrayOutputStream bos=new ByteArrayOutputStream((int)file.length()); + BufferedInputStream in=new BufferedInputStream(new FileInputStream(file)); + int size=1024; + byte[] buffer=new byte[size]; + int length=0; + while((length=in.read(buffer, 0, size))!=-1){ + bos.write(buffer,0,length); + } + return bos.toByteArray(); + } + + + public void addClassPath(String path) { + clzPaths.add(path); + } + + + + public String getClassPath(){ + StringBuffer buffer=new StringBuffer(); + for(String path:clzPaths){ + buffer.append(path+";"); + } + buffer.deleteCharAt(buffer.length()-1); + return buffer.toString(); + } + + private String getCompleteClassName(String name){ + if(!name.endsWith(".class")){ + name=name+".class"; + } + int pointPos=name.lastIndexOf(".", name.length()-7); + if(pointPos>-1){ + name=name.substring(pointPos+1); + } + return name; + } + // ------------------------------backup------------------------ + public String getClassPath_V1(){ + + StringBuffer buffer = new StringBuffer(); + for(int i=0;i", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(10); + Assert.assertEquals("(Ljava/lang/String;I)V", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(11); + Assert.assertEquals("Code", utf8Info.getValue()); + } + + { + MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(12); + Assert.assertEquals(3, methodRef.getClassInfoIndex()); + Assert.assertEquals(13, methodRef.getNameAndTypeIndex()); + } + + { + NameAndTypeInfo nameAndType = (NameAndTypeInfo) pool.getConstantInfo(13); + Assert.assertEquals(9, nameAndType.getIndex1()); + Assert.assertEquals(14, nameAndType.getIndex2()); + } + //抽查几个吧 + { + MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(45); + Assert.assertEquals(1, methodRef.getClassInfoIndex()); + Assert.assertEquals(46, methodRef.getNameAndTypeIndex()); + } + + { + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(53); + Assert.assertEquals("EmployeeV1.java", utf8Info.getValue()); + } + } + @Test + public void testClassIndex(){ + + ClassIndex clzIndex = clzFile.getClzIndex(); + ClassInfo thisClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getThisClassIndex()); + ClassInfo superClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getSuperClassIndex()); + + + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); + Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); + } + } diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/util/Util.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/util/Util.java new file mode 100644 index 0000000000..b8eaef98ef --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/util/Util.java @@ -0,0 +1,26 @@ +package com.github.ipk2015.coding2017.minijvm.util; + + + +public class Util { + public static int byteToInt(byte[] codes){ + String s1 = byteToHexString(codes); + return Integer.valueOf(s1, 16).intValue(); + } + + + + public static String byteToHexString(byte[] codes ){ + StringBuffer buffer = new StringBuffer(); + for(int i=0;i Date: Sun, 9 Apr 2017 19:03:30 +0800 Subject: [PATCH 093/203] finish JVM ClassFileParser by Korben --- .../mini-jvm/lib/commons-io-2.5.jar | Bin 0 -> 208700 bytes .../mini-jvm/lib/commons-lang3-3.5.jar | Bin 0 -> 479881 bytes .../com/coderising/jvm/clz/AccessFlag.java | 25 ++++ .../src/com/coderising/jvm/clz/ClassFile.java | 75 ++++++++++++ .../com/coderising/jvm/clz/ClassIndex.java | 22 ++++ .../coderising/jvm/constant/ClassInfo.java | 28 +++++ .../coderising/jvm/constant/ConstantInfo.java | 30 +++++ .../coderising/jvm/constant/ConstantPool.java | 29 +++++ .../coderising/jvm/constant/FieldRefInfo.java | 57 +++++++++ .../jvm/constant/MethodRefInfo.java | 56 +++++++++ .../jvm/constant/NameAndTypeInfo.java | 48 ++++++++ .../jvm/constant/NullConstantInfo.java | 13 ++ .../coderising/jvm/constant/StringInfo.java | 26 ++++ .../com/coderising/jvm/constant/UTF8Info.java | 36 ++++++ .../jvm/loader/ByteCodeIterator.java | 45 +++++++ .../jvm/loader/ClassFileLoader.java | 98 ++++----------- .../jvm/loader/ClassFileParser.java | 112 ++++++++++++++++++ .../jvm/test/ClassFileloaderTest.java | 110 +++++++++++++++++ .../com/coderising/jvm/test/EmployeeV1.java | 31 ++--- .../src/com/coderising/jvm/util/Util.java | 22 ++++ 20 files changed, 773 insertions(+), 90 deletions(-) create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/lib/commons-io-2.5.jar create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/lib/commons-lang3-3.5.jar create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/clz/AccessFlag.java create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/clz/ClassIndex.java create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/ClassInfo.java create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/ConstantInfo.java create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/ConstantPool.java create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/FieldRefInfo.java create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/MethodRefInfo.java create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/NameAndTypeInfo.java create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/NullConstantInfo.java create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/StringInfo.java create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/UTF8Info.java create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/util/Util.java diff --git a/group20/1107837739/1107837739Learning/mini-jvm/lib/commons-io-2.5.jar b/group20/1107837739/1107837739Learning/mini-jvm/lib/commons-io-2.5.jar new file mode 100644 index 0000000000000000000000000000000000000000..107b061f5fa84cecca645eae9bdefc98e084ce03 GIT binary patch literal 208700 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 z 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 C_bBoJ literal 0 HcmV?d00001 diff --git a/group20/1107837739/1107837739Learning/mini-jvm/lib/commons-lang3-3.5.jar b/group20/1107837739/1107837739Learning/mini-jvm/lib/commons-lang3-3.5.jar new file mode 100644 index 0000000000000000000000000000000000000000..6328c8de419b8424a27705fb940d2cfeccafddd9 GIT binary patch literal 479881 zcmbTd1C%Ar(k{H)n6_=(_Oxx=wrx(^c2C>3Ic>YAZBAQv-gD0P-S?dP-&x=N_sYF? zt*UskvYv>j+!+xmF9iY$4SD##1A`YDG%bvuxz4XKawGN{6QXM@4YYAh${wP~U1P59K6LH3m4bKb7 zdQLrm?-U38J}M<+uXyHLaqMNQ*rx<59URgC#v;jB;oh%sK#_LYZX34CHci?S)yv=x zSb{JSC0G*iJW# zN@>cGDEkk?qYc&tS-~P2fMF1dc!^Lw%=_dbMvH4e8Y#!gEeguylbM};y~}; z^wH=VFz-t|HdKR`;C!-+S=tH5rt`^5-xh?}0Z&7cT0DnGKuUaUNR&kN5zrJ+DCe8R z%ZnE;mn4-FdT%fmZXGGaSd+?5!*FvNW(}?jjg{GtcXioAxmHB4tkt?*6?NZ2a%V8fc(4r$p6E!0FZ!xIM#1p`tJ|a@1y^Atp6<* z`P={gTjuux=j7e*;AQ$GtKCzX8?; zwr0$KfD!%)X6RyJZEWKB2RO-};6`?~MlOzyCbrIh=mGyvJ(#%u8BF{~u)C3oy|aa# z?ceVHpBlsaQwKH%&gOr^{wL#qq|V00*}%~H?;8Gpf;*a+TALXCiMKzF+}XtaPgsgS zJ@r4Z&W;AQPSys_e|msFkHEs_PuM?d-Py(d-U-Ho8M#BrTLE;T3X_( zh^&$bowK|1rlywD`Y@{RW6g?ViIN3)Nj8fG_EALLerVNK3*k0fvcxdbT7nkv+EF@! z$oG5R)UJRcW49MonG#ls^VNo<+w7~Xp)WUWJtFiI*+^F|WnABNdG7Z4lU&xEch8>B zgx+La3mYMB?$4IDdD_g`Vcs*|nuhD=nZ2tDy0*6x(~}cUp|p`s(Kzt4=yeKJ!-23`QK?2in}t zXijEho7oW<$I54a_K7jmn}~`z>roh1ouT<^n(?HsLAJ;c@ro6*!HBgdo|xuvvm%2 z!#-!o;M=hjQcyj--GNRK8yDeFfx5IVaKLzmFv)@14oDW3YPFy!Ax{?Z#5C1V$u>Jtcw=Zu$hkL_qHL|AQx3toHs@oWYYlMRWR+#1VRt)to zu*3SSLsP8v5Z7kp%}aG~mKM*{H4?&9oWghd5)Ux*uOWw+n*AdC(tCU%4|il+K}9=c ze|%@;$MP@_MRER9YA($ll9;yG|FWOa5V-c_txi(|D2_*bb5sWTmVclacoqeuHi<9E zcre7@Rv+A*qaRxf8gI#1l@mr?Yg9;3i+&dvE)UOSePF55I|i_^*9rS}(nZoNDDO>-%T-gTTxk#g%{Lrxm}(<(Bc!c% z`@}Id0EolN9}AFfu^2?AW{47G;hh5shQ`L`4UD)o>A~h*Wn47DRS2@fZDI-E-$XLq^w?cxMfkYLnu~n{rnp3Z*$ZmuN+$C0rcDCOOjv zcmdd6QDRj)jO;Q%xH*LsHG-%jezufcGT$YsEOB|8DCrf;Z)tCY6G4e>ogQn3T)VVb z0Um|z25QLuAYDApc!jMI+SgC=nMf)UNMXBoNyguX-4?*j;|{tdI4hEo=*fp_PTYTk ztclnueQ>#I8IO!AY_f*8=Tq35#+tTkaeHgBsQY6#-BcHC`4w`aR-84?e+htrejE~Q zO%d~ew(KIzH$0`Kr;oNTsx~HX{=Ki*nDDh@cU2Lkj(Qv9Ly8NC=oB2CU4T+hQ?;H5 z)e(Zdbm;&Aj@3~MuA{xvia8tp;jtI9C58~=)+mF>@}eT*aFR!_MI_FrEr`3{`)s5@ z9u6I&gW09{!3%1Rc5B2d?AKdvo&q!??nj3fM^0Bw$)p-^l2Mf<;xWYug8iokcf-*E zoWV-K180kX6sVsNGt0_e(b|Q~n^L!(LCAX}slA@(XxQXVag+A$8d_kvEC?MCN9H>xZ zm-TJES-W!75B;mQIt{m1k`m##Tc%+0v!3zVJT?!NoxvadDZ8Z+>ST8Qq;y(}LZ?}CbzKH>B#$mkDc+chO-F>xLt z#Gt;-A}N6}N)MI9V^AoWi~5uVixMBC(R&1_IJoqph+KuJ$I~G+LwCdUp;vvGtCg$7 zfbLF@;!c(eJ#2KLhKE{>QGm3Uhp=VtD>PHbYXh|)wq^q!Rlp%E4ESWPBa&M;rTZyI zpb@W0$RrM3rAqnWXoGbe(b^4h?umSQ9@4p=7=vJ;wSd03=L@n?{xcj>lk+}$lkg)O zM_JK_1_r>%ao3&}okCM;6iW~Jw(EqaMn=s`#}ALNB3!4cy#<9rF_HZzwe zK8QPsxC0MfTmdK@@~pmuHW}1wnss_P~D*a7d z*l{M@k<$zVah*I;#>^|On?bnVchjjinf(B*6OR2LJR;VbQTdY7rwyV(E@{)dI_uH$ zem|{qx7+X^MWBmaA>Aa%(9PW-V*6$VzR)AsD#h)V)*v?7!qNb=%g;dWSjK1=oKOt? z(1tPLd8*^|G>DZOj*k@vxlOGsR)tfl@aDPN9H`#e9cm{q=$oTamErg-(IqZ}HZu%w ztc&b6CPT(mo%ph8bETrjvN8=Gp4rI#`L;Ak68M&>5)X-h#PxCs)R;h937*E?dP_FJuYPv>X4(DCN2uS?hAG6b6L z@Wn11&co05UD*xa){ZU>J*TFF^?qh*z}zDInbeJIAhX-o6Z;vf~hNCV>-JGT5&XfHu`;NAB#O zd#Bfu0-l_`_s~~M4eMs&6a>xQ$^M|BX6^2TMLAV7FfUN?j|8{_Jv0-E3y|J zSdwIVo+Gv86S*JCAasKD?o3|vVN*i{1UZC*zPlqFnG71VSK_hgBrJX0!;S*%g0CHe z(5Er4H??UbE1}Fo{5xCkh)_>yDEThq+U4f&pX#qy&zgIMCbAiMz=|b~_Up4vt9#ci zMcjeq#jwV!mA%7rM)L69;ZWSlFRm98SP+aF*aY1S*rIcV5bZodYJ+~H)@bhVq|tZx z%mE1+1>F>`8j%lH8M9!lG9zbAiP<$e%eZ1AakliJfRKGv zi9)5qo$^=Hr)j-)?As zg(e`}^SXw9zvl9%UC}t-7HQx1J31Z3n-$8ug;3ric>S;tHeYa=Xgt@mW<`l3Ff=F$ zchCp89VM#p;d!c_8RC;U)6a@cLQv%V@~fA6Sx-8;YU#(Yr*46iLcymiIxv^Bg%Ykj zbOb1Yn?k&9?$L2qSN5p3T{!=v*c+mx3{O>nJun&@9DV7N1wT0~h3vHBhCmXb(Lr;R zxha06L#yUy>929<%{Xuw9J;IkN0wGmm>h$uv@P$KR6ThaNFLm)y{?1)E-RerBEqo7 z130@%PK-H|U3!S8SCuy*&!8N!mdc*FJwEaBO0$emx%eIgD!S`{r>TR3M+%}}#E_uc z-EU7kGwz$uY)N^HqRK@aL@w{9U+0-PF;_zbQoceyPIo!J;I+P5`n)44myqi9&*bjn zePlDEBt|dDZrk@u1-%7)$9Vb_?*X|XYp6=jC`Aa&GKU?6!Kqr0L9iEq%A;`}v3q#7 zkk~!D{H1+|{t5I~-0$y;@_&Zw{#vg86{8UoTF3hMz39&c0sz>4|Na%w`&YQ`zoG^I zT;=~)bWGV!$=T7u)=b3R$lAr&gwDv?z{x2@enJw25rwx!Q|zoF5F1fJ+u1@mwHoxh zd?|cMA+}ojFQyXX1g1%pS1YV6U#mqbx6-@OL8 zyNk6to5;%)dm80yD+Ir%PFcmPtbJ=k@yn4ruHMCOfTEV;u*qtDNyH17fo=+YX{_z; zTwj5F=g6b5&-_N~T&pvnhF}EI!T%S-f9LUkGyGQo4t>z-(DOID?Z5!QUxA(fF~dsE z9@Zu#!X~B$F4oTfMf*Qa{*&~o_-V-j0fgb6*@Y#nCd+rV`@?)s^GG~Y!8K?}`P!x( ziRKecwK<(tl1RH^T~K&Fe|S<^BSbLzz>fZHFOT;N4TjJ)NTXy`G}gVsVs>Or1u zg*iww&MspJ;*mGE>PJ8Y(iX)-rd_F@EdLtT2ASNW;7)o!-1m{b-EQ7I^$wo@GV<9F zL?!BR-zl0D*N5>+BSt)W6V(UdID9bA=4F_>>J83Yk}#&+Tb~u0$egyj@{VGF)lg;% zH$<4n1j-?Y;qg?C&mw$zsa18S!kxPY_M^y$0=LnB4&pC`|6Q&BuJFyPcykS00Kh^6 z0ATrlR`@@4TdW18ue`X(_c)a?Hjx9R0U3utAdN(XfCeR8j{q6Udamjq4jyjW_aiuR zZLMATY;6dwZ>hpkZ# z`!3sSyXy*e+V|s{kSK!;ootqNmkIw}Ui%Vp`#RrIgo$%78Sh30zimim!-=&;dtj_7 zOMAp-`Sn=U0afk;jePrXpF7KYnc8;e%}e*jXUffUC_3wE*O;B0-D3!z<1=4vQ3am^Fs5&umj-_+Hw$XrL?RJD!CXWp!hiEzI|j-r2;{FEtJ7lxSvWiU1n|Ev67yUj(&6sL3}o?)j~Qk0OpPID@th#ac?=@P zx@TBT+uu6Hx~JR~jx~zo?9Dl4@l0=V9U_`&KZB9eyAPsF`HhX$@EB4Z^&IZA<0%Y1 z+i`l#5}P`FaLf8$Av$qMXm7=hHB}Y8q4K; z{zC3|AMuIoXY{(YbDEj;mR<3=GpD8PnJIN;e@jRHx!>&PaKcO1HC+tf`in62W3u@3 zX;5s}NS4oF@$(=?&S#hTrcKV9a7+wV@u>*K&a-HMIvelgb~f2^L%c=I)7!a8^~TdU zA+~y+iZ53BVYa0yayOomuU)XB$kR9@*3~lEIrhi(tZh}oNxTM5s+xy!v)BtSlbHPQ zuD#oG`DKc@oY!(n%4keX96@ne1@(f`HX=;eR|CN|sgA|lIeoKH7A7+ZJF%j!wyued z_{F)cwyJ@RjP?4a4)Xd=^2WAzZ>QzC%i#xkvCNQ!^U#??f?sJF^8@)g5Beh+@^YWNpHOgs-twjN@d<>gGWhAm6A1D|EEGc!}@Fya!roL7g3 zOTZ>!u~V1mG-jA)vR3QOSI1SbQ){$mRvK;d6f7(>>pNG|GD6DkC!1(#PZt7Iw|7%a zq#&ralE0v_HC1Z1>CTiMIt8u=QT2|iXn6_sH6LCs=|jkqHZ|IvK#O{M?If`-6&_kn zcEvx$j5p=)v_%E}tda^`KOFw1+kBEGZ&l=JE(QA$^yoQ27(@UXvI6j$F%KG| zNo%HQWNiv*C%TBot!(V>hz6-_>YxrBP7$vq2R0j`_?;IH;q&a*4RF=JhRf4JcjX&{aj&(wn*w)XOuF`xj@Krb#Wkl1=HdKT9xC-vgX|0bBVl z(^})G_4&myLwkq31}Yc+tz!QLda&}UCU5##TIr%=e^+*PUk+|YrctQLhzrJEVoNX) z^;fO6f%qI;c^xj!P$he)R8H2bk{eI$we>d2g$AnDh}3bKyPZT5Jn5z|*6jQo1ek|Z zI9xUl5av;ZX0mWFsE~HmW!FQh99mYcWr9aJK7cr`I3dOP-S zvD&hZzUIr};C5`AQ`^QWudhOz*w&}2k992Xkc{qoAF;I#_CvRR-PwTc;jspel9=(h~b6gh9A{Jt>Gcr7u!!)ar3+_@!> z;mKr=%CyZwJ_s$pUO}$4NsU{D%h7EHg9*buX|r}x>>RFt&tXW)-Nf6;bt(Cc8bn(B zOBm73#gt-l7mZ8jYJ#;*YujoK9NxH944b#PSOyp2!(2`^Y_ttoh{3Y_WSp2P6O3|j5Ef#dMq1dtT{S== z@^%6fhiGy(QcTTJVGrZ%YxvtWLpCM|vkb+gO<^rtrJmJ39Hx!)bC|5+&qHhx_4!DFBR7b2hnkxbduz&H2p3Am-86tMhwmOCz7jo(`{pmWJeJRM()m3zdZ-%W zHPnvZa4JR}>c!)S3}GdY^FW;C^Tjwg2geM!!kJGop?M`^^X*H7Vk<&Cpm_yjDSwf` zdrIOeSI;0eT?vKc9Cn*=Jh!bqqK4!gtSMBt9olo*gtA-DG*+9x-ezrs(o=n zeF2m62uN%>hK__v|{fOBlH#OUg z+_4^#(L&UXFPgFX#pMc9v7SfdO{9VNeE_mfeczrnJJC_Z*l8CzS-X6Hj)hKUZw`iT za%aw(Zt_r(HMP7=d7v1JZqcz!HD1ZMSS+Vtw2T0461mj_I5nX)X+M4*g%cMqaJd|% zPMYS3k6%rNlv6untXLsy-$Ak0rlD1NloYjJoi2O4n22ujX4Fz-D*29s!wSVC!(3?) z(=b|WO3k<`>nPqOvN9DmQoA>rqb7;OJE{uo-I4?Tl?ST4<*~bC@U*Ez=yCQv5N!p; zI{6La?%h%Euc#(MtT|EAF~y{8Y31Pb-J{W~9@lEf44n^ZU6K%h2zsdS2^F??l@nk_);`6;LMfO)E*Zy9TnHeFp z?JLIO0_TPX9yHylOImzawn7cOu){7k8KkdD`|#c`WQs4Fi)e#b)P0i#?4|3??dsup z_*Tl?LRUhXiE*G@hFg8F3lQ#%58XDk+*e7(+R;O%@Cioj4&**~8YR3EYG%8CeUlsQ z#-gBlo+4@wu^rkwW}_s#3J6IdAvPh%2I&`ek!{mep6#j~Bm5C{ z<4q@CqxgQ?>*%VsYcSI|@aq_<1-eI;&%Sf5T6Q@~F4rZ6<;d|P#ewb-wDcHmo$)_#%>_{F&H}d9X=pg z`dmd9XSK5}N}zVb&9Bergt_6Xrp!Esk!)28M;9poL=}^CQlptlhOzzeeb0#JZdQ5$IUwfmy-~`42-et z>GwH-!+l@q(t~I4Y4)%A~+7 zV#;&g3L??F%3L}NGte8bOFN^Vq;*Mb5ol{vOA4tRiA07Cr=%jx2_LbI<{#Ky`P_L> zd=3PUpyT6(%6yO#uu8L1wsktFjI!7zQ9E;)zuZ(R!#)B+27SFJ5MIr`9gb@1`Ua<@ zK;RWsQmB}(CN)^K_Td+gr%ws>+@Y0IbViW9X0t0uaGok~nZ$enadeAkmq#luGx4aV zkkOhrIPp?O!qfvmN@z>UI$%Bz9k8f+2bF|Vo2RrUSPuT4^0j56hFBY=wQF{3fO0g{ zP3=G`qTX1-wgk;N&1td&uXhPRGzZ!bLR}^h-K}xMh96+#WzQsijRx#Srv-zW9_eP$4 z6>i4~KO`Ef^1&4ebDxG3f zKEfz>+Et;p$Gfb`uP@z_)Y_S_{SdAoH?)_mE>?SGS#fY6 zDfXgT9;YZ`7m+6RYu+hC%BY|vTC7n7kKoxLA~D*q0;dnmmd=W7`3bW184l1Htkv?_ zQoA|oJNh2Uid~7^Vj5@lW!4lu!Qe&yG|#WL-p^WYU!iKbh2AHjt^-D7?))!&B@&h# zKPucaP@0tI!*EL~JBi}L!ue?>?-rNV1osxIG&;kFuvPNs${5x zT$2RlNc7&OwQtKRx_u2>BMSi`!&7rpO9z{J;tc?wa|jwvuPk2?bLlYG9x_ty$-IqY zJui_q{^F{{R2Z$ehxbh*yhNnK9BIBl^M-;pQc)@QsX})(wkhnc_rzy+8RIk@|1@0D zDc4=S=KMS9%M3T8^9dc*LB59OmExO-g+^{GS#x)%oOW;>_3lV@uU?YsLqvno8Lf{Y z=Wul-eh0Llg61Z9x#5}Bi!ju1bu@kl+V3;V({GHX2lbMsP77a+&ai*4?!WPJ`<|~pMJd+C(nVF-ofbk4HxI|!4Cy7Uy_oA* z^Dc-*32Yxy*hJuWqxvaWUKNhj-8;Qd#6lFCSLUvZ@l`DVy_h}5GmQ*|@GSr24R2KB z)CEW22hx~o!|SWjA0WN4J2%6hb-!WEG0asgdkUmN%urF3uX2`;a-Ii2$&a3s!krV- zOQv*glP<0>#=1zsbWZ(I!aFCYkp5N7n68WB%drV(hHh%euN)leA{sOa$4>ENQp0aq z6eXi$hM_Rwob}Q)DX4})JR+b6%5@sD$m=G_PoY_))yWM*Zu@1st{Sv>ajb?tJTf>5 zcSCpevYkZe;q1nR?pkyxxnpGMM5&|FZOSnz69#)!oD$Wc$rby~ZKn39Gav0L)#ju*`K**y@AW5ZWl~ECI#$OH<^O*?x+03082Rnd<`HM z6|DEIg@aYu30JsQp=f>DM}-tA(*NkCl(Ui$iSlGawg2yCR&nsNwNV#+6~r z|7s_`M@O-GVzsD1A*FC=Wm*GbiH20s_ZdT$9(0m7oky-*6ksT(P`X`6;yio#Bi*?Y@n+;nt<$R(70545GyqO9M2rEoNe&b9a-*e0~+Q>7>5~vrRgy zD0_wdXbO-GcW9c*7ZI1{A6SK%tZal@$OX;;O&Sw~+ff`iTn5?pFmsSX^1=mBq z{@_B6oT@ij;@GS#_!)RjWYsVg(hQfj2-VPTeGv@d(hyl0cuoEF#~P3b`pOy<{HZDG z8T9244_sJz{$q*I#gs9Q?0WRT3Fo1dGNXq=C$M?91mB1X!z&inMQaKfSGNdi%+;K; zwhuVH(lBGpHzOR(5sswcD5QHP6;!8m$9Q7u`KlMwK)82YmRneNF#fGC&o?m@mD?H) z$F3PFKiyhg(@tZlB&q)Hk5$opx_uVc==7I7rQ1W%_6naa#5g zydkV#5Dz$grHyd-^Ce=q%QkM5GJdv(SVbfdF<8oX>ZgDiO-&)6Tcya|)Y5Pfm>8nmZT=BhvWy6NNB8R)0 z4sO{jiE<}l)`4z}t>2)jTOg4`6#i$4l`c&Wan0T%V-)F_f4p(8IFmlfiSxA~)QTR> z#J8dP4bQqa*r)>;nv@>m+O2*=4{W%1aASH4V{P)Kb zNj<>CbuFUyDY?eJuaJ8*3EpB^B?J+)p^~)p$z%%NqQ!Z`iC=<_=`@SyaN&&2i;CaE zY*@<*+=3B23+44dlK6p<=)ok=gO2GzjHP~y+b@F>&vC6M(St~+X%V?q&fY(HkkB=Y z>)guN|J_{`!82Ry30&M8aoh$(!WHnC+d5I3B}anUZ{$hqQMUhnn7}Px-Zp#!KKK}f z;4NRAHzWx@9^shE?`|FHN$|nOMy%ttixYX~`NqsJNc_e!_W1+$Qw49S?dK~9o>}AG z(Bt0N99?U4s*$8MChce!jRIEtAfgUf#;o; zbUsPy`EtFe$G8`REtjMOoe_%3dz^#T9EcwJ8J6W5BVTsLO#u7v#(U_7ESrFw2vofV za0~dzjJ^q=@bN*925R*NS4-i`-M&l7_a5VGXTkgS0s^-z1-N7C?F42RDOU%E}U;9p5M_3b$FM4r8QOvA5vhC$`i2}%6S4ov3hN$z|k zxOzt(wPNwrTBv-LNLDi>y>c3TB^n0%dXQfP5t;az9D+Ir{AJ7*p0urtT%dhaV6B*# z*1vT@CkaH9nX{x3-mh>sU3q(^ota`aTLSZvX58)7NScBH1r>t~<(TZ4=J2aqV!l^= z^}5a5F~w30&Apyh?kwSNEzk$I|s|$5nis&UbN%=1jyLAyE%XA~E6z zwS~l6;s>b-_F2}6w)pE2mm0Z0wvE^)mE^G=hIxWOXBk$hf0wJCHJZnzIR4JUoQu2D zzzl9kll#`76*F<4A}}{8Fx3KD--jjMjyXySaI^p>2y-SdQwJVn0BKu78cnSXFis2b z#usoU130QfIF^vcDKp2d(*$Ihz>+M&?9&0-xPjt8xZxo1Bb?*17NLz@DK`T^i?25ogw z_ZK1a$3y4jwY_!kEOJjk0(dXM)NUf}U?2;~rI7YIg@SPm!`RaRVnBKg0XVsU9cEMi zBTe8ROdyrDpeu|ty)?|dNkN|qaxLK9)Snj63Jq8W z?5u$T@YzAmn?X6oVHnJz?AL1nV(CDx!20L_Taezn-*@hZx#p4b2Q&3Y*91PtMAHwz z+(8AnlLBs0~!=>a@21Q1974@rny6RB~@A4$9>Q2TENl+=t$4^r|E)bbD5@(=5vNw~~P z%>zg~!pyzPv_QHHG`$g~{-40TkAQ0sz#9Wl@6itceIuy4CGc@_3VA5 z?JS3ashfhg0t3{5cc=i`*?^rdH-N6)vtfRMc5Phg#$A9;+Xvyxp>F#rKqq>R)$3#p z#2Hs|`Ks6sH_xu{S9aI0O%P`g$?bKiZGHi6g?0z}3od~Ug?0=2_Z`4HLUHC}f_|3a zbu>&>FV>d$sxw@4{)MunUZI6E>}0W4Y5a@*Vry_VFXzkIb)Wrro<8&U-ljjMZomFj z^`PQxVeLdBVe4$-Xlh_&;`GndZMM>t-JCoMuN^H)yY1V`LcrY!4pl9b(GR&eFcX?S zmUW2W)~6E%?xo_!lB9Q?7}62nR;P%+Ac$%eJGe*O!;~ks~`ma~*QX zH*%^Rq6&QpLEVs0*g9*`+B`)EC4wB0IE1>qywN-s_)|}>n!Y?X-0fd6Z3b`{jU{_& zx|@eV0pcyr%V((1Ubb0jA_EtXI%e{XZS&OVAkynC=YoeBc|wEH>_ ^B(yv*tDT@ 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
A6;v5cGzAZa6hb`eZ&6g4q?PG~ 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%0DplU~I@98OekpK=g=$9`7uGGKHDu1_S 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
`QEZug%9 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 constantInfos = new ArrayList(); + + public ConstantPool() { + + } + + public void addConstantInfo(ConstantInfo info) { + this.constantInfos.add(info); + } + + public ConstantInfo getConstantInfo(int index) { + return this.constantInfos.get(index); + } + + public String getUTF8String(int index) { + return ((UTF8Info) this.constantInfos.get(index)).getValue(); + } + + public Object getSize() { + return this.constantInfos.size() - 1; + } +} diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/FieldRefInfo.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..92aa99b18d --- /dev/null +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/FieldRefInfo.java @@ -0,0 +1,57 @@ +package com.coderising.jvm.constant; + +public class FieldRefInfo extends ConstantInfo { + private int type = ConstantInfo.FIELD_INFO; + private int classInfoIndex; + private int nameAndTypeIndex; + + public FieldRefInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String toString() { + + NameAndTypeInfo typeInfo = (NameAndTypeInfo) this.getConstantInfo(this.getNameAndTypeIndex()); + + return getClassName() + " : " + typeInfo.getName() + ":" + typeInfo.getTypeInfo() + "]"; + } + + public String getClassName() { + + ClassInfo classInfo = (ClassInfo) this.getConstantInfo(this.getClassInfoIndex()); + + UTF8Info utf8Info = (UTF8Info) this.getConstantInfo(classInfo.getUtf8Index()); + + return utf8Info.getValue(); + } + + public String getFieldName() { + NameAndTypeInfo typeInfo = (NameAndTypeInfo) this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getFieldType() { + NameAndTypeInfo typeInfo = (NameAndTypeInfo) this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } +} diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/MethodRefInfo.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..08bed198d3 --- /dev/null +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/MethodRefInfo.java @@ -0,0 +1,56 @@ +package com.coderising.jvm.constant; + +public class MethodRefInfo extends ConstantInfo { + + private int type = ConstantInfo.METHOD_INFO; + + private int classInfoIndex; + private int nameAndTypeIndex; + + public MethodRefInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String toString() { + + return getClassName() + " : " + this.getMethodName() + " : " + this.getParamAndReturnType(); + } + + public String getClassName() { + ConstantPool pool = this.getConstantPool(); + ClassInfo clzInfo = (ClassInfo) pool.getConstantInfo(this.getClassInfoIndex()); + return clzInfo.getClassName(); + } + + public String getMethodName() { + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo) pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getParamAndReturnType() { + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo) pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } +} diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/NameAndTypeInfo.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..d7cd146895 --- /dev/null +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,48 @@ +package com.coderising.jvm.constant; + +public class NameAndTypeInfo extends ConstantInfo { + public int type = ConstantInfo.NAME_AND_TYPE_INFO; + + private int index1; + private int index2; + + public NameAndTypeInfo(ConstantPool pool) { + super(pool); + } + + public int getIndex1() { + return index1; + } + + public void setIndex1(int index1) { + this.index1 = index1; + } + + public int getIndex2() { + return index2; + } + + public void setIndex2(int index2) { + this.index2 = index2; + } + + public int getType() { + return type; + } + + public String getName() { + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info1 = (UTF8Info) pool.getConstantInfo(index1); + return utf8Info1.getValue(); + } + + public String getTypeInfo() { + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info2 = (UTF8Info) pool.getConstantInfo(index2); + return utf8Info2.getValue(); + } + + public String toString() { + return "(" + getName() + "," + getTypeInfo() + ")"; + } +} diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/NullConstantInfo.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..0ee9e721ad --- /dev/null +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/NullConstantInfo.java @@ -0,0 +1,13 @@ +package com.coderising.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo() { + + } + + @Override + public int getType() { + return -1; + } +} diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/StringInfo.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..5cd3df772e --- /dev/null +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/StringInfo.java @@ -0,0 +1,26 @@ +package com.coderising.jvm.constant; + +public class StringInfo extends ConstantInfo { + private int type = ConstantInfo.STRING_INFO; + private int index; + + public StringInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + + public String toString() { + return this.getConstantPool().getUTF8String(index); + } +} diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/UTF8Info.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..49bfcb9434 --- /dev/null +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/UTF8Info.java @@ -0,0 +1,36 @@ +package com.coderising.jvm.constant; + +public class UTF8Info extends ConstantInfo { + private int type = ConstantInfo.UTF8_INFO; + private int length; + private String value; + + public UTF8Info(ConstantPool pool) { + super(pool); + } + + public int getLength() { + return length; + } + + public void setLength(int length) { + this.length = length; + } + + public int getType() { + return type; + } + + @Override + public String toString() { + return "UTF8Info [type=" + type + ", length=" + length + ", value=" + value + ")]"; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..35a6a8b207 --- /dev/null +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,45 @@ +package com.coderising.jvm.loader; + +import com.coderising.jvm.util.Util; +import java.util.Arrays; + +public class ByteCodeIterator { + private byte[] codes; + private int pos; + + public ByteCodeIterator(byte[] codes) { + this.codes = codes; + } + + public byte[] getBytes(int len) { + if (pos + len >= codes.length) { + throw new IndexOutOfBoundsException(); + } + + byte[] bytes = Arrays.copyOfRange(codes, pos, pos + len); + pos += len; + return bytes; + } + + public int nextU1ToInt() { + return Util.byteToInt(new byte[] {codes[pos++]}); + } + + public int nextU2ToInt() { + return Util.byteToInt(new byte[] {codes[pos++], codes[pos++]}); + } + + public int nextU4ToInt() { + return Util.byteToInt(new byte[] {codes[pos++], codes[pos++], codes[pos++], codes[pos++]}); + } + + public String nextU4ToHexString() { + return Util.byteToHexString(new byte[] {codes[pos++], codes[pos++], codes[pos++], codes[pos++]}); + } + + public String newUxToHexString(int len) { + String hexString = Util.byteToHexString(Arrays.copyOfRange(codes, pos, pos + len)); + pos += len; + return hexString; + } +} diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java index 0411392cee..20fb8c530e 100644 --- a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -1,111 +1,59 @@ package com.coderising.jvm.loader; -import java.io.ByteArrayOutputStream; +import com.coderising.jvm.clz.ClassFile; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; public class ClassFileLoader { private List clzPaths = new ArrayList(); public byte[] readBinaryCode(String className) { - if (className == null || className.length() == 0) { - return null; - } - - File classFile = getClassFileFromClassPath(className); - - if (classFile == null) { - return null; - } - return readFileBytes(classFile); - } + className = className.replace('.', File.separatorChar) + ".class"; - public void addClassPath(String path) { - if (path == null || path.length() == 0) { - return; - } - - clzPaths.add(path); - } - - public String getClassPath() { - StringBuilder stringBuilder = new StringBuilder(); - for (int i = 0; i < clzPaths.size(); i++) { - stringBuilder.append(clzPaths.get(i)); - if (i < clzPaths.size() - 1) { - stringBuilder.append(";"); + for (String path : this.clzPaths) { + String clzFileName = path + File.separatorChar + className; + byte[] codes = loadClassFile(clzFileName); + if (codes != null) { + return codes; } } - return stringBuilder.toString(); + return null; } - private byte[] readFileBytes(File file) { - ByteArrayOutputStream out = new ByteArrayOutputStream(); + private byte[] loadClassFile(String clzFileName) { + File f = new File(clzFileName); - FileInputStream in = null; try { - in = new FileInputStream(file); - byte[] buffer = new byte[1024]; - int len; - while ((len = in.read(buffer)) != -1) { - out.write(buffer, 0, len); - } - - return out.toByteArray(); + return IOUtils.toByteArray(new FileInputStream(f)); } catch (IOException e) { e.printStackTrace(); return null; - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } } } - private File getClassFileFromClassPath(String className) { - className = className2FilePath(className); - className += ".class"; - - // 从当前路径读取 - File classFile = getFileFromDir("", className); - if (classFile != null) { - return classFile; - } - - // 从环境变量路径读取 - for (String clzPath : clzPaths) { - classFile = getFileFromDir(clzPath, className); - if (classFile != null) { - return classFile; - } + public void addClassPath(String path) { + if (this.clzPaths.contains(path)) { + return; } - return null; + this.clzPaths.add(path); } - private File getFileFromDir(String dir, String fileName) { - File file = new File(dir); - File destFile; - if (file.exists() && file.isDirectory()) { - destFile = new File(file.getAbsolutePath() + File.separator + fileName); - if (destFile.isFile() && destFile.exists()) { - return destFile; - } - } - return null; + public String getClassPath() { + return StringUtils.join(this.clzPaths, ";"); } - private String className2FilePath(String className) { - return className.replaceAll("\\.", File.separator); + public ClassFile loadClass(String className) { + byte[] codes = this.readBinaryCode(className); + ClassFileParser parser = new ClassFileParser(); + return parser.parse(codes); } } diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..8ac21a8870 --- /dev/null +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java @@ -0,0 +1,112 @@ +package com.coderising.jvm.loader; + +import com.coderising.jvm.clz.AccessFlag; +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.clz.ClassIndex; +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantInfo; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.FieldRefInfo; +import com.coderising.jvm.constant.MethodRefInfo; +import com.coderising.jvm.constant.NameAndTypeInfo; +import com.coderising.jvm.constant.NullConstantInfo; +import com.coderising.jvm.constant.StringInfo; +import com.coderising.jvm.constant.UTF8Info; +import java.io.UnsupportedEncodingException; + +public class ClassFileParser { + + public ClassFile parse(byte[] codes) { + ClassFile classFile = new ClassFile(); + + ByteCodeIterator iterator = new ByteCodeIterator(codes); + + String magicNumber = iterator.nextU4ToHexString(); + if (!"cafebabe".equals(magicNumber)) { + return null; + } + + classFile.setMinorVersion(iterator.nextU2ToInt()); + classFile.setMajorVersion(iterator.nextU2ToInt()); + + classFile.setConstPool(parseConstantPool(iterator)); + classFile.setAccessFlag(parseAccessFlag(iterator)); + classFile.setClassIndex(parseClassInfex(iterator)); + + return classFile; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + AccessFlag accessFlag = new AccessFlag(iter.nextU2ToInt()); + return accessFlag; + } + + private ClassIndex parseClassInfex(ByteCodeIterator iter) { + ClassIndex classIndex = new ClassIndex(); + classIndex.setThisClassIndex(iter.nextU2ToInt()); + classIndex.setSuperClassIndex(iter.nextU2ToInt()); + return classIndex; + } + + private ConstantPool parseConstantPool(ByteCodeIterator iter) { + int constantPoolCount = iter.nextU2ToInt(); + + ConstantPool pool = new ConstantPool(); + pool.addConstantInfo(new NullConstantInfo()); + + for (int i = 1; i < constantPoolCount; i++) { + int type = iter.nextU1ToInt(); + + if (type == ConstantInfo.CLASS_INFO) { + int utf8Index = iter.nextU2ToInt(); + ClassInfo clzInfo = new ClassInfo(pool); + clzInfo.setUtf8Index(utf8Index); + + pool.addConstantInfo(clzInfo); + } else if (type == ConstantInfo.UTF8_INFO) { + int len = iter.nextU2ToInt(); + byte[] data = iter.getBytes(len); + + String value = null; + try { + value = new String(data, "UTF-8"); + } catch (UnsupportedEncodingException e) { + // ignore + } + + UTF8Info utf8Info = new UTF8Info(pool); + utf8Info.setLength(len); + utf8Info.setValue(value); + + pool.addConstantInfo(utf8Info); + } else if (type == ConstantInfo.STRING_INFO) { + StringInfo stringInfo = new StringInfo(pool); + stringInfo.setIndex(iter.nextU2ToInt()); + + pool.addConstantInfo(stringInfo); + } else if (type == ConstantInfo.FIELD_INFO) { + FieldRefInfo fieldRefInfo = new FieldRefInfo(pool); + fieldRefInfo.setClassInfoIndex(iter.nextU2ToInt()); + fieldRefInfo.setNameAndTypeIndex(iter.nextU2ToInt()); + + pool.addConstantInfo(fieldRefInfo); + } else if (type == ConstantInfo.METHOD_INFO) { + MethodRefInfo methodRefInfo = new MethodRefInfo(pool); + methodRefInfo.setClassInfoIndex(iter.nextU2ToInt()); + methodRefInfo.setNameAndTypeIndex(iter.nextU2ToInt()); + + pool.addConstantInfo(methodRefInfo); + } else if (type == ConstantInfo.NAME_AND_TYPE_INFO) { + NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(pool); + nameAndTypeInfo.setIndex1(iter.nextU2ToInt()); + nameAndTypeInfo.setIndex2(iter.nextU2ToInt()); + + pool.addConstantInfo(nameAndTypeInfo); + } else { + throw new RuntimeException("the constant pool type " + type + " hasn't been implemented yet!"); + } + } + + return pool; + } +} diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java index b598f7f6d1..d033dfe252 100644 --- a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -1,5 +1,12 @@ package com.coderising.jvm.test; +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.clz.ClassIndex; +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.MethodRefInfo; +import com.coderising.jvm.constant.NameAndTypeInfo; +import com.coderising.jvm.constant.UTF8Info; import com.coderising.jvm.loader.ClassFileLoader; import org.junit.After; import org.junit.Assert; @@ -8,9 +15,22 @@ public class ClassFileloaderTest { + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + static String path1 = "/Users/Korben/wks/hom/01.coding2017/group20/1107837739/1107837739Learning/mini-jvm/out/production/mini-jvm/"; static String path2 = "C:\temp"; + static ClassFile clzFile = null; + + static { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "com.coderising.jvm.test.EmployeeV1"; + + clzFile = loader.loadClass(className); + clzFile.print(); + } + @Before public void setUp() throws Exception { } @@ -71,4 +91,94 @@ private String byteToHexString(byte[] codes) { } return buffer.toString(); } + + /** + * ---------------------------------------------------------------------- + */ + + @Test + public void testVersion() { + + Assert.assertEquals(0, clzFile.getMinorVersion()); + Assert.assertEquals(52, clzFile.getMajorVersion()); + } + + @Test + public void testConstantPool() { + + ConstantPool pool = clzFile.getConstantPool(); + + Assert.assertEquals(53, pool.getSize()); + + { + ClassInfo clzInfo = (ClassInfo) pool.getConstantInfo(1); + Assert.assertEquals(2, clzInfo.getUtf8Index()); + + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(2); + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, utf8Info.getValue()); + } + { + ClassInfo clzInfo = (ClassInfo) pool.getConstantInfo(3); + Assert.assertEquals(4, clzInfo.getUtf8Index()); + + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(4); + Assert.assertEquals("java/lang/Object", utf8Info.getValue()); + } + { + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(5); + Assert.assertEquals("name", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(6); + Assert.assertEquals("Ljava/lang/String;", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(7); + Assert.assertEquals("age", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(8); + Assert.assertEquals("I", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(9); + Assert.assertEquals("", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(10); + Assert.assertEquals("(Ljava/lang/String;I)V", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(11); + Assert.assertEquals("Code", utf8Info.getValue()); + } + + { + MethodRefInfo methodRef = (MethodRefInfo) pool.getConstantInfo(12); + Assert.assertEquals(3, methodRef.getClassInfoIndex()); + Assert.assertEquals(13, methodRef.getNameAndTypeIndex()); + } + + { + NameAndTypeInfo nameAndType = (NameAndTypeInfo) pool.getConstantInfo(13); + Assert.assertEquals(9, nameAndType.getIndex1()); + Assert.assertEquals(14, nameAndType.getIndex2()); + } + //抽查几个吧 + { + MethodRefInfo methodRef = (MethodRefInfo) pool.getConstantInfo(45); + Assert.assertEquals(1, methodRef.getClassInfoIndex()); + Assert.assertEquals(46, methodRef.getNameAndTypeIndex()); + } + + { + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(53); + Assert.assertEquals("EmployeeV1.java", utf8Info.getValue()); + } + } + + @Test + public void testClassIndex() { + + ClassIndex clzIndex = clzFile.getClzIndex(); + ClassInfo thisClassInfo = (ClassInfo) clzFile.getConstantPool().getConstantInfo(clzIndex.getThisClassIndex()); + ClassInfo superClassInfo = (ClassInfo) clzFile.getConstantPool().getConstantInfo(clzIndex.getSuperClassIndex()); + + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); + Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); + } } diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/test/EmployeeV1.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/test/EmployeeV1.java index 9a36573dd3..029d3c8d3d 100644 --- a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/test/EmployeeV1.java +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/test/EmployeeV1.java @@ -1,28 +1,29 @@ package com.coderising.jvm.test; public class EmployeeV1 { - - - private String name; + + private String name; private int age; - + public EmployeeV1(String name, int age) { this.name = name; - this.age = age; - } + this.age = age; + } + + public static void main(String[] args) { + EmployeeV1 p = new EmployeeV1("Andy", 29); + p.sayHello(); + } public void setName(String name) { this.name = name; } - public void setAge(int age){ - this.age = age; - } - public void sayHello() { - System.out.println("Hello , this is class Employee "); + + public void setAge(int age) { + this.age = age; } - public static void main(String[] args){ - EmployeeV1 p = new EmployeeV1("Andy",29); - p.sayHello(); - + + public void sayHello() { + System.out.println("Hello , this is class Employee "); } } \ No newline at end of file diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/util/Util.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/util/Util.java new file mode 100644 index 0000000000..f6e9689c5a --- /dev/null +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/util/Util.java @@ -0,0 +1,22 @@ +package com.coderising.jvm.util; + +public class Util { + public static int byteToInt(byte[] codes) { + String s1 = byteToHexString(codes); + return Integer.valueOf(s1, 16).intValue(); + } + + public static String byteToHexString(byte[] codes) { + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < codes.length; i++) { + byte b = codes[i]; + int value = b & 0xFF; + String strHex = Integer.toHexString(value); + if (strHex.length() < 2) { + strHex = "0" + strHex; + } + buffer.append(strHex); + } + return buffer.toString(); + } +} From ad537f8cf8a748b2d54213c373b678fc03254363 Mon Sep 17 00:00:00 2001 From: James <1310368322@qq.com> Date: Sun, 9 Apr 2017 19:41:22 +0800 Subject: [PATCH 094/203] FifthHomework --- .../DataStructure_5_Stack/StackUtil.java | 106 +++++++++++ .../src/FifthHomework/jvm/clz/AccessFlag.java | 26 +++ .../src/FifthHomework/jvm/clz/ClassFile.java | 75 ++++++++ .../src/FifthHomework/jvm/clz/ClassIndex.java | 23 +++ .../FifthHomework/jvm/constant/ClassInfo.java | 33 ++++ .../jvm/constant/ConstantInfo.java | 34 ++++ .../jvm/constant/ConstantPool.java | 30 +++ .../jvm/constant/FieldRefInfo.java | 62 +++++++ .../jvm/constant/MethodRefInfo.java | 52 ++++++ .../jvm/constant/NameAndTypeInfo.java | 52 ++++++ .../jvm/constant/NullConstantInfo.java | 13 ++ .../jvm/constant/StringInfo.java | 30 +++ .../FifthHomework/jvm/constant/UTF8Info.java | 40 ++++ .../jvm/loader/ByteCodeIterator.java | 45 +++++ .../jvm/loader/ClassFileLoader.java | 69 +++++++ .../jvm/loader/ClassFileParser.java | 130 +++++++++++++ .../src/FifthHomework/jvm/loader/TestJVM.java | 7 + .../DataStructure_5_Stack/TestStackUtil.java | 77 ++++++++ .../DataStructure_5_Stack/TestSwitch.java | 15 ++ .../FifthHomework/jvm/loader/EmployeeV1.java | 28 +++ .../FifthHomework/jvm/loader/TestArray.java | 8 + .../jvm/loader/TestArrayList.java | 14 ++ .../jvm/loader/TestByteArrayToHexString.java | 15 ++ .../jvm/loader/TestByteArrayToInt.java | 12 ++ .../jvm/loader/TestByteToInt.java | 12 ++ .../jvm/loader/TestClassFileLoader.java | 174 ++++++++++++++++++ .../jvm/loader/TestIntegerToHexString.java | 10 + 27 files changed, 1192 insertions(+) create mode 100644 group11/1310368322/src/FifthHomework/DataStructure_5_Stack/StackUtil.java create mode 100644 group11/1310368322/src/FifthHomework/jvm/clz/AccessFlag.java create mode 100644 group11/1310368322/src/FifthHomework/jvm/clz/ClassFile.java create mode 100644 group11/1310368322/src/FifthHomework/jvm/clz/ClassIndex.java create mode 100644 group11/1310368322/src/FifthHomework/jvm/constant/ClassInfo.java create mode 100644 group11/1310368322/src/FifthHomework/jvm/constant/ConstantInfo.java create mode 100644 group11/1310368322/src/FifthHomework/jvm/constant/ConstantPool.java create mode 100644 group11/1310368322/src/FifthHomework/jvm/constant/FieldRefInfo.java create mode 100644 group11/1310368322/src/FifthHomework/jvm/constant/MethodRefInfo.java create mode 100644 group11/1310368322/src/FifthHomework/jvm/constant/NameAndTypeInfo.java create mode 100644 group11/1310368322/src/FifthHomework/jvm/constant/NullConstantInfo.java create mode 100644 group11/1310368322/src/FifthHomework/jvm/constant/StringInfo.java create mode 100644 group11/1310368322/src/FifthHomework/jvm/constant/UTF8Info.java create mode 100644 group11/1310368322/src/FifthHomework/jvm/loader/ByteCodeIterator.java create mode 100644 group11/1310368322/src/FifthHomework/jvm/loader/ClassFileLoader.java create mode 100644 group11/1310368322/src/FifthHomework/jvm/loader/ClassFileParser.java create mode 100644 group11/1310368322/src/FifthHomework/jvm/loader/TestJVM.java create mode 100644 group11/1310368322/test/FifthHomework/DataStructure_5_Stack/TestStackUtil.java create mode 100644 group11/1310368322/test/FifthHomework/DataStructure_5_Stack/TestSwitch.java create mode 100644 group11/1310368322/test/FifthHomework/jvm/loader/EmployeeV1.java create mode 100644 group11/1310368322/test/FifthHomework/jvm/loader/TestArray.java create mode 100644 group11/1310368322/test/FifthHomework/jvm/loader/TestArrayList.java create mode 100644 group11/1310368322/test/FifthHomework/jvm/loader/TestByteArrayToHexString.java create mode 100644 group11/1310368322/test/FifthHomework/jvm/loader/TestByteArrayToInt.java create mode 100644 group11/1310368322/test/FifthHomework/jvm/loader/TestByteToInt.java create mode 100644 group11/1310368322/test/FifthHomework/jvm/loader/TestClassFileLoader.java create mode 100644 group11/1310368322/test/FifthHomework/jvm/loader/TestIntegerToHexString.java diff --git a/group11/1310368322/src/FifthHomework/DataStructure_5_Stack/StackUtil.java b/group11/1310368322/src/FifthHomework/DataStructure_5_Stack/StackUtil.java new file mode 100644 index 0000000000..782c7d59a6 --- /dev/null +++ b/group11/1310368322/src/FifthHomework/DataStructure_5_Stack/StackUtil.java @@ -0,0 +1,106 @@ +package DataStructure_5_Stack; + +import java.util.Stack; + +public class StackUtil { + /* + * ����ջ�е�Ԫ����Integer����ջ����ջ���ǣ� 5,4,3,2,1 ���ø÷����󣬴�ջ����ջ�׻��� 1,2,3,4,5 + * ע�⣺ ֻ��ʹ�� Stack�Ļ�����������push,pop,peek,isEmpty + */ + public static void reverse(Stack s){ + if(s.isEmpty()){ return; } + int length = s.size(); + Object []temp = new Object[length]; + for(int i = 0; i < length; i++){ + temp[i] = s.pop(); + } + for(int i = 0; i < length; i++){ + s.push(temp[i]); + } + return; + } + + /* + * ɾ��ջ��ָ��Ԫ�أ�ע�⣺ֻ��ʹ��Stack�Ļ�����������push,pop,peek,isEmpty + * + */ + public static void remove(Stack s, Object o){ + int length = s.size(); + Object elementTemp; + System.out.println(length); + int count = 0; + Object []temp = new Object[length]; + if(s.isEmpty()){ return; } + for(int i = 0; i < length;i++){ + elementTemp = s.pop(); + if(!o.equals(elementTemp)){ + temp[count++] = elementTemp; + System.out.println(temp[i]); + } + } + + for(int i = count-1; i >= 0; i--){ + s.push(temp[i]); + } + return; + } + + /* + * ��ջ��ȡ��len��Ԫ�أ�ԭ��ջ�е�Ԫ�ر��ֲ��� + * @param len + * @return + */ + public static Object[] getTop(Stack s , int len){ + if(s.isEmpty() || len > s.size() || len < 0){ + return null; + } + Object []result = new Object[len]; + for(int i = 0; i < len; i++){ + result[i] = s.pop(); + } + return result; + } + + /* + * �ַ��� s ���ܰ�����Щ�ַ��� () [] {}, a, b, c ... x, y, z + * ʹ�ö�ջ����ַ��� s �е������Dz��dzɶԳ��ֵ� + * ���磺 s = ��([e{d}f])��,����ַ����е������dzɶԳ��ֵģ��÷������� true + * ����� s = "([b{x]})",����ַ����е����Ų��dzɶԳ��ֵģ��÷��� ���� false + * @param s + * @return + */ + public static boolean isValidPairs(String s){ + Stack stack = new Stack(); + System.out.println(stack.isEmpty()); + char elementTemp; + boolean tag = false; + char [] a = s.toCharArray(); + for(int i = 0; i < a.length; i++){ + if((!tag) && (a[i] == '(' || a[i] == ')' || a[i] == '[' || a[i] == ']' || a[i] == '{' || a[i] == '}')){ + stack.push(a[i]); + tag = true; + }else{ + if(a[i] == '(' || a[i] == ')' || a[i] == '[' || a[i] == ']' || a[i] == '{' || a[i] == '}'){ + elementTemp = (char) stack.pop(); + switch(elementTemp){ + case '(': if(a[i]==')'){}else{ stack.push(elementTemp); stack.push(a[i]); }; break; + case '[': if(a[i]==']'){}else{ stack.push(elementTemp); stack.push(a[i]); }; break; + case '{': if(a[i]=='}'){}else{ stack.push(elementTemp); stack.push(a[i]); }; break; + + } + } + } + + } + if(stack.isEmpty()){ + return true; + } + return false; + } +} + + + + + + diff --git a/group11/1310368322/src/FifthHomework/jvm/clz/AccessFlag.java b/group11/1310368322/src/FifthHomework/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..4e26442ed5 --- /dev/null +++ b/group11/1310368322/src/FifthHomework/jvm/clz/AccessFlag.java @@ -0,0 +1,26 @@ +package com.coderising.jvm.clz; + +public class AccessFlag { + private int flagValue; + + public AccessFlag(int value){ + this.flagValue = value; + } + + public int getFlagValue(){ + return flagValue; + } + + public void setFlagValue(int flag){ + this.flagValue = flag; + } + + public boolean isPublicClass(){ + return (this.flagValue & 0x0001) != 0; + } + + public boolean isFinalClass(){ + return (this.flagValue & 0x0010) != 0; + } + +} diff --git a/group11/1310368322/src/FifthHomework/jvm/clz/ClassFile.java b/group11/1310368322/src/FifthHomework/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..3bf1a8c56e --- /dev/null +++ b/group11/1310368322/src/FifthHomework/jvm/clz/ClassFile.java @@ -0,0 +1,75 @@ +package com.coderising.jvm.clz; + +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantPool; + +public class ClassFile { + private int minorVersion; + private int majorVersion; + + private AccessFlag accessFlag;// �ڳ�����֮�� + private ClassIndex clzIndex;// �ڷ��ʱ�־֮��, �����������������������ͽӿ����� + private ConstantPool pool; + + + public AccessFlag getAccessFlag(){ + return accessFlag; + } + + public ClassIndex getClzIndex(){ + return clzIndex; + } + + public void setClassIndex(ClassIndex clzIndex){ + this.clzIndex = clzIndex; + } + + public int getMinorVersion(){ + System.out.println(minorVersion); + return minorVersion; + } + + public void setMinorVersion(int minorVersion){ + this.minorVersion = minorVersion; + } + + public int getMajorVersion(){ + return majorVersion; + } + + public void setMajorVersion(int majorVersion){ + this.majorVersion = majorVersion; + } + + public ConstantPool getConstantPool(){ + return this.pool; + } + public void setConstantPool(ConstantPool pool){ + this.pool = pool; + } + + public void print(){ + if(this.accessFlag.isPublicClass()){ + System.out.println("Access flag : public "); + } + System.out.println("ClassName: " + getClassName()); + System.out.println("SuperClassName: " + getSuperClassName()); + + } + + public void setAccessFlag(AccessFlag accessFlag){ + this.accessFlag = accessFlag; + } + + private String getClassName(){ + int thisClassIndex = this.clzIndex.getThisClassIndex(); + ClassInfo thisClass = (ClassInfo)this.getConstantPool().getConstantInfo(thisClassIndex); + return thisClass.getClassName(); + } + + private String getSuperClassName(){ + ClassInfo superClass = (ClassInfo)this.getConstantPool().getConstantInfo(this.clzIndex.getSuperClassIndex()); + return superClass.getClassName(); + } + +} diff --git a/group11/1310368322/src/FifthHomework/jvm/clz/ClassIndex.java b/group11/1310368322/src/FifthHomework/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..8382ef03f9 --- /dev/null +++ b/group11/1310368322/src/FifthHomework/jvm/clz/ClassIndex.java @@ -0,0 +1,23 @@ +package com.coderising.jvm.clz; + +public class ClassIndex { + private int thisClassIndex; + private int superClassIndex; + + public int getThisClassIndex(){ + System.out.println(thisClassIndex); + return thisClassIndex; + } + + public void setThisClassIndex(int thisClassIndex){ + this.thisClassIndex = thisClassIndex; + } + + public int getSuperClassIndex(){ + return superClassIndex; + } + + public void setSuperClassIndex(int superClassIndex){ + this.superClassIndex = superClassIndex; + } +} diff --git a/group11/1310368322/src/FifthHomework/jvm/constant/ClassInfo.java b/group11/1310368322/src/FifthHomework/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..13fc4101a3 --- /dev/null +++ b/group11/1310368322/src/FifthHomework/jvm/constant/ClassInfo.java @@ -0,0 +1,33 @@ +package com.coderising.jvm.constant; + +public class ClassInfo extends ConstantInfo{ + + private int type = ConstantInfo.CLASS_INFO;// ��ʾ�ó���Ϊ ���ӿڵķ������� + private int utf8Index;// CONSTANT_Class_info �ͳ����� �������ṹ�е� name_index�� name_index ָ��������һ�� CONSTANT_Utf8_info ���͵ij��� + + public ClassInfo(ConstantPool pool){ + super(pool); + } + + public int getUtf8Index(){ + return utf8Index; + } + + public void setUtf8Index(int utf8Index){ + this.utf8Index = utf8Index; + } + + @Override + public int getType(){ + return type; + } + + // �������� + public String getClassName(){ + int index = getUtf8Index(); + UTF8Info utf8Info = (UTF8Info)constantPool.getConstantInfo(index); + return utf8Info.getValue(); + } + + +} diff --git a/group11/1310368322/src/FifthHomework/jvm/constant/ConstantInfo.java b/group11/1310368322/src/FifthHomework/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..e20be200d6 --- /dev/null +++ b/group11/1310368322/src/FifthHomework/jvm/constant/ConstantInfo.java @@ -0,0 +1,34 @@ +package com.coderising.jvm.constant; + +public abstract class ConstantInfo { + public static final int UTF8_INFO = 1; + public static final int FLOAT_INFO = 4; + public static final int CLASS_INFO = 7; + public static final int STRING_INFO = 8; + public static final int FIELD_INFO = 9; + public static final int METHOD_INFO = 10; + public static final int NAME_AND_TYPE_INFO = 12; + + protected ConstantPool constantPool; + + public ConstantInfo(){ + + } + + public ConstantInfo(ConstantPool pool){// ��Ϊ�����������֮��Ҫ���� + this.constantPool = pool; + } + + public abstract int getType(); + + public ConstantPool getConstantPool(){ + return constantPool; + } + + public ConstantInfo getConstantInfo(int index){ + return this.constantPool.getConstantInfo(index);// ������õ��� ConstantInfo ���� �ı��� constantPool �е� getConstantInfo������ + // ContantInfo ���е� getConstantInfo ��������ͬ + } + + +} diff --git a/group11/1310368322/src/FifthHomework/jvm/constant/ConstantPool.java b/group11/1310368322/src/FifthHomework/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..9dbd3ed9ef --- /dev/null +++ b/group11/1310368322/src/FifthHomework/jvm/constant/ConstantPool.java @@ -0,0 +1,30 @@ +package com.coderising.jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + // �������е� ������������Ϣ + private List constantInfos = new ArrayList(); + + public ConstantPool(){ + + } + + public void addConstantInfo(ConstantInfo info){ + this.constantInfos.add(info); + } + + public ConstantInfo getConstantInfo(int index){ + return this.constantInfos.get(index); + } + + public String getUTF8String(int index){ + return ((UTF8Info)this.constantInfos.get(index)).getValue(); + } + + public Object getSize(){ + return constantInfos.size() - 1; + } + +} diff --git a/group11/1310368322/src/FifthHomework/jvm/constant/FieldRefInfo.java b/group11/1310368322/src/FifthHomework/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..731c35b118 --- /dev/null +++ b/group11/1310368322/src/FifthHomework/jvm/constant/FieldRefInfo.java @@ -0,0 +1,62 @@ +package com.coderising.jvm.constant; + +public class FieldRefInfo extends ConstantInfo{ + + private int type = ConstantInfo.FIELD_INFO; + private int classInfoIndex;// ָ�� ����Ϣ������ + private int nameAndTypeIndex;// ָ����ֶ� �� ���ֺ����� ������ + + public FieldRefInfo(ConstantPool pool){ + super(pool); + } + + public int getType() { + return type; + } + + public int getClassInfoIndex(){ + return classInfoIndex; + } + + public void setClassInfoIndex(int classInfoIndex){ + this.classInfoIndex = classInfoIndex; + } + + public int getNameAndTypeIndex(){ + return nameAndTypeIndex; + } + + public void setNameAndTypeIndex(int nameAndTypeIndex){ + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String toString(){ + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + return getClassName() + " : " + typeInfo.getName() + typeInfo.getTypeInfo() + "]"; + } + + public String getClassName(){ + ClassInfo classInfo = (ClassInfo)this.getConstantInfo(this.getClassInfoIndex()); + UTF8Info utf8Info = (UTF8Info)this.getConstantInfo(classInfo.getUtf8Index()); + return utf8Info.getValue(); + } + + public String getFieldName(){ + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(nameAndTypeIndex); + return typeInfo.getName(); + } + + public String getFieldType(){ + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(nameAndTypeIndex); + return typeInfo.getTypeInfo(); + } +} + + + + + + + + + diff --git a/group11/1310368322/src/FifthHomework/jvm/constant/MethodRefInfo.java b/group11/1310368322/src/FifthHomework/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..49d89083fd --- /dev/null +++ b/group11/1310368322/src/FifthHomework/jvm/constant/MethodRefInfo.java @@ -0,0 +1,52 @@ +package com.coderising.jvm.constant; + +public class MethodRefInfo extends ConstantInfo{ + + private int type = ConstantInfo.METHOD_INFO; + private int classInfoIndex;// ָ�� �����÷������������ + private int nameAndTypeIndex;// ָ������÷��� ���ƺ����͵����� + + public MethodRefInfo(ConstantPool pool){ + super(pool); + } + + @Override + public int getType() { + return type; + } + + public int getClassInfoIndex(){ + return classInfoIndex; + } + + public void setClassInfoIndex(int classInfoIndex){ + this.classInfoIndex = classInfoIndex; + } + + public int getNameAndTypeIndex(){ + return nameAndTypeIndex; + } + + public void setNameAndTypeIndex(int nameAndTypeIndex){ + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String getClassName(){ + ConstantPool pool = this.getConstantPool(); + ClassInfo clzInfo = (ClassInfo)pool.getConstantInfo(this.classInfoIndex); + return clzInfo.getClassName(); + } + + public String getMethodName(){ + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo)pool.getConstantInfo(this.nameAndTypeIndex); + return typeInfo.getName(); + } + + public String getParamAndReturnType(){ + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo)pool.getConstantInfo(this.nameAndTypeIndex); + return typeInfo.getTypeInfo(); + } + +} diff --git a/group11/1310368322/src/FifthHomework/jvm/constant/NameAndTypeInfo.java b/group11/1310368322/src/FifthHomework/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..8494e5e76a --- /dev/null +++ b/group11/1310368322/src/FifthHomework/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,52 @@ +package com.coderising.jvm.constant; + +public class NameAndTypeInfo extends ConstantInfo{ + + public int type = ConstantInfo.NAME_AND_TYPE_INFO; + + private int index1;// ָ�����Ƶ����� + private int index2;// ָ������(������)������ + + public NameAndTypeInfo(ConstantPool pool){ + super(pool); + } + + public int getIndex1(){ + return index1; + } + + public void setIndex1(int index1){ + this.index1 = index1; + } + + public int getIndex2(){ + return index2; + } + + public void setIndex2(int index2){ + this.index2 = index2; + } + + @Override + public int getType(){ + return type; + } + + + public String getName(){ + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info1 = (UTF8Info)pool.getConstantInfo(index1);// �õ� �������ֶ� �� Name ������ + return utf8Info1.getValue(); // ���� ������� �� �ֶ� ��Nameֵ + } + + public String getTypeInfo(){ + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info2 = (UTF8Info)pool.getConstantInfo(index2); + return utf8Info2.getValue(); + } + + public String toString(){ + return "(" + getName() + "," + getTypeInfo() + ")"; + } + +} diff --git a/group11/1310368322/src/FifthHomework/jvm/constant/NullConstantInfo.java b/group11/1310368322/src/FifthHomework/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..f0be39e410 --- /dev/null +++ b/group11/1310368322/src/FifthHomework/jvm/constant/NullConstantInfo.java @@ -0,0 +1,13 @@ +package com.coderising.jvm.constant; + +public class NullConstantInfo extends ConstantInfo{ + + public NullConstantInfo(){ + + } + @Override + public int getType() { + return -1; + } + +} diff --git a/group11/1310368322/src/FifthHomework/jvm/constant/StringInfo.java b/group11/1310368322/src/FifthHomework/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..3ff8e9402b --- /dev/null +++ b/group11/1310368322/src/FifthHomework/jvm/constant/StringInfo.java @@ -0,0 +1,30 @@ +package com.coderising.jvm.constant; + +public class StringInfo extends ConstantInfo{ + + private int type = ConstantInfo.STRING_INFO; + private int index;// ָ���ַ��������������� + + public StringInfo(ConstantPool pool){ + super(pool); + } + + + @Override + public int getType() { + return type; + } + + public int getIndex(){ + return index; + } + + public void setIndex(int index){ + this.index = index; + } + + public String toString(){ + return this.getConstantPool().getUTF8String(index); + } + +} diff --git a/group11/1310368322/src/FifthHomework/jvm/constant/UTF8Info.java b/group11/1310368322/src/FifthHomework/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..6374764b5f --- /dev/null +++ b/group11/1310368322/src/FifthHomework/jvm/constant/UTF8Info.java @@ -0,0 +1,40 @@ +package com.coderising.jvm.constant; + +public class UTF8Info extends ConstantInfo{ + + private int type = ConstantInfo.UTF8_INFO; + private int length; + private String value; + + public UTF8Info(ConstantPool pool){ + super(pool); + } + + public int getLength(){ + return length; + } + + public void setLength(int length){ + this.length = length; + } + + @Override + public int getType() { + return type; + } + + public String getValue(){ + return value; + } + + public void setValue(String value){ + this.value = value; + } + + @Override + public String toString(){ + return "UTF8Info [type=" + type + ",length" + length + ",value" + value + ")]"; + } + + +} diff --git a/group11/1310368322/src/FifthHomework/jvm/loader/ByteCodeIterator.java b/group11/1310368322/src/FifthHomework/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..4d740d8149 --- /dev/null +++ b/group11/1310368322/src/FifthHomework/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,45 @@ +package com.coderising.jvm.loader; + +public class ByteCodeIterator { + + byte[] codes; + int pos;// ά��λ�� + + public ByteCodeIterator(byte[] codes){ + this.codes = codes; + } + + public int nextU1toInt(){ + return (codes[pos++] & 0xFF); + } + + public int nextU2toInt(){ + byte [] a = new byte[]{ codes[pos++], codes[pos++]}; + return (a[0]<<8) + a[1]; + } + + public int nextU4toInt(){ + byte [] a = new byte[]{ codes[pos++], codes[pos++], codes[pos++], codes[pos++]}; + return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3]; + } + + public byte[] getByte(int length){ + byte []a = new byte[length]; + for(int i = 0; i < length; i++){ + a[i] = codes[pos++]; + } + return a; + } + public String nextU4ToHexString(){ + StringBuffer buffer = new StringBuffer(); + for(int i = 0; i < 4; i++){ + int a = codes[pos++] & 0xFF; + String strHex = Integer.toHexString(a); + if(strHex.length() < 2){ + strHex = "0" + strHex; + } + buffer.append(strHex); + } + return buffer.toString(); + } +} diff --git a/group11/1310368322/src/FifthHomework/jvm/loader/ClassFileLoader.java b/group11/1310368322/src/FifthHomework/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..6e479bbce9 --- /dev/null +++ b/group11/1310368322/src/FifthHomework/jvm/loader/ClassFileLoader.java @@ -0,0 +1,69 @@ +package com.coderising.jvm.loader; + +import java.io.BufferedInputStream; +import java.io.DataInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.junit.runners.Parameterized.Parameters; + +import com.coderising.jvm.clz.ClassFile; + +public class ClassFileLoader { + private List clzPaths = new ArrayList(); + int countForClassPath = 0; + int countForReadBinaryCode = 0; + byte [] a = new byte[10000]; + + /* ��ָ��·����ȡ�������ļ����������䱣�浽һ���ֽ������У������� + * @Parameters ָ��·�� + * @�ֽ����� + */ + public byte[] readBinaryCode(String className) throws IOException{ + DataInputStream dis = new DataInputStream( + new BufferedInputStream(new FileInputStream(className))); + for(int i = 0; dis.available() != 0; i++){ + a[i] = dis.readByte(); + countForReadBinaryCode++; + } + byte []target = new byte[countForReadBinaryCode]; + System.arraycopy(a, 0, target, 0, countForReadBinaryCode); + dis.close(); + return target; + } + + public void addClassPath(String path){ + clzPaths.add(path); + countForClassPath++; + } + + public String getClassPath(){ + StringBuffer buffer = new StringBuffer(); + for(int i = 0; i < countForClassPath; i++ ){ + if(i==countForClassPath-1){ + buffer.append(clzPaths.get(i)); + }else{ + buffer.append(clzPaths.get(i)+";"); + } + } + return buffer.toString(); + } + + public ClassFile loadClass(String className) throws IOException{ + byte[] codes = this.readBinaryCode(className); + ClassFileParser parser = new ClassFileParser(); + return parser.parse(codes); + } + + + + + + + + + + +} diff --git a/group11/1310368322/src/FifthHomework/jvm/loader/ClassFileParser.java b/group11/1310368322/src/FifthHomework/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..a2de56dfc7 --- /dev/null +++ b/group11/1310368322/src/FifthHomework/jvm/loader/ClassFileParser.java @@ -0,0 +1,130 @@ +package com.coderising.jvm.loader; + +import java.io.UnsupportedEncodingException; + +import javax.management.RuntimeErrorException; + +import com.coderising.jvm.clz.AccessFlag; +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.clz.ClassIndex; +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.FieldRefInfo; +import com.coderising.jvm.constant.MethodRefInfo; +import com.coderising.jvm.constant.NameAndTypeInfo; +import com.coderising.jvm.constant.NullConstantInfo; +import com.coderising.jvm.constant.StringInfo; +import com.coderising.jvm.constant.UTF8Info; + +/* + * ����һ���ֽ����飬����������ɶ������а��������� ClassFile + */ +public class ClassFileParser { + + // ���غ����� ClassFile + public ClassFile parse(byte[] codes){ + ClassFile clzFile = new ClassFile(); + ByteCodeIterator iter = new ByteCodeIterator(codes); + String magicNumber = iter.nextU4ToHexString(); + if(!magicNumber.equals("cafebabe")){ + return null; + } + clzFile.setMinorVersion(iter.nextU2toInt()); + clzFile.setMajorVersion(iter.nextU2toInt()); + + // ��ȡ������ + ConstantPool pool = parseConstantPool(iter); + AccessFlag accessFlag = parseAccessFlag(iter); + ClassIndex clzIndex = parseClassIndex(iter); + clzFile.setAccessFlag(accessFlag); + clzFile.setClassIndex(clzIndex); + clzFile.setConstantPool(pool);// �������м��볣���� + + + return clzFile; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter){ + int accessFlagValue = iter.nextU2toInt(); + AccessFlag accessFlag = new AccessFlag(accessFlagValue); + accessFlag.setFlagValue(accessFlagValue); + return accessFlag; + } + + private ClassIndex parseClassIndex(ByteCodeIterator iter){ + int thisClassIndex = iter.nextU2toInt(); + int superClassIndex = iter.nextU2toInt(); + ClassIndex classIndex = new ClassIndex(); + classIndex.setThisClassIndex(thisClassIndex); + classIndex.setSuperClassIndex(superClassIndex); + return classIndex; + } + + private ConstantPool parseConstantPool(ByteCodeIterator iter){ + + int constantPoolCount = iter.nextU2toInt(); + System.out.println("ConstantPool Count : " + constantPoolCount); + ConstantPool pool = new ConstantPool(); + pool.addConstantInfo(new NullConstantInfo()); + + // ����������ӳ���������Ϣ + for(int i = 1; i <= constantPoolCount-1; i++){// JVM �涨��������Ҫ ��ȥ 1����ȥ 1����������ij������� + + int tag = iter.nextU1toInt(); + if(tag == 7){ + // ���ӿڵķ������� ClassInfo + int utf8Index = iter.nextU2toInt(); + ClassInfo clzInfo= new ClassInfo(pool);// ����һ�� ClassInfo �� ���� + clzInfo.setUtf8Index(utf8Index); + pool.addConstantInfo(clzInfo); + }else if(tag == 1){ + // UTF-8 ������ַ��� + int length = iter.nextU2toInt(); + byte data[] = iter.getByte(length); + String value = null; + try { + value = new String(data,"UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + UTF8Info utf8Info = new UTF8Info(pool); + utf8Info.setLength(length); + utf8Info.setValue(value); + pool.addConstantInfo(utf8Info); + }else if(tag == 12){ + // NameAndTypeInfo �ֶλ򷽷��IJ��ַ������� + int NameIndex = iter.nextU2toInt(); + int TypeIndex = iter.nextU2toInt(); + NameAndTypeInfo nameAndType = new NameAndTypeInfo(pool); + nameAndType.setIndex1(NameIndex); + nameAndType.setIndex2(TypeIndex); + pool.addConstantInfo(nameAndType); + }else if(tag == 9){ + // FieldRefInfo �ֶεķ������� + int classInfoIndex = iter.nextU2toInt(); + int nameAndTypeIndex = iter.nextU2toInt(); + FieldRefInfo fieldRefInfo = new FieldRefInfo(pool); + fieldRefInfo.setClassInfoIndex(classInfoIndex); + fieldRefInfo.setNameAndTypeIndex(nameAndTypeIndex); + pool.addConstantInfo(fieldRefInfo); + }else if(tag == 10){ + // MethodRefInfo ���з����ķ������� + int classInfoIndex = iter.nextU2toInt(); + int nameAndTypeIndex = iter.nextU2toInt(); + MethodRefInfo methodRefInfo = new MethodRefInfo(pool); + methodRefInfo.setClassInfoIndex(classInfoIndex); + methodRefInfo.setNameAndTypeIndex(nameAndTypeIndex); + pool.addConstantInfo(methodRefInfo); + }else if(tag == 8){ + int stringIndex = iter.nextU2toInt();// ָ���ַ��������������� + StringInfo stringInfo = new StringInfo(pool); + stringInfo.setIndex(stringIndex); + pool.addConstantInfo(stringInfo); + }else{ + throw new RuntimeException("the constant pool tag" + tag + "has not been implemented yet"); + } + + } + return pool; + } +} diff --git a/group11/1310368322/src/FifthHomework/jvm/loader/TestJVM.java b/group11/1310368322/src/FifthHomework/jvm/loader/TestJVM.java new file mode 100644 index 0000000000..735e4d1dc2 --- /dev/null +++ b/group11/1310368322/src/FifthHomework/jvm/loader/TestJVM.java @@ -0,0 +1,7 @@ +package com.coderising.jvm.loader; + +public class TestJVM { + public static void main(String[] args) { + System.out.println("Hello"); + } +} diff --git a/group11/1310368322/test/FifthHomework/DataStructure_5_Stack/TestStackUtil.java b/group11/1310368322/test/FifthHomework/DataStructure_5_Stack/TestStackUtil.java new file mode 100644 index 0000000000..0b227e9ff6 --- /dev/null +++ b/group11/1310368322/test/FifthHomework/DataStructure_5_Stack/TestStackUtil.java @@ -0,0 +1,77 @@ +package DataStructure_5_Stack; + +import java.util.Stack; + +import org.junit.Assert; + +import org.junit.Test; + +public class TestStackUtil { + + @Test + public void test_reverse_1() { + Stack s = new Stack(); + for(int i = 0; i < 5; i++){ + s.push(i+1); + } + System.out.println(s.toString()); + StackUtil.reverse(s); + System.out.println(s.toString()); + } + + @Test + public void test_reverse_2() { + Stack s = new Stack(); + System.out.println(s.isEmpty()); + System.out.println(s.toString()); + StackUtil.reverse(s); + System.out.println(s.toString()); + } + + @Test + public void testRemove_1(){ + Stack actual = new Stack(); + Stack expected = new Stack(); + for(int i = 0; i < 5; i++){ + actual.push(i+1); + if(i != 2){ expected.push(i+1); } + } + StackUtil.remove(actual, 3); + Assert.assertEquals(expected, actual); + } + @Test + public void testRemove_2(){ + Stack actual = new Stack(); + Stack expected = new Stack(); + StackUtil.remove(actual, 3); + Assert.assertEquals(expected, actual); + } + + @Test + public void testGetTop(){ + Stack s = new Stack(); + for(int i = 0; i < 5; i++){ + s.push(i+1); + } + Object expected[] = {5,4,3}; + Object[] actual = StackUtil.getTop(s, 3); + Assert.assertArrayEquals(expected, actual); + + } + + + @Test + public void testIsValidPairs_1(){ + boolean actual = StackUtil.isValidPairs("([e{d}f])"); + boolean expected = true; + Assert.assertEquals(expected, actual); + } + + @Test + public void testValidPairs_2(){ + boolean actual = StackUtil.isValidPairs("([b{x]})"); + boolean expected = false; + Assert.assertEquals(expected, actual); + } + +} diff --git a/group11/1310368322/test/FifthHomework/DataStructure_5_Stack/TestSwitch.java b/group11/1310368322/test/FifthHomework/DataStructure_5_Stack/TestSwitch.java new file mode 100644 index 0000000000..a14ae1683b --- /dev/null +++ b/group11/1310368322/test/FifthHomework/DataStructure_5_Stack/TestSwitch.java @@ -0,0 +1,15 @@ +package DataStructure_5_Stack; + +public class TestSwitch { + public static void main(String[] args) { + int i = 3; + while(true){ + switch(i){ + case 1: System.out.println("1"); break; + case 3: System.out.println("3"); + case 4: System.out.println("4"); break; + } + } + + } +} diff --git a/group11/1310368322/test/FifthHomework/jvm/loader/EmployeeV1.java b/group11/1310368322/test/FifthHomework/jvm/loader/EmployeeV1.java new file mode 100644 index 0000000000..acbc34c9bb --- /dev/null +++ b/group11/1310368322/test/FifthHomework/jvm/loader/EmployeeV1.java @@ -0,0 +1,28 @@ +package com.coderising.jvm.loader; + +public class EmployeeV1 { + private String name; + private int age; + + public EmployeeV1(String name, int age){ + this.name = name; + this.age = age; + } + + public void setName(String name){ + this.name = name; + } + + public void setAge(int age){ + this.age = age; + } + + public void sayHello(){ + System.out.println("Hello, this is class Employee"); + } + + public static void main(String[] args) { + EmployeeV1 p = new EmployeeV1("Andy",29); + p.sayHello(); + } +} diff --git a/group11/1310368322/test/FifthHomework/jvm/loader/TestArray.java b/group11/1310368322/test/FifthHomework/jvm/loader/TestArray.java new file mode 100644 index 0000000000..6d78273d8c --- /dev/null +++ b/group11/1310368322/test/FifthHomework/jvm/loader/TestArray.java @@ -0,0 +1,8 @@ +package com.coderising.jvm.loader; + +public class TestArray { + public static void main(String[] args) { + byte [] a; + + } +} diff --git a/group11/1310368322/test/FifthHomework/jvm/loader/TestArrayList.java b/group11/1310368322/test/FifthHomework/jvm/loader/TestArrayList.java new file mode 100644 index 0000000000..13bfb372fb --- /dev/null +++ b/group11/1310368322/test/FifthHomework/jvm/loader/TestArrayList.java @@ -0,0 +1,14 @@ +package com.coderising.jvm.loader; + +import java.util.ArrayList; + +public class TestArrayList { + public static void main(String[] args) { + ArrayList list = new ArrayList(); + for(int i = 0; i < 5; i++){ + list.add(i); + } + System.out.println(list.size()); + } + +} diff --git a/group11/1310368322/test/FifthHomework/jvm/loader/TestByteArrayToHexString.java b/group11/1310368322/test/FifthHomework/jvm/loader/TestByteArrayToHexString.java new file mode 100644 index 0000000000..d0ef456005 --- /dev/null +++ b/group11/1310368322/test/FifthHomework/jvm/loader/TestByteArrayToHexString.java @@ -0,0 +1,15 @@ +package com.coderising.jvm.loader; + +public class TestByteArrayToHexString { + + public static void main(String[] args) { + byte [] a = { -54,-2,-70,-66}; + for(int i = 0; i < 2; i++){ + byte b = a[i]; + int j = b & 0xFF; + String s = Integer.toHexString(j); + System.out.println(s.length()); + System.out.println(s); + } + } +} diff --git a/group11/1310368322/test/FifthHomework/jvm/loader/TestByteArrayToInt.java b/group11/1310368322/test/FifthHomework/jvm/loader/TestByteArrayToInt.java new file mode 100644 index 0000000000..8bde4d5974 --- /dev/null +++ b/group11/1310368322/test/FifthHomework/jvm/loader/TestByteArrayToInt.java @@ -0,0 +1,12 @@ +package com.coderising.jvm.loader; + +public class TestByteArrayToInt { + public static void main(String[] args) { + byte a[] = {1,1}; + // System.out.println(a[0]<<7); ���ƣ�������ߵ� k λ���Ҷ˲� k ��0 + // int b = a[0]<<8 + a[1]; + int b = (a[0]<<8) + a[1]; + // System.out.println(a[0]); ���ƶ�ԭ�ڴ��е�ֵû��Ӱ�� + System.out.println(b); + } +} diff --git a/group11/1310368322/test/FifthHomework/jvm/loader/TestByteToInt.java b/group11/1310368322/test/FifthHomework/jvm/loader/TestByteToInt.java new file mode 100644 index 0000000000..2c51afb572 --- /dev/null +++ b/group11/1310368322/test/FifthHomework/jvm/loader/TestByteToInt.java @@ -0,0 +1,12 @@ +package com.coderising.jvm.loader; + +public class TestByteToInt { + public static void main(String[] args) { + byte a = -1; + int b = a;// �������a��ֱֵ�Ӹ��� b�����ᷢ���ı䣬���ڴ��У� �Ὣ ǰ�����ȫ����� 1�� -128�� byte�е��ڴ��ʾΪ�� 1000 0000��Ȼ����int���ǣ� 1111 1111 1111 1111 1111 1111 1000 0000��-128��int�Ͳ��룩 + int c = a & 0xFFFF;// ��λ�������ڴ��н��еģ�Ҳ����˵���Ƕ�a�IJ�����в����ģ� a & 0xFF �е� a ������������λ��0xFF(Ĭ����int�͵�) ��������� + System.out.println(b); + System.out.println(c); + System.out.println(a>>>24); + } +} diff --git a/group11/1310368322/test/FifthHomework/jvm/loader/TestClassFileLoader.java b/group11/1310368322/test/FifthHomework/jvm/loader/TestClassFileLoader.java new file mode 100644 index 0000000000..3971ac81cd --- /dev/null +++ b/group11/1310368322/test/FifthHomework/jvm/loader/TestClassFileLoader.java @@ -0,0 +1,174 @@ +package com.coderising.jvm.loader; + +import static org.junit.Assert.*; + +import java.io.IOException; + +import org.junit.*; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.clz.ClassIndex; +import com.coderising.jvm.constant.*; + +public class TestClassFileLoader { + static String path1 = "D:/ProgramWorld"; + static String path2 = "D:/ProgramWorld/Java"; + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/loader/EmployeeV1"; + static String path = "D:/ProgramWorld/Java/Practice/LangSi/2017������Ⱥ/bin/com/coderising/jvm/loader/EmployeeV1.class"; + static ClassFile clzFile = null; + + + + @Test + public void test() { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + loader.addClassPath(path2); + String clzPath = loader.getClassPath(); + Assert.assertEquals(path1 + ";" + path2, clzPath); + } + @Test + public void testClassFileLength() throws IOException{ + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + + String className = "D:/ProgramWorld/Java/Practice/LangSi/2017������Ⱥ/bin/com/coderising/jvm/loader/EmployeeV1.class"; + + byte[] byteCodes = loader.readBinaryCode(className); + + // ע�⣺ ����ֽ������ܺ����JVM�汾�й�ϵ������Կ�������õ��ൽ���ж�� + Assert.assertEquals(1058,byteCodes.length); + } + @Test + public void testMagicNumber() throws IOException{ + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "D:/ProgramWorld/Java/Practice/LangSi/2017������Ⱥ/bin/com/coderising/jvm/loader/EmployeeV1.class"; + byte[] byteCodes = loader.readBinaryCode(className); + byte[] codes = new byte[]{ + byteCodes[0],byteCodes[1],byteCodes[2],byteCodes[3] + }; + System.out.println("ddd"); + String actualValue = this.byteToHexString(codes); + Assert.assertEquals("cafebabe",actualValue); + + } + + private String byteToHexString(byte[] codes){ + StringBuffer buffer = new StringBuffer(); + for(int i = 0; i < codes.length; i++){ + byte b = codes[i]; + int value = b & 0xFF; + String strHex = Integer.toHexString(value); + if(strHex.length() < 2){ + strHex = "0" + strHex; + } + buffer.append(strHex); + } + return buffer.toString(); + } + + //--------------------------------------------- + + + @Test + public void testVersion() throws IOException{ + ClassFileLoader loader = new ClassFileLoader(); + String className = "D:/TestJVM.class"; + clzFile = loader.loadClass(className); + Assert.assertEquals(0, clzFile.getMinorVersion()); + Assert.assertEquals(51, clzFile.getMajorVersion()); + + } + + @Test + public void testConstantPool() throws IOException{ + + ClassFileLoader loader = new ClassFileLoader(); + clzFile = loader.loadClass(path); + ConstantPool pool = clzFile.getConstantPool(); + + Assert.assertEquals(53, pool.getSize()); + + { + ClassInfo clzInfo = (ClassInfo) pool.getConstantInfo(1); + Assert.assertEquals(2, clzInfo.getUtf8Index()); + + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(2); + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, utf8Info.getValue()); + } + { + ClassInfo clzInfo = (ClassInfo) pool.getConstantInfo(3); + Assert.assertEquals(4, clzInfo.getUtf8Index()); + + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(4); + Assert.assertEquals("java/lang/Object", utf8Info.getValue()); + } + { + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(5); + Assert.assertEquals("name", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(6); + Assert.assertEquals("Ljava/lang/String;", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(7); + Assert.assertEquals("age", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(8); + Assert.assertEquals("I", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(9); + Assert.assertEquals("", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(10); + Assert.assertEquals("(Ljava/lang/String;I)V", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(11); + Assert.assertEquals("Code", utf8Info.getValue()); + } + + { + MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(12); + Assert.assertEquals(3, methodRef.getClassInfoIndex()); + Assert.assertEquals(13, methodRef.getNameAndTypeIndex()); + } + + { + NameAndTypeInfo nameAndType = (NameAndTypeInfo) pool.getConstantInfo(13); + Assert.assertEquals(9, nameAndType.getIndex1()); + Assert.assertEquals(14, nameAndType.getIndex2()); + } + //��鼸���� + { + MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(45); + Assert.assertEquals(1, methodRef.getClassInfoIndex()); + Assert.assertEquals(46, methodRef.getNameAndTypeIndex()); + } + + { + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(53); + Assert.assertEquals("EmployeeV1.java", utf8Info.getValue()); + } + } + @Test + public void testClassIndex() throws IOException{ + + ClassFileLoader loader = new ClassFileLoader(); + clzFile = loader.loadClass(path); + ClassIndex clzIndex = clzFile.getClzIndex(); + System.out.println("clzIndex="+clzIndex); + ClassInfo thisClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getThisClassIndex()); + ClassInfo superClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getSuperClassIndex()); + System.out.println(thisClassInfo.getClassName()); + System.out.println(superClassInfo.getClassName()); + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); + Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); + } + + + + + + +} diff --git a/group11/1310368322/test/FifthHomework/jvm/loader/TestIntegerToHexString.java b/group11/1310368322/test/FifthHomework/jvm/loader/TestIntegerToHexString.java new file mode 100644 index 0000000000..b5be2a16d1 --- /dev/null +++ b/group11/1310368322/test/FifthHomework/jvm/loader/TestIntegerToHexString.java @@ -0,0 +1,10 @@ +package com.coderising.jvm.loader; + +public class TestIntegerToHexString { + public static void main(String[] args) { + int i = 10; + System.out.println(i); + String s = Integer.toHexString(i); + System.out.println(s); + } +} From b1adbb3d534db8e20f02ce2f91f1fe9ea8005600 Mon Sep 17 00:00:00 2001 From: xukai Date: Sun, 9 Apr 2017 19:53:56 +0800 Subject: [PATCH 095/203] =?UTF-8?q?jvm=E8=A7=A3=E6=9E=90=E5=B8=B8=E9=87=8F?= =?UTF-8?q?=E6=B1=A0=E3=80=81=E6=A0=88=E7=9A=84=E7=BB=83=E4=B9=A0=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xukai/coderising/array/ArrayUtilTest.java | 306 ++++++++++++++++++ .../coderising/download/FileDownloader.java | 13 +- .../xukai/coderising/litestruts/Struts.java | 6 +- .../coderising/litestruts/StrutsTest.java | 4 +- .../{common => coderising/stack}/Stack.java | 8 +- .../org/xukai/coderising/stack/StackUtil.java | 147 +++++++++ .../xukai/coderising/stack/StackUtilTest.java | 60 ++++ .../xukai/coderising/util/ReflectUtil.java | 2 +- .../common/linklist/LRUPageFrame_liuxin.java | 150 +++++++++ .../java/org/xukai/jvm/clz/AccessFlag.java | 25 ++ .../java/org/xukai/jvm/clz/ClassFile.java | 76 +++++ .../java/org/xukai/jvm/clz/ClassIndex.java | 19 ++ .../org/xukai/jvm/constant/ClassInfo.java | 24 ++ .../org/xukai/jvm/constant/ConstantInfo.java | 29 ++ .../org/xukai/jvm/constant/ConstantPool.java | 29 ++ .../org/xukai/jvm/constant/FieldRefInfo.java | 54 ++++ .../org/xukai/jvm/constant/MethodRefInfo.java | 55 ++++ .../xukai/jvm/constant/NameAndTypeInfo.java | 45 +++ .../xukai/jvm/constant/NullConstantInfo.java | 13 + .../org/xukai/jvm/constant/StringInfo.java | 26 ++ .../java/org/xukai/jvm/constant/UTF8Info.java | 32 ++ .../xukai/jvm/loader/ByteCodeIterator.java | 52 +++ .../org/xukai/jvm/loader/ClassFileLoader.java | 127 ++++++-- .../org/xukai/jvm/loader/ClassFileParser.java | 126 ++++++++ .../xukai/jvm/test/ClassFileloaderTest.java | 203 +++++++++--- .../main/java/org/xukai/jvm/util/Util.java | 25 ++ .../test/java/org/xukai/common/StackTest.java | 3 +- 27 files changed, 1580 insertions(+), 79 deletions(-) create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/array/ArrayUtilTest.java rename group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/{common => coderising/stack}/Stack.java (81%) create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/StackUtil.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/StackUtilTest.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/common/linklist/LRUPageFrame_liuxin.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/clz/AccessFlag.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/clz/ClassFile.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/clz/ClassIndex.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/ClassInfo.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/ConstantInfo.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/ConstantPool.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/FieldRefInfo.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/MethodRefInfo.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/NameAndTypeInfo.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/NullConstantInfo.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/StringInfo.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/UTF8Info.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/loader/ByteCodeIterator.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/loader/ClassFileParser.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/util/Util.java diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/array/ArrayUtilTest.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/array/ArrayUtilTest.java new file mode 100644 index 0000000000..d74b977d0e --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/array/ArrayUtilTest.java @@ -0,0 +1,306 @@ +package org.xukai.coderising.array; + +import org.junit.Test; + +public class ArrayUtilTest { + + /** + * 给定一个整形数组a , 对该数组的值进行置换 + 例如: a = [7, 9 , 30, 3] , 置换后为 [3, 30, 9,7] + 如果 a = [7, 9, 30, 3, 4] , 置换后为 [4,3, 30 , 9,7] + * @param origin + * @return + */ + public void reverseArray(int[] origin){ + for (int i = 0; i < origin.length; i++) { + if (i == origin.length/2) { + break; + } + swap(origin,i,origin.length - 1 -i); + } + } + private void swap(int[] array,int a,int b){ + array[a] = array[a] + array[b]; + array[b] = array[a] - array[b]; + array[a] = array[a] - array[b]; + } + + @Test + public void testReverseArray() { + int[] test = new int[]{7, 9, 30,-11, 3, 4}; + reverseArray(test); + for (int i = 0; i < test.length; i++) { + System.out.println(test[i]); + } + } + /** + * 现在有如下的一个数组: int oldArr[]={1,3,4,5,0,0,6,6,0,5,4,7,6,7,0,5} + * 要求将以上数组中值为0的项去掉,将不为0的值存入一个新的数组,生成的新数组为: + * {1,3,4,5,6,6,5,4,7,6,7,5} + * @param oldArray + * @return + */ + + public int[] removeZero(int[] oldArray){ + int nullIndex = 0; + for (int i = 0; i < oldArray.length; i++) { + if (oldArray[i] != 0) { + nullIndex ++; + } + } + int[] newArray = new int[nullIndex]; + nullIndex = 0; + for (int i = 0; i < oldArray.length; i++) { + if (oldArray[i] != 0) { + newArray[nullIndex] = oldArray[i]; + nullIndex++; + } + } + return newArray; + } + @Test + public void removeZero() { + int[] test = new int[]{1,3,4,5,0,0,6,6,0,5,4,7,6,7,0,5}; + int[] newArray = removeZero(test); + for (int i = 0; i < newArray.length; i++) { + System.out.println(newArray[i]); + } + } + + /** + * 给定两个已经排序好的整形数组, a1和a2 , 创建一个新的数组a3, 使得a3 包含a1和a2 的所有元素, 并且仍然是有序的 + * 例如 a1 = [3, 5, 7,8] a2 = [4, 5, 6,7] 则 a3 为[3,4,5,6,7,8] , 注意: 已经消除了重复 + * @param array1 + * @param array2 + * @return + */ + + public int[] merge(int[] array1, int[] array2){ + int index_a = 0; + int index_b = 0; + int[] array = new int[array1.length + array2.length]; + int i = 0 ; + while(index_a < array1.length && index_b < array2.length){ + if (array1[index_a] < array2[index_b]) { + array[i] = array1[index_a]; + index_a++; + i++; + } else if(array1[index_a] > array2[index_b]) { + array[i] = array2[index_b]; + index_b++; + i++; + } else { + array[i] = array1[index_a]; + i++; + index_a++; + index_b++; + } + } + if (index_a == array1.length) { + for (int j = index_b; j < array2.length; j++) { + array[i] = array2[j]; + i++; + } + } else { + for (int j = index_a; j < array1.length; j++) { + array[i] = array1[j]; + i++; + } + } + int[] result = new int[i]; + System.arraycopy(array,0,result,0,i); + return result; + } + + @Test + public void testMerge() { + int[] test1 = new int[]{2,3, 5, 7,8}; + int[] test2 = new int[]{4, 5, 6,7,8,21,33}; + int[] newArray = merge(test1,test2); + for (int i = 0; i < newArray.length; i++) { + System.out.println(newArray[i]); + } + } + /** + * 把一个已经存满数据的数组 oldArray的容量进行扩展, 扩展后的新数据大小为oldArray.length + size + * 注意,老数组的元素在新数组中需要保持 + * 例如 oldArray = [2,3,6] , size = 3,则返回的新数组为 + * [2,3,6,0,0,0] + * @param oldArray + * @param size + * @return + */ + public int[] grow(int [] oldArray, int size){ + int[] newArray = new int[oldArray.length + size]; + System.arraycopy(oldArray,0,newArray,0,oldArray.length); + + + return newArray; + } + + @Test + public void testGrow() { + int[] test1 = new int[]{2,3, 5, 7,8}; + int[] newArray = grow(test1, 5); + for (int i = 0; i < newArray.length; i++) { + System.out.println(newArray[i]); + } + } + + /** + * 斐波那契数列为:1,1,2,3,5,8,13,21...... ,给定一个最大值, 返回小于该值的数列 + * 例如, max = 15 , 则返回的数组应该为 [1,1,2,3,5,8,13] + * max = 1, 则返回空数组 [] + * @param max + * @return + */ + public int[] fibonacci(int max){ + if (max <= 1) { + return new int[0]; + } + int index_a = 1; + int index_b = 1; + int temp = 0; + int count = 2; + while ((temp = index_a + index_b) < max) { + index_a = index_b; + index_b = temp; + count++; + } + int[] newArray = new int[count]; + for (int i = count-1; i > -1 ; i--) { + newArray[i] = index_b; + temp = index_b - index_a; + index_b = index_a; + index_a = temp; + } + return newArray; + } + + @Test + public void testfibonacci() { + int[] newArray = fibonacci(15); + for (int i = 0; i < newArray.length; i++) { + System.out.println(newArray[i]); + } + } + /** + * 返回小于给定最大值max的所有素数数组 + * 例如max = 23, 返回的数组为[2,3,5,7,11,13,17,19] + * @param max + * @return + */ + public int[] getPrimes(int max){ + int[] container = new int[5]; + int count = 0; + for (int i = 3; i < max; i++) { + if (isShusu(i)) { + if (count == container.length) { + container = grow(container,container.length << 1); + } + container[count] = i; + count++; + } + + } + int[] array = new int[count]; + System.arraycopy(container,0,array,0,count); + return array; + } + @Test + public void testGetPrimes() { + int[] newArray = getPrimes(4); + for (int i = 0; i < newArray.length; i++) { + System.out.println(newArray[i]); + } + } + private boolean isShusu(int num){ + int sqrt = 1; + while (sqrt * sqrt < num){ + sqrt++; + } + for (int i = 2; i < sqrt; i++) { + if (num % i == 0) { + return false; + } + } + return true; + } + + /** + * 所谓“完数”, 是指这个数恰好等于它的因子之和,例如6=1+2+3 + * 给定一个最大值max, 返回一个数组, 数组中是小于max 的所有完数 + * @param max + * @return + */ + public int[] getPerfectNumbers(int max){ + int[] container = new int[5]; + int count = 0; + for (int i = 1; i < max; i++) { + if (isWanshu(i)) { + if (count == container.length) { + container = grow(container,container.length << 1); + } + container[count] = i; + count++; + } + + } + int[] array = new int[count]; + System.arraycopy(container,0,array,0,count); + return array; + } + @Test + public void testGetPerfectNumbers() { + int[] newArray = getPerfectNumbers(29); + for (int i = 0; i < newArray.length; i++) { + System.out.println(newArray[i]); + } +// isWanshu(6); + } + private boolean isWanshu(int num){ + int sqrt = 1; + while (sqrt * sqrt < num){ + sqrt++; + } + int sum = 1; + for (int i = 2; i < sqrt; i++) { + if (num % i == 0 ) { + sum = sum + i + (num/i); + } + } + if (sum == num) { + return true; + } + return false; + } + + /** + * 用seperator 把数组 array给连接起来 + * 例如array= [3,8,9], seperator = "-" + * 则返回值为"3-8-9" + * @param array + * @param + * @return + */ + public String join(int[] array, String seperator){ + String result = ""; + + for (int i = 0; i < array.length; i++) { + if (i != 0) { + result = result + seperator; + } + result = result + array[i]; + } + + return result; + } + @Test + public void testJoin() { + int[] test = {1, 5, 8, 4}; + String seperator = "-"; + String join = join(test, seperator); + System.out.println(join); + } + +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/download/FileDownloader.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/download/FileDownloader.java index e538a04769..13d9ab7001 100644 --- a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/download/FileDownloader.java +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/download/FileDownloader.java @@ -44,7 +44,7 @@ public void execute() throws ConnectionException { int length = conn.getContentLength(); System.out.println(length); int blockSize = length / 9; - ArrayList downloadThreads = new ArrayList<>(); + ArrayList downloadThreads = new ArrayList(); for (int i = 0; i < 9; i++) { int startPos = blockSize * i; @@ -57,9 +57,9 @@ public void execute() throws ConnectionException { downloadThreads.add(thread); thread.start(); } -// for(DownloadThread thread : downloadThreads){ -// thread.join(); -// } + for(DownloadThread thread : downloadThreads){ + thread.join(); + } } catch (Exception e) { e.printStackTrace(); @@ -70,11 +70,6 @@ public void execute() throws ConnectionException { } } listener.notifyFinished(); - try { - System.in.read(); - } catch (IOException e) { - e.printStackTrace(); - } } diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/litestruts/Struts.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/litestruts/Struts.java index 524b0634e8..3e7a4301f7 100644 --- a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/litestruts/Struts.java +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/litestruts/Struts.java @@ -55,7 +55,7 @@ public static View runAction(String actionName, Map parameters) { //根据映射关系将值放入 view.setJsp(mapping.get(result)); List gets = ReflectUtil.getMethodBeginWith(cls, "get"); - HashMap models = new HashMap<>(); + HashMap models = new HashMap(); for(Method getMethod : gets){ //调用所有getter方法 Object getFieldResult = ReflectUtil.invokeMethod(obj, getMethod); @@ -87,7 +87,7 @@ private static List initalStruts() throws ClassNotFoundException, Docume Document doc = sr.read(strutsPath); XmlParseHelper helper = new XmlParseHelper(doc); List actions = helper.getNodeByPath("//action"); - ArrayList actionsList = new ArrayList<>(); + ArrayList actionsList = new ArrayList(); for (Element action : actions){ Action obj = new Action(); String nameAttr = helper.getNodeAttrValue(action, "name"); @@ -95,7 +95,7 @@ private static List initalStruts() throws ClassNotFoundException, Docume obj.setName(nameAttr); obj.setaClass(Class.forName(classAttr)); List results = helper.getChildNodeByName(action, "result"); - HashMap map = new HashMap<>(); + HashMap map = new HashMap(); for (Element result : results){ String resultNameAttr = helper.getNodeAttrValue(result, "name"); String resultValue = helper.getNodeValue(result); diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/litestruts/StrutsTest.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/litestruts/StrutsTest.java index 53bf155c33..d9157edf95 100644 --- a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/litestruts/StrutsTest.java +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/litestruts/StrutsTest.java @@ -55,7 +55,7 @@ public void testInital() throws ClassNotFoundException { Document doc = sr.read(strutsPath); XmlParseHelper helper = new XmlParseHelper(doc); List actions = helper.getNodeByPath("//action"); - ArrayList actionsList = new ArrayList<>(); + ArrayList actionsList = new ArrayList(); for (Element action : actions){ Action obj = new Action(); String nameAttr = helper.getNodeAttrValue(action, "name"); @@ -66,7 +66,7 @@ public void testInital() throws ClassNotFoundException { for (Element result : results){ String resultNameAttr = helper.getNodeAttrValue(result, "name"); String resultValue = helper.getNodeValue(result); - HashMap map = new HashMap<>(); + HashMap map = new HashMap(); map.put("name",resultNameAttr); map.put("viewPath",resultValue); obj.setResultMapping(map); diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/common/Stack.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/Stack.java similarity index 81% rename from group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/common/Stack.java rename to group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/Stack.java index de705e1fec..dddfe7511a 100644 --- a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/common/Stack.java +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/Stack.java @@ -1,4 +1,6 @@ -package org.xukai.common; +package org.xukai.coderising.stack; + +import org.xukai.common.ArrayList; import java.util.EmptyStackException; @@ -31,4 +33,8 @@ public boolean isEmpty(){ public int size(){ return elementData.size(); } + + public void display() { + elementData.display(); + } } diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/StackUtil.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/StackUtil.java new file mode 100644 index 0000000000..d34eb23b4d --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/StackUtil.java @@ -0,0 +1,147 @@ +package org.xukai.coderising.stack; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Maps; +import org.junit.Assert; +import org.junit.Test; + +import java.util.HashMap; +import java.util.regex.Pattern; + +public class StackUtil { + + + /** + * 假设栈中的元素是Integer, 从栈顶到栈底是 : 5,4,3,2,1 调用该方法后, 元素次序变为: 1,2,3,4,5 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + */ + public static void reverse(Stack s) { + Stack stack1 = new Stack(); + while (!s.isEmpty()){ + stack1.push(s.pop()); + } + Stack stack2 = new Stack(); + while (!stack1.isEmpty()){ + stack2.push(stack1.pop()); + } + while (!stack2.isEmpty()){ + s.push(stack2.pop()); + } + } + @Test + public void testReverse(){ + Stack stack = new Stack(); + stack.push(1); + stack.push(2); + stack.push(3); + stack.push(4); + stack.push(5); + stack.display(); + reverse(stack); + stack.display(); + } + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s,Object o) { + Stack stack = new Stack(); + while (!s.isEmpty()){ + if (!s.peek().equals(o)) { + stack.push(s.pop()); + } else { + s.pop(); + } + } + while (!stack.isEmpty()){ + s.push(stack.pop()); + } + } + + @Test + public void testRemove(){ + Stack stack = new Stack(); + stack.push(1); + stack.push(2); + stack.push(3); + stack.push(4); + stack.push(5); + stack.display(); + remove(stack,3); + stack.display(); + } + + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * @param len + * @return + */ + public static Object[] getTop(Stack s,int len) { + Preconditions.checkArgument(len > 0); + Stack stack = new Stack(); + Object[] objects = new Object[Math.min(len,s.size())]; + for (int i = 0; i < len; i++) { + if (s.isEmpty()) { + break; + } + objects[i] = s.pop(); + stack.push(objects[i]); + } + while (!stack.isEmpty()){ + s.push(stack.pop()); + } + return objects; + } + + @Test + public void testGetTop(){ + Stack stack = new Stack(); + stack.push(1); + stack.push(2); + stack.push(3); + stack.push(4); + stack.push(5); + stack.display(); + Object[] objects = getTop(stack, 6); + for (int i = 0; i < objects.length; i++) { + System.out.println(objects[i]); + } + } + /** + * 字符串s 可能包含这些字符: ( ) [ ] { }, a,b,c... x,yz + * 使用堆栈检查字符串s中的括号是不是成对出现的。 + * 例如s = "([e{d}f])" , 则该字符串中的括号是成对出现, 该方法返回true + * 如果 s = "([b{x]y})", 则该字符串中的括号不是成对出现的, 该方法返回false; + * @param s + * @return + */ + public static boolean isValidPairs(String s){ + HashMap map = Maps.newHashMap(); + map.put("}","{"); + map.put(")","("); + map.put("]","["); + Stack stack = new Stack(); + char[] chars = s.toCharArray(); + for (int i = 0; i < chars.length; i++) { + if (Pattern.matches("[\\[({]{1}", chars[i]+"")) { + stack.push(chars[i]); + } + if (Pattern.matches("[\\])}]{1}", chars[i]+"") && !map.get(chars[i]+"").equals(""+stack.pop())) { + return false; + } + } + return true; + } + + @Test + public void testIsValidPairs(){ + Assert.assertTrue(isValidPairs("[d(a)](da){21}")); + Assert.assertTrue(!isValidPairs("[d(a{)}](da){21}")); + } + + +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/StackUtilTest.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/StackUtilTest.java new file mode 100644 index 0000000000..f8f2d1b4e4 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/StackUtilTest.java @@ -0,0 +1,60 @@ +package org.xukai.coderising.stack; + +import org.junit.Assert; +import org.junit.Test; + +public class StackUtilTest { + + + @Test + public void testReverse(){ + Stack stack = new Stack(); + stack.push(1); + stack.push(2); + stack.push(3); + stack.push(4); + stack.push(5); + stack.display(); + StackUtil.reverse(stack); + stack.display(); + } + + + @Test + public void testRemove(){ + Stack stack = new Stack(); + stack.push(1); + stack.push(2); + stack.push(3); + stack.push(4); + stack.push(5); + stack.display(); + StackUtil.remove(stack,3); + stack.display(); + } + + + @Test + public void testGetTop(){ + Stack stack = new Stack(); + stack.push(1); + stack.push(2); + stack.push(3); + stack.push(4); + stack.push(5); + stack.display(); + Object[] objects = StackUtil.getTop(stack, 8); + for (int i = 0; i < objects.length; i++) { + System.out.println(objects[i]); + } + Assert.assertEquals(5,objects.length); + } + + @Test + public void testIsValidPairs(){ + Assert.assertTrue(StackUtil.isValidPairs("[d(a)](da){21}")); + Assert.assertTrue(!StackUtil.isValidPairs("[d(a{)}](da){21}")); + } + + +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/util/ReflectUtil.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/util/ReflectUtil.java index 7bca0d6506..6522b30daf 100644 --- a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/util/ReflectUtil.java +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/util/ReflectUtil.java @@ -59,7 +59,7 @@ public static Method getMethod(Class cls, String methodName){ } public static List getMethodBeginWith(Class cls, String methodName){ - ArrayList methodsList = new ArrayList<>(); + ArrayList methodsList = new ArrayList(); try { Method[] methods = cls.getDeclaredMethods(); for(Method method : methods){ diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/common/linklist/LRUPageFrame_liuxin.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/common/linklist/LRUPageFrame_liuxin.java new file mode 100644 index 0000000000..5a9b7cc940 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/common/linklist/LRUPageFrame_liuxin.java @@ -0,0 +1,150 @@ +package org.xukai.common.linklist; + + +public class LRUPageFrame_liuxin { + + private static class Node { + + Node prev; + Node next; + int pageNum; + + Node() { + } + } + + private int capacity; + + private int currentSize; + private Node first;// 链表头 + private Node last;// 链表尾 + + + public LRUPageFrame_liuxin(int capacity) { + this.currentSize = 0; + this.capacity = capacity; + + } + + /** + * 获取缓存中对象 + * + * @param pageNum + * @return + */ + public void access(int pageNum) { + Node node = find(pageNum); + //在该队列中存在, 则提到队列头 + if (node != null) { + moveExistingNodeToHead(node); + } else{ + node = new Node(); + node.pageNum = pageNum; + + // 缓存容器是否已经超过大小. + if (currentSize >= capacity) { + removeLast(); + + } + addNewNodetoHead(node); + } + } + + private void addNewNodetoHead(Node node) { + if(isEmpty()){ + node.prev = null; + node.next = null; + first = node; + last = node; + } else{ + node.prev = null; + node.next = first; + first.prev = node; + first = node; + } + this.currentSize ++; + } + + private Node find(int data){ + Node node = first; + while(node != null){ + if(node.pageNum == data){ + return node; + } + node = node.next; + } + return null; + } + + + + + + + /** + * 删除链表尾部节点 表示 删除最少使用的缓存对象 + */ + private void removeLast() { + Node prev = last.prev; + prev.next = null; + last.prev = null; + last = prev; + this.currentSize --; + } + + /** + * 移动到链表头,表示这个节点是最新使用过的 + * + * @param node + */ + private void moveExistingNodeToHead(Node node) { + + if (node == first) { + + return; + } + else if(node == last){ + //当前节点是链表尾, 需要放到链表头 + Node prevNode = node.prev; + prevNode.next = null; + last.prev = null; + last = prevNode; + + } else{ + //node 在链表的中间, 把node 的前后节点连接起来 + Node prevNode = node.prev; + prevNode.next = node.next; + + Node nextNode = node.next; + nextNode.prev = prevNode; + + + } + + node.prev = null; + node.next = first; + first.prev = node; + first = node; + + } + private boolean isEmpty(){ + return (first == null) && (last == null); + } + + public String toString(){ + StringBuilder buffer = new StringBuilder(); + Node node = first; + while(node != null){ + buffer.append(node.pageNum); + + node = node.next; + if(node != null){ + buffer.append(","); + } + } + return buffer.toString(); + } + + + +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/clz/AccessFlag.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..bbfe6b2872 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/clz/AccessFlag.java @@ -0,0 +1,25 @@ +package org.xukai.jvm.clz; + +public class AccessFlag { + private int flagValue; + + public AccessFlag(int value) { + this.flagValue = value; + } + + public int getFlagValue() { + return flagValue; + } + + public void setFlagValue(int flag) { + this.flagValue = flag; + } + + public boolean isPublicClass(){ + return (this.flagValue & 0x0001) != 0; + } + public boolean isFinalClass(){ + return (this.flagValue & 0x0010) != 0; + } + +} \ No newline at end of file diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/clz/ClassFile.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..a66ec2e5a0 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/clz/ClassFile.java @@ -0,0 +1,76 @@ +package org.xukai.jvm.clz; + + +import org.xukai.jvm.constant.ClassInfo; +import org.xukai.jvm.constant.ConstantPool; + +public class ClassFile { + + private int minorVersion; + private int majorVersion; + + private AccessFlag accessFlag; + private ClassIndex clzIndex; + private ConstantPool pool; + + + public ClassIndex getClzIndex() { + return clzIndex; + } + public AccessFlag getAccessFlag() { + return accessFlag; + } + public void setAccessFlag(AccessFlag accessFlag) { + this.accessFlag = accessFlag; + } + + + + public ConstantPool getConstantPool() { + return pool; + } + public int getMinorVersion() { + return minorVersion; + } + public void setMinorVersion(int minorVersion) { + this.minorVersion = minorVersion; + } + public int getMajorVersion() { + return majorVersion; + } + public void setMajorVersion(int majorVersion) { + this.majorVersion = majorVersion; + } + public void setConstPool(ConstantPool pool) { + this.pool = pool; + + } + public void setClassIndex(ClassIndex clzIndex) { + this.clzIndex = clzIndex; + } + + + + + public void print(){ + + if(this.accessFlag.isPublicClass()){ + System.out.println("Access flag : public "); + } + System.out.println("Class Name:"+ getClassName()); + + System.out.println("Super Class Name:"+ getSuperClassName()); + + + } + + private String getClassName(){ + int thisClassIndex = this.clzIndex.getThisClassIndex(); + ClassInfo thisClass = (ClassInfo)this.getConstantPool().getConstantInfo(thisClassIndex); + return thisClass.getClassName(); + } + private String getSuperClassName(){ + ClassInfo superClass = (ClassInfo)this.getConstantPool().getConstantInfo(this.clzIndex.getSuperClassIndex()); + return superClass.getClassName(); + } +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/clz/ClassIndex.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..93ba2d7b86 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/clz/ClassIndex.java @@ -0,0 +1,19 @@ +package org.xukai.jvm.clz; + +public class ClassIndex { + private int thisClassIndex; + private int superClassIndex; + + public int getThisClassIndex() { + return thisClassIndex; + } + public void setThisClassIndex(int thisClassIndex) { + this.thisClassIndex = thisClassIndex; + } + public int getSuperClassIndex() { + return superClassIndex; + } + public void setSuperClassIndex(int superClassIndex) { + this.superClassIndex = superClassIndex; + } +} \ No newline at end of file diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/ClassInfo.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..bf7171a966 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/ClassInfo.java @@ -0,0 +1,24 @@ +package org.xukai.jvm.constant; + +public class ClassInfo extends ConstantInfo { + private int type = ConstantInfo.CLASS_INFO; + private int utf8Index ; + public ClassInfo(ConstantPool pool) { + super(pool); + } + public int getUtf8Index() { + return utf8Index; + } + public void setUtf8Index(int utf8Index) { + this.utf8Index = utf8Index; + } + public int getType() { + return type; + } + + public String getClassName() { + int index = getUtf8Index(); + UTF8Info utf8Info = (UTF8Info)constantPool.getConstantInfo(index); + return utf8Info.getValue(); + } +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/ConstantInfo.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..24323692e9 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/ConstantInfo.java @@ -0,0 +1,29 @@ +package org.xukai.jvm.constant; + +public abstract class ConstantInfo { + public static final int UTF8_INFO = 1; + public static final int FLOAT_INFO = 4; + public static final int CLASS_INFO = 7; + public static final int STRING_INFO = 8; + public static final int FIELD_INFO = 9; + public static final int METHOD_INFO = 10; + public static final int NAME_AND_TYPE_INFO = 12; + protected ConstantPool constantPool; + + public ConstantInfo(){ + + } + + public ConstantInfo(ConstantPool pool) { + this.constantPool = pool; + } + public abstract int getType(); + + public ConstantPool getConstantPool() { + return constantPool; + } + public ConstantInfo getConstantInfo(int index){ + return this.constantPool.getConstantInfo(index); + } + +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/ConstantPool.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..ff4aa4b906 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/ConstantPool.java @@ -0,0 +1,29 @@ +package org.xukai.jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List constantInfos = new ArrayList(); + + + public ConstantPool(){ + + } + public void addConstantInfo(ConstantInfo info){ + + this.constantInfos.add(info); + + } + + public ConstantInfo getConstantInfo(int index){ + return this.constantInfos.get(index); + } + public String getUTF8String(int index){ + return ((UTF8Info)this.constantInfos.get(index)).getValue(); + } + public Object getSize() { + return this.constantInfos.size() -1; + } +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/FieldRefInfo.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..f0b846f47c --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/FieldRefInfo.java @@ -0,0 +1,54 @@ +package org.xukai.jvm.constant; + +public class FieldRefInfo extends ConstantInfo{ + private int type = ConstantInfo.FIELD_INFO; + private int classInfoIndex; + private int nameAndTypeIndex; + + public FieldRefInfo(ConstantPool pool) { + super(pool); + } + public int getType() { + return type; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String toString(){ + + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + + return getClassName() +" : "+ typeInfo.getName() + ":" + typeInfo.getTypeInfo() +"]"; + } + + public String getClassName(){ + + ClassInfo classInfo = (ClassInfo) this.getConstantInfo(this.getClassInfoIndex()); + + UTF8Info utf8Info = (UTF8Info)this.getConstantInfo(classInfo.getUtf8Index()); + + return utf8Info.getValue(); + + } + + public String getFieldName(){ + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getFieldType(){ + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/MethodRefInfo.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..a0c02fedaf --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/MethodRefInfo.java @@ -0,0 +1,55 @@ +package org.xukai.jvm.constant; + +public class MethodRefInfo extends ConstantInfo { + + private int type = ConstantInfo.METHOD_INFO; + + private int classInfoIndex; + private int nameAndTypeIndex; + + public MethodRefInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String toString(){ + + return getClassName() +" : "+ this.getMethodName() + " : " + this.getParamAndReturnType() ; + } + public String getClassName(){ + ConstantPool pool = this.getConstantPool(); + ClassInfo clzInfo = (ClassInfo)pool.getConstantInfo(this.getClassInfoIndex()); + return clzInfo.getClassName(); + } + + public String getMethodName(){ + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo)pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getParamAndReturnType(){ + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo)pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } + + + +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/NameAndTypeInfo.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..c88c848d3a --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,45 @@ +package org.xukai.jvm.constant; + +public class NameAndTypeInfo extends ConstantInfo{ + public int type = ConstantInfo.NAME_AND_TYPE_INFO; + + private int index1; + private int index2; + + public NameAndTypeInfo(ConstantPool pool) { + super(pool); + } + + public int getIndex1() { + return index1; + } + public void setIndex1(int index1) { + this.index1 = index1; + } + public int getIndex2() { + return index2; + } + public void setIndex2(int index2) { + this.index2 = index2; + } + public int getType() { + return type; + } + + + public String getName(){ + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info1 = (UTF8Info)pool.getConstantInfo(index1); + return utf8Info1.getValue(); + } + + public String getTypeInfo(){ + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info2 = (UTF8Info)pool.getConstantInfo(index2); + return utf8Info2.getValue(); + } + + public String toString(){ + return "(" + getName() + "," + getTypeInfo()+")"; + } +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/NullConstantInfo.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..0aa452b866 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/NullConstantInfo.java @@ -0,0 +1,13 @@ +package org.xukai.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo(){ + + } + @Override + public int getType() { + return -1; + } + +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/StringInfo.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..31a3c52910 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/StringInfo.java @@ -0,0 +1,26 @@ +package org.xukai.jvm.constant; + +public class StringInfo extends ConstantInfo{ + private int type = ConstantInfo.STRING_INFO; + private int index; + public StringInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } + + + public String toString(){ + return this.getConstantPool().getUTF8String(index); + } + +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/UTF8Info.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..caf1c19918 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/UTF8Info.java @@ -0,0 +1,32 @@ +package org.xukai.jvm.constant; + +public class UTF8Info extends ConstantInfo{ + private int type = ConstantInfo.UTF8_INFO; + private int length ; + private String value; + public UTF8Info(ConstantPool pool) { + super(pool); + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getType() { + return type; + } + @Override + public String toString() { + return "UTF8Info [type=" + type + ", length=" + length + ", value=" + value +")]"; + } + public String getValue() { + return value; + } + public void setValue(String value) { + this.value = value; + } + + + +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/loader/ByteCodeIterator.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..26a5ecad60 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,52 @@ +package org.xukai.jvm.loader; + +import com.google.common.base.Charsets; +import com.google.common.base.Preconditions; +import org.xukai.jvm.constant.ConstantPool; +import org.xukai.jvm.util.Util; + +import java.util.Arrays; + +public class ByteCodeIterator { + + private byte[] bytes; + + private int offset; + + public ByteCodeIterator(byte[] bytes,int offset) { + this.bytes = bytes; + this.offset = offset; + } + + + public int nextToInt(int length){ + Preconditions.checkArgument(length > 0); + if ((offset + length) < bytes.length) { + int i = Util.byteToInt(Arrays.copyOfRange(bytes, offset, offset + length)); + offset = offset + length; + return i; + } + return -1; + } + + public String nextToString(int length){ + Preconditions.checkArgument(length > 0); + if ((offset + length) < bytes.length) { + String str = Util.byteToHexString(Arrays.copyOfRange(bytes,offset,offset + length)); + offset = offset + length; + return str; + } + return null; + } + + public String nextToUTF(int length){ + Preconditions.checkArgument(length > 0); + if ((offset + length) < bytes.length) { + String str = new String(Arrays.copyOfRange(bytes,offset,offset + length), Charsets.UTF_8); + offset = offset + length; + return str; + } + return null; + } + +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/loader/ClassFileLoader.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/loader/ClassFileLoader.java index 5f03628651..2f75ef3692 100644 --- a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/loader/ClassFileLoader.java +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/loader/ClassFileLoader.java @@ -1,53 +1,136 @@ package org.xukai.jvm.loader; -import com.google.common.base.Joiner; -import com.google.common.base.Splitter; -import org.xukai.coderising.util.FileUtil; - +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.xukai.jvm.clz.ClassFile; public class ClassFileLoader { private List clzPaths = new ArrayList(); - public byte[] readBinaryCode(String className) throws IOException, ClassNotFoundException { - for(String classPath : clzPaths){ - File classFile = findClassFile(classPath, className); - if (classFile.exists()) { - return FileUtil.toByteArray(classFile); - } + public byte[] readBinaryCode(String className) { + + className = className.replace('.', File.separatorChar) +".class"; + + for(String path : this.clzPaths){ + + String clzFileName = path + File.separatorChar + className; + byte[] codes = loadClassFile(clzFileName); + if(codes != null){ + return codes; + } + } + + return null; + + + + } + + private byte[] loadClassFile(String clzFileName) { + + File f = new File(clzFileName); + + try { + + return IOUtils.toByteArray(new FileInputStream(f)); + + } catch (IOException e) { + e.printStackTrace(); + return null; } - throw new ClassNotFoundException(); } + public void addClassPath(String path) { - if (path != null && !path.trim().equals("")) { - if (!path.endsWith("\\")) { - path = path + "\\"; - } - clzPaths.add(path); + if(this.clzPaths.contains(path)){ + return; } + + this.clzPaths.add(path); + } public String getClassPath(){ - Joiner joiner = Joiner.on(";"); - return joiner.join(clzPaths); + return StringUtils.join(this.clzPaths,";"); } - private File findClassFile(String classPath, String className){ - className = className.replaceAll("\\.", "/"); - return new File(classPath + "\\" + className + ".class"); + public ClassFile loadClass(String className) { + byte[] codes = this.readBinaryCode(className); + ClassFileParser parser = new ClassFileParser(); + return parser.parse(codes); + + } + + + + // ------------------------------backup------------------------ + public String getClassPath_V1(){ + + StringBuffer buffer = new StringBuffer(); + for(int i=0;i 0, "无法解析此class文件"); + + ConstantPool pool = new ConstantPool(); + pool.addConstantInfo(new NullConstantInfo()); + for (int i = 0; i < constantCount - 1; i++) { + int tag = iter.nextToInt(1); + switch (tag) { + case 1: + UTF8Info info = new UTF8Info(pool); + int length = iter.nextToInt(2); + String value = iter.nextToUTF(length); + Preconditions.checkNotNull(value); + info.setLength(length); + info.setValue(value); + pool.addConstantInfo(info); + break; + case 4: + throw new RuntimeException(); + case 7: + ClassInfo classInfo = new ClassInfo(pool); + int ut8Index = iter.nextToInt(2); + Preconditions.checkArgument(-1 != ut8Index); + classInfo.setUtf8Index(ut8Index); + pool.addConstantInfo(classInfo); + break; + case 8: + StringInfo stringInfo = new StringInfo(pool); + int index = iter.nextToInt(2); + Preconditions.checkArgument(-1 != index); + stringInfo.setIndex(index); + pool.addConstantInfo(stringInfo); + break; + case 9: + FieldRefInfo fieldRefInfo = new FieldRefInfo(pool); + int classIndex = iter.nextToInt(2); + int nameAndType = iter.nextToInt(2); + Preconditions.checkArgument(-1 != classIndex); + Preconditions.checkArgument(-1 != nameAndType); + fieldRefInfo.setClassInfoIndex(classIndex); + fieldRefInfo.setNameAndTypeIndex(nameAndType); + pool.addConstantInfo(fieldRefInfo); + break; + case 10: + MethodRefInfo methodRefInfo = new MethodRefInfo(pool); + int classIndex2 = iter.nextToInt(2); + int nameAndType2 = iter.nextToInt(2); + Preconditions.checkArgument(-1 != classIndex2); + Preconditions.checkArgument(-1 != nameAndType2); + methodRefInfo.setClassInfoIndex(classIndex2); + methodRefInfo.setNameAndTypeIndex(nameAndType2); + pool.addConstantInfo(methodRefInfo); + break; + case 12: + NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(pool); + int nameIndex = iter.nextToInt(2); + int descriptorIndex = iter.nextToInt(2); + Preconditions.checkArgument(-1 != nameIndex); + Preconditions.checkArgument(-1 != descriptorIndex); + nameAndTypeInfo.setIndex1(nameIndex); + nameAndTypeInfo.setIndex2(descriptorIndex); + pool.addConstantInfo(nameAndTypeInfo); + break; + default: + throw new RuntimeException(); + } + } + return pool; + } + + +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/test/ClassFileloaderTest.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/test/ClassFileloaderTest.java index c2112cba9c..4b4f8d807f 100644 --- a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/test/ClassFileloaderTest.java +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/test/ClassFileloaderTest.java @@ -1,31 +1,45 @@ package org.xukai.jvm.test; -import com.google.common.base.Splitter; +import com.google.common.base.Charsets; +import com.google.common.base.Preconditions; import org.junit.After; -import org.junit.Assert; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import org.xukai.coderising.util.FileUtil; +import org.xukai.jvm.clz.ClassFile; +import org.xukai.jvm.clz.ClassIndex; +import org.xukai.jvm.constant.ClassInfo; +import org.xukai.jvm.constant.ConstantPool; +import org.xukai.jvm.constant.MethodRefInfo; +import org.xukai.jvm.constant.NameAndTypeInfo; +import org.xukai.jvm.constant.NullConstantInfo; +import org.xukai.jvm.constant.UTF8Info; +import org.xukai.jvm.loader.ByteCodeIterator; import org.xukai.jvm.loader.ClassFileLoader; +import org.xukai.jvm.loader.ClassFileParser; +import org.xukai.jvm.util.Util; -import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.channels.FileChannel; +import java.util.Arrays; public class ClassFileloaderTest { + private static final String FULL_QUALIFIED_CLASS_NAME = "org/xukai/jvm/test/EmployeeV1"; + static String path1 = "D:\\java\\IDEA-Workspace\\coding2017\\group19\\527220084\\xukai_coding\\coding-common\\target\\classes"; static String path2 = "C:\temp"; - + static ClassFile clzFile = null; + static { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "org.xukai.jvm.test.EmployeeV1"; + + clzFile = loader.loadClass(className); + clzFile.print(); + } + @Before public void setUp() throws Exception { @@ -49,7 +63,7 @@ public void testClassPath(){ } @Test - public void testClassFileLength() throws IOException, ClassNotFoundException { + public void testClassFileLength() { ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); @@ -65,48 +79,159 @@ public void testClassFileLength() throws IOException, ClassNotFoundException { @Test - public void testMagicNumber() throws IOException, ClassNotFoundException { + public void testMagicNumber(){ ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); String className = "org.xukai.jvm.test.EmployeeV1"; byte[] byteCodes = loader.readBinaryCode(className); byte[] codes = new byte[]{byteCodes[0],byteCodes[1],byteCodes[2],byteCodes[3]}; - - + + String acctualValue = this.byteToHexString(codes); Assert.assertEquals("cafebabe", acctualValue); } - private File findClassFile(String classPath, String className){ - className = className.replaceAll("\\.", "/"); - System.out.println(classPath + "\\" + className + ".class"); - return new File(classPath + "\\" + className + ".class"); + @Test + public void testParse(){ + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "org.xukai.jvm.test.EmployeeV1"; + byte[] bytes = loader.readBinaryCode(className); + + ClassFileParser parser = new ClassFileParser(); + parser.parse(bytes); + + + } - @Test - public void testFile() throws IOException { - File file = findClassFile(path1, "org.xukai.jvm.test.EmployeeV1"); - Assert.assertTrue(file.exists()); - byte[] bytes = FileUtil.toByteArray(file); - System.out.println(bytes.length); + private ClassFile parse(byte[] bytes){ + ByteCodeIterator iter = new ByteCodeIterator(bytes, 0); + String magic = iter.nextToString(4); + Preconditions.checkArgument(magic.equals("cafebabe"),"无法解析此class文件"); + + ClassFile classFile = new ClassFile(); + + int minor_version = iter.nextToInt(2); + classFile.setMinorVersion(minor_version); + int major_version = iter.nextToInt(2); + System.out.println(minor_version + "_" + major_version); + classFile.setMajorVersion(major_version); + + + + + return null; } + private String byteToHexString(byte[] codes ){ + StringBuffer buffer = new StringBuffer(); + for(int i=0;i", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(10); + Assert.assertEquals("(Ljava/lang/String;I)V", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(11); + Assert.assertEquals("Code", utf8Info.getValue()); + } + + { + MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(12); + Assert.assertEquals(3, methodRef.getClassInfoIndex()); + Assert.assertEquals(13, methodRef.getNameAndTypeIndex()); + } + + { + NameAndTypeInfo nameAndType = (NameAndTypeInfo) pool.getConstantInfo(13); + Assert.assertEquals(9, nameAndType.getIndex1()); + Assert.assertEquals(14, nameAndType.getIndex2()); + } + //抽查几个吧 + { + MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(45); + Assert.assertEquals(1, methodRef.getClassInfoIndex()); + Assert.assertEquals(46, methodRef.getNameAndTypeIndex()); + } + + { + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(53); + Assert.assertEquals("EmployeeV1.java", utf8Info.getValue()); + } + } + @Test + public void testClassIndex(){ + + ClassIndex clzIndex = clzFile.getClzIndex(); + ClassInfo thisClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getThisClassIndex()); + ClassInfo superClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getSuperClassIndex()); + + + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); + Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); + } + + } diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/util/Util.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/util/Util.java new file mode 100644 index 0000000000..2ce88b8f57 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/util/Util.java @@ -0,0 +1,25 @@ +package org.xukai.jvm.util; + +public class Util { + + public static int byteToInt(byte[] codes){ + String s1 = byteToHexString(codes); + return Integer.parseInt(s1,16); + } + + + + public static String byteToHexString(byte[] codes ){ + StringBuffer buffer = new StringBuffer(); + for(int i=0;i Date: Sun, 9 Apr 2017 20:02:02 +0800 Subject: [PATCH 096/203] =?UTF-8?q?=E7=AC=AC=E4=BA=94=E5=91=A8=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/com/coding/basic/stack/Stack.java | 68 ++++++++++ .../src/com/coding/basic/stack/StackUtil.java | 128 ++++++++++++++++++ .../com/coderising/jvm/clz/AccessFlag.java | 25 ++++ .../src/com/coderising/jvm/clz/ClassFile.java | 75 ++++++++++ .../com/coderising/jvm/clz/ClassIndex.java | 19 +++ .../coderising/jvm/constant/ClassInfo.java | 24 ++++ .../coderising/jvm/constant/ConstantInfo.java | 34 +++++ .../coderising/jvm/constant/ConstantPool.java | 29 ++++ .../coderising/jvm/constant/FieldRefInfo.java | 54 ++++++++ .../jvm/constant/MethodRefInfo.java | 56 ++++++++ .../jvm/constant/NameAndTypeInfo.java | 49 +++++++ .../jvm/constant/NullConstantInfo.java | 13 ++ .../coderising/jvm/constant/StringInfo.java | 26 ++++ .../com/coderising/jvm/constant/UTF8Info.java | 32 +++++ .../jvm/loader/ByteCodeIterator.java | 34 +++++ .../jvm/loader/ClassFileLoader.java | 10 ++ .../jvm/loader/ClassFileParser.java | 109 +++++++++++++++ .../jvm/test/ClassFileloaderTest.java | 108 +++++++++++++++ .../src/com/coderising/jvm/util/Util.java | 24 ++++ 19 files changed, 917 insertions(+) create mode 100644 group27/513274874/data-structure/src/com/coding/basic/stack/Stack.java create mode 100755 group27/513274874/data-structure/src/com/coding/basic/stack/StackUtil.java create mode 100755 group27/513274874/mini-jvm/src/com/coderising/jvm/clz/AccessFlag.java create mode 100755 group27/513274874/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java create mode 100755 group27/513274874/mini-jvm/src/com/coderising/jvm/clz/ClassIndex.java create mode 100755 group27/513274874/mini-jvm/src/com/coderising/jvm/constant/ClassInfo.java create mode 100755 group27/513274874/mini-jvm/src/com/coderising/jvm/constant/ConstantInfo.java create mode 100755 group27/513274874/mini-jvm/src/com/coderising/jvm/constant/ConstantPool.java create mode 100755 group27/513274874/mini-jvm/src/com/coderising/jvm/constant/FieldRefInfo.java create mode 100755 group27/513274874/mini-jvm/src/com/coderising/jvm/constant/MethodRefInfo.java create mode 100755 group27/513274874/mini-jvm/src/com/coderising/jvm/constant/NameAndTypeInfo.java create mode 100755 group27/513274874/mini-jvm/src/com/coderising/jvm/constant/NullConstantInfo.java create mode 100755 group27/513274874/mini-jvm/src/com/coderising/jvm/constant/StringInfo.java create mode 100755 group27/513274874/mini-jvm/src/com/coderising/jvm/constant/UTF8Info.java create mode 100755 group27/513274874/mini-jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java create mode 100755 group27/513274874/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java create mode 100755 group27/513274874/mini-jvm/src/com/coderising/jvm/util/Util.java diff --git a/group27/513274874/data-structure/src/com/coding/basic/stack/Stack.java b/group27/513274874/data-structure/src/com/coding/basic/stack/Stack.java new file mode 100644 index 0000000000..4a0980079b --- /dev/null +++ b/group27/513274874/data-structure/src/com/coding/basic/stack/Stack.java @@ -0,0 +1,68 @@ + +package com.coding.basic.stack; + +import com.coding.basic.List; +import com.coding.basic.array.ArrayList; + +/** + * author zhougd 20170306 + * + */ +public class Stack { + private List elementData = new ArrayList(); + + + public Stack() { + } + + /** + * 入栈 + * @param o + */ + public void push(Object o){ + elementData.add(o); + } + + /** + * 出栈 + * @return + */ + public Object pop(){ + if(this.isEmpty()){ + throw new IndexOutOfBoundsException("stack is empty!"); + } + Object element = elementData.get(size()-1); + elementData.remove(size()-1); + return element; + } + + /** + * 查看栈顶元素 + * @return Object + */ + public Object peek(){ + if(this.isEmpty()){ + throw new IndexOutOfBoundsException("stack is empty!"); + } + Object element = elementData.get(size()-1); + return element; + } + + /** + * 查看栈是否为空 + * @return boolean + */ + public boolean isEmpty(){ + + return elementData == null || elementData.size()<=0; + + } + + /** + * 获取栈大小 + * @return + */ + public int size(){ + return elementData.size(); + } +} \ No newline at end of file diff --git a/group27/513274874/data-structure/src/com/coding/basic/stack/StackUtil.java b/group27/513274874/data-structure/src/com/coding/basic/stack/StackUtil.java new file mode 100755 index 0000000000..e53e38ca4b --- /dev/null +++ b/group27/513274874/data-structure/src/com/coding/basic/stack/StackUtil.java @@ -0,0 +1,128 @@ +package com.coding.basic.stack; + +public class StackUtil { + + /** + * 假设栈中的元素是Integer, 从栈顶到栈底是 : 5,4,3,2,1 调用该方法后, 元素次序变为: 1,2,3,4,5 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + */ + public static void reverse(Stack s) { + Stack temp = new Stack(); + //先清空s + while (!s.isEmpty()) { + temp.push(s.pop()); + } + + } + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s, Object o) { + Stack temp = new Stack(); + while (!s.isEmpty()) { + Object a = s.pop(); + if (a.equals(o)) { + break; + } + temp.push(a); + } + + while (!temp.isEmpty()) { + s.push(temp.pop()); + } + + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param len + * @return + */ + public static Object[] getTop(Stack s, int len) { + + Object[] os = null; + if (len > 0) { + os = new Object[len]; + } else { + return null; + } + + Stack temp = new Stack(); + for (int i = 0; i < len; i++) { + if (!s.isEmpty()) { + Object o = s.pop(); + os[i] = o; + temp.push(o); + } else { + break; + } + } + + while (!temp.isEmpty()) { + s.push(temp.pop()); + } + return os; + } + + /** + * 字符串s 可能包含这些字符: ( ) [ ] { }, a,b,c... x,yz + * 使用堆栈检查字符串s中的括号是不是成对出现的。 + * 例如s = "([e{d}f])" , 则该字符串中的括号是成对出现, 该方法返回true + * 如果 s = "([b{x]y})", 则该字符串中的括号不是成对出现的, 该方法返回false; + * + * @param s + * @return + */ + public static boolean isValidPairs(String s) { + if (s == null || s.trim().equals("")) return false; + Stack stack = new Stack(); + byte[] bytes = s.getBytes(); + byte temp; + for (byte b : bytes) { + switch (b) { + case '(': + case '[': + case '{': + stack.push(b); + break; + + case ')': + temp = (byte) stack.peek(); + if (temp != '(') { + return false; + } else { + stack.pop(); + } + break; + case ']': + temp = (byte) stack.peek(); + if (temp != ']') { + return false; + } else { + stack.pop(); + } + break; + case '}': + temp = (byte) stack.peek(); + if (temp != ']') { + return false; + } else { + stack.pop(); + } + break; + + } + + if(stack.isEmpty() ) return true; + } + + return false; + } + + +} diff --git a/group27/513274874/mini-jvm/src/com/coderising/jvm/clz/AccessFlag.java b/group27/513274874/mini-jvm/src/com/coderising/jvm/clz/AccessFlag.java new file mode 100755 index 0000000000..faae056835 --- /dev/null +++ b/group27/513274874/mini-jvm/src/com/coderising/jvm/clz/AccessFlag.java @@ -0,0 +1,25 @@ +package com.coderising.jvm.clz; + +public class AccessFlag { + private int flagValue; + + public AccessFlag(int value) { + this.flagValue = value; + } + + public int getFlagValue() { + return flagValue; + } + + public void setFlagValue(int flag) { + this.flagValue = flag; + } + + public boolean isPublicClass(){ + return (this.flagValue & 0x0001) != 0; + } + public boolean isFinalClass(){ + return (this.flagValue & 0x0010) != 0; + } + +} \ No newline at end of file diff --git a/group27/513274874/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java b/group27/513274874/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java new file mode 100755 index 0000000000..650ca8375d --- /dev/null +++ b/group27/513274874/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java @@ -0,0 +1,75 @@ +package com.coderising.jvm.clz; + +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantPool; + +public class ClassFile { + + private int minorVersion; + private int majorVersion; + + private AccessFlag accessFlag; + private ClassIndex clzIndex; + private ConstantPool pool; + + + public ClassIndex getClzIndex() { + return clzIndex; + } + public AccessFlag getAccessFlag() { + return accessFlag; + } + public void setAccessFlag(AccessFlag accessFlag) { + this.accessFlag = accessFlag; + } + + + + public ConstantPool getConstantPool() { + return pool; + } + public int getMinorVersion() { + return minorVersion; + } + public void setMinorVersion(int minorVersion) { + this.minorVersion = minorVersion; + } + public int getMajorVersion() { + return majorVersion; + } + public void setMajorVersion(int majorVersion) { + this.majorVersion = majorVersion; + } + public void setConstPool(ConstantPool pool) { + this.pool = pool; + + } + public void setClassIndex(ClassIndex clzIndex) { + this.clzIndex = clzIndex; + } + + + + + public void print(){ + + if(this.accessFlag.isPublicClass()){ + System.out.println("Access flag : public "); + } + System.out.println("Class Name:"+ getClassName()); + + System.out.println("Super Class Name:"+ getSuperClassName()); + + + } + + private String getClassName(){ + int thisClassIndex = this.clzIndex.getThisClassIndex(); + ClassInfo thisClass = (ClassInfo)this.getConstantPool().getConstantInfo(thisClassIndex); + return thisClass.getClassName(); + } + private String getSuperClassName(){ + ClassInfo superClass = (ClassInfo)this.getConstantPool().getConstantInfo(this.clzIndex.getSuperClassIndex()); + return superClass.getClassName(); + } +} diff --git a/group27/513274874/mini-jvm/src/com/coderising/jvm/clz/ClassIndex.java b/group27/513274874/mini-jvm/src/com/coderising/jvm/clz/ClassIndex.java new file mode 100755 index 0000000000..e424f284b3 --- /dev/null +++ b/group27/513274874/mini-jvm/src/com/coderising/jvm/clz/ClassIndex.java @@ -0,0 +1,19 @@ +package com.coderising.jvm.clz; + +public class ClassIndex { + private int thisClassIndex; + private int superClassIndex; + + public int getThisClassIndex() { + return thisClassIndex; + } + public void setThisClassIndex(int thisClassIndex) { + this.thisClassIndex = thisClassIndex; + } + public int getSuperClassIndex() { + return superClassIndex; + } + public void setSuperClassIndex(int superClassIndex) { + this.superClassIndex = superClassIndex; + } +} \ No newline at end of file diff --git a/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/ClassInfo.java b/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/ClassInfo.java new file mode 100755 index 0000000000..aea9048ea4 --- /dev/null +++ b/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/ClassInfo.java @@ -0,0 +1,24 @@ +package com.coderising.jvm.constant; + +public class ClassInfo extends ConstantInfo { + private int type = ConstantInfo.CLASS_INFO; + private int utf8Index ; + public ClassInfo(ConstantPool pool) { + super(pool); + } + public int getUtf8Index() { + return utf8Index; + } + public void setUtf8Index(int utf8Index) { + this.utf8Index = utf8Index; + } + public int getType() { + return type; + } + + public String getClassName() { + int index = getUtf8Index(); + UTF8Info utf8Info = (UTF8Info)constantPool.getConstantInfo(index); + return utf8Info.getValue(); + } +} diff --git a/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/ConstantInfo.java b/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/ConstantInfo.java new file mode 100755 index 0000000000..5d66317801 --- /dev/null +++ b/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/ConstantInfo.java @@ -0,0 +1,34 @@ +package com.coderising.jvm.constant; + +public abstract class ConstantInfo { + public static final int UTF8_INFO = 1; + public static final int FLOAT_INFO = 4; + public static final int CLASS_INFO = 7; + public static final int STRING_INFO = 8; + public static final int FIELD_INFO = 9; + public static final int METHOD_INFO = 10; + public static final int NAME_AND_TYPE_INFO = 12; + protected ConstantPool constantPool; + + public ConstantInfo(){ + + } + + public ConstantInfo(ConstantPool pool) { + this.constantPool = pool; + } + public abstract int getType(); + + @Override + public String toString(){ + return super.toString(); + } + + public ConstantPool getConstantPool() { + return constantPool; + } + public ConstantInfo getConstantInfo(int index){ + return this.constantPool.getConstantInfo(index); + } + +} diff --git a/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/ConstantPool.java b/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/ConstantPool.java new file mode 100755 index 0000000000..f92c8028b9 --- /dev/null +++ b/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/ConstantPool.java @@ -0,0 +1,29 @@ +package com.coderising.jvm.constant; + +import java.util.LinkedList; +import java.util.List; + +public class ConstantPool { + + private List constantInfos = new LinkedList(); + + + public ConstantPool(){ + + } + public void addConstantInfo(ConstantInfo info){ + + this.constantInfos.add(info); + + } + + public ConstantInfo getConstantInfo(int index){ + return this.constantInfos.get(index); + } + public String getUTF8String(int index){ + return ((UTF8Info)this.constantInfos.get(index)).getValue(); + } + public Object getSize() { + return this.constantInfos.size() -1; + } +} diff --git a/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/FieldRefInfo.java b/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/FieldRefInfo.java new file mode 100755 index 0000000000..65475e194c --- /dev/null +++ b/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/FieldRefInfo.java @@ -0,0 +1,54 @@ +package com.coderising.jvm.constant; + +public class FieldRefInfo extends ConstantInfo{ + private int type = ConstantInfo.FIELD_INFO; + private int classInfoIndex; + private int nameAndTypeIndex; + + public FieldRefInfo(ConstantPool pool) { + super(pool); + } + public int getType() { + return type; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String toString(){ + + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + + return getClassName() +" : "+ typeInfo.getName() + ":" + typeInfo.getTypeInfo() +"]"; + } + + public String getClassName(){ + + ClassInfo classInfo = (ClassInfo) this.getConstantInfo(this.getClassInfoIndex()); + + UTF8Info utf8Info = (UTF8Info)this.getConstantInfo(classInfo.getUtf8Index()); + + return utf8Info.getValue(); + + } + + public String getFieldName(){ + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getFieldType(){ + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } +} diff --git a/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/MethodRefInfo.java b/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/MethodRefInfo.java new file mode 100755 index 0000000000..65c586916c --- /dev/null +++ b/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/MethodRefInfo.java @@ -0,0 +1,56 @@ +package com.coderising.jvm.constant; + +public class MethodRefInfo extends ConstantInfo { + + private int type = ConstantInfo.METHOD_INFO; + + private int classIndex; + private int nameAndTypeIndex; + + public MethodRefInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + public int getClassInfoIndex() { + return classIndex; + } + public void setClassIndex(int classIndex) { + this.classIndex = classIndex; + } + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + @Override + public String toString(){ + + return getClassName() +" : "+ this.getMethodName() + " : " + this.getParamAndReturnType() ; + } + public String getClassName(){ + ConstantPool pool = this.getConstantPool(); + ClassInfo clzInfo = (ClassInfo)pool.getConstantInfo(this.getClassInfoIndex()); + return clzInfo.getClassName(); + } + + public String getMethodName(){ + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo)pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getParamAndReturnType(){ + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo)pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } + + + +} diff --git a/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/NameAndTypeInfo.java b/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/NameAndTypeInfo.java new file mode 100755 index 0000000000..b9d9185ef8 --- /dev/null +++ b/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,49 @@ +package com.coderising.jvm.constant; + +public class NameAndTypeInfo extends ConstantInfo{ + public int type = ConstantInfo.NAME_AND_TYPE_INFO; + + private int name_index; + private int descriptor_index; + + public NameAndTypeInfo(ConstantPool pool) { + super(pool); + } + + public int getNameIndex() { + return name_index; + } + + public void setNameIndex(int name_index) { + this.name_index = name_index; + } + + public int getDescriptorIndex() { + return descriptor_index; + } + + public void setDescriptorIndex(int descriptor_index) { + this.descriptor_index = descriptor_index; + } + + public int getType() { + return type; + } + + + public String getName(){ + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info1 = (UTF8Info)pool.getConstantInfo(name_index); + return utf8Info1.getValue(); + } + + public String getTypeInfo(){ + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info2 = (UTF8Info)pool.getConstantInfo(descriptor_index); + return utf8Info2.getValue(); + } + + public String toString(){ + return "(" + getName() + "," + getTypeInfo()+")"; + } +} diff --git a/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/NullConstantInfo.java b/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/NullConstantInfo.java new file mode 100755 index 0000000000..936736016f --- /dev/null +++ b/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/NullConstantInfo.java @@ -0,0 +1,13 @@ +package com.coderising.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo(){ + + } + @Override + public int getType() { + return -1; + } + +} diff --git a/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/StringInfo.java b/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/StringInfo.java new file mode 100755 index 0000000000..f1f8eb4ed4 --- /dev/null +++ b/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/StringInfo.java @@ -0,0 +1,26 @@ +package com.coderising.jvm.constant; + +public class StringInfo extends ConstantInfo{ + private int type = ConstantInfo.STRING_INFO; + private int index; + public StringInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } + + + public String toString(){ + return this.getConstantPool().getUTF8String(index); + } + +} diff --git a/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/UTF8Info.java b/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/UTF8Info.java new file mode 100755 index 0000000000..5cac9f04f7 --- /dev/null +++ b/group27/513274874/mini-jvm/src/com/coderising/jvm/constant/UTF8Info.java @@ -0,0 +1,32 @@ +package com.coderising.jvm.constant; + +public class UTF8Info extends ConstantInfo{ + private int type = ConstantInfo.UTF8_INFO; + private int length ; + private String value; + public UTF8Info(ConstantPool pool) { + super(pool); + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getType() { + return type; + } + @Override + public String toString() { + return "UTF8Info [type=" + type + ", length=" + length + ", value=" + value +")]"; + } + public String getValue() { + return value; + } + public void setValue(String value) { + this.value = value; + } + + + +} diff --git a/group27/513274874/mini-jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java b/group27/513274874/mini-jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java new file mode 100755 index 0000000000..e4c5c83681 --- /dev/null +++ b/group27/513274874/mini-jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,34 @@ +package com.coderising.jvm.loader; + +import com.coderising.jvm.util.Util; + +import java.util.Arrays; + +public class ByteCodeIterator { + private byte[] code ; + private int pos = 0; + + public ByteCodeIterator(byte[] code) { + this.code = code; + } + + public int nextU1Int(){ + return Util.byteToInt(new byte[]{code[pos++]}); + } + public int nextU2Int(){ + + return Util.byteToInt(new byte[]{code[pos++],code[pos++]}); + } + public String nextU4HexString(){ + return Util.byteToHexString(new byte[]{code[pos++],code[pos++],code[pos++],code[pos++]}); + } + + public byte[] getBytes(int length){ + if(pos+length >= code.length){ + throw new IndexOutOfBoundsException("not enough bytes!"); + } + byte[] bytes = Arrays.copyOfRange(code,pos,pos+length); + pos += length; + return bytes; + } +} diff --git a/group27/513274874/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java b/group27/513274874/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java index 4b5d12b49f..4d146e14c2 100755 --- a/group27/513274874/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java +++ b/group27/513274874/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -1,5 +1,7 @@ package com.coderising.jvm.loader; +import com.coderising.jvm.clz.ClassFile; + import java.io.*; import java.util.ArrayList; import java.util.List; @@ -54,4 +56,12 @@ public String getClassPath() { return clazzPaths; } + public ClassFile loadClass(String className) { + byte[] codes = this.readBinaryCode(className); + ClassFileParser parser = new ClassFileParser(); + return parser.parse(codes); + + } + + } diff --git a/group27/513274874/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java b/group27/513274874/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java new file mode 100755 index 0000000000..0c35bca807 --- /dev/null +++ b/group27/513274874/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java @@ -0,0 +1,109 @@ +package com.coderising.jvm.loader; + +import com.coderising.jvm.clz.AccessFlag; +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.clz.ClassIndex; +import com.coderising.jvm.constant.*; + +import java.io.UnsupportedEncodingException; + +public class ClassFileParser { + + public ClassFile parse(byte[] codes) { + + ClassFile clzFile = new ClassFile(); + ByteCodeIterator iterator = new ByteCodeIterator(codes); + + String magicNumber = iterator.nextU4HexString(); + if (!"cafebabe".equals(magicNumber)) { + return null; + } + + clzFile.setMinorVersion(iterator.nextU2Int()); + clzFile.setMajorVersion(iterator.nextU2Int()); + + clzFile.setConstPool(parseConstantPool(iterator)); + clzFile.setAccessFlag(parseAccessFlag(iterator)); + clzFile.setClassIndex(parseClassIndex(iterator)); + + return clzFile; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + AccessFlag accessFlag = new AccessFlag(iter.nextU2Int()); + return accessFlag; + } + + private ClassIndex parseClassIndex(ByteCodeIterator iter) { + ClassIndex classIndex = new ClassIndex(); + classIndex.setThisClassIndex(iter.nextU2Int()); + classIndex.setSuperClassIndex(iter.nextU2Int()); + + return classIndex; + + } + + private ConstantPool parseConstantPool(ByteCodeIterator iter) { + int constantCount = iter.nextU2Int(); + ConstantPool pool = new ConstantPool(); + //因为常量池索引是#1开始,所以此处常量池的第0位设置成空 + pool.addConstantInfo(new NullConstantInfo()); + for (int i = 1; i < constantCount; i++) { + int tag = iter.nextU1Int(); + if (tag == 7) { + //CONSTANT_Class_info + ClassInfo classInfo = new ClassInfo(pool); + classInfo.setUtf8Index(iter.nextU2Int()); + pool.addConstantInfo(classInfo); + } else if (tag == 1) { + //CONSTANT_Utf8_info + UTF8Info utf8Info = new UTF8Info(pool); + int len = iter.nextU2Int(); + utf8Info.setLength(len); + byte[] utf8Bytes = iter.getBytes(len); + String utf8Value = null; + try { + utf8Value = new String(utf8Bytes, "UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + utf8Info.setValue(utf8Value); + + pool.addConstantInfo(utf8Info); + } else if (tag == 8) { + //CONSTANT_String_info + StringInfo stringInfo = new StringInfo(pool); + stringInfo.setIndex(iter.nextU2Int()); + + pool.addConstantInfo(stringInfo); + } else if (tag == 9) { + //CONSTANT_Fieldref_info + FieldRefInfo fieldRefInfo = new FieldRefInfo(pool); + fieldRefInfo.setClassInfoIndex(iter.nextU2Int()); + fieldRefInfo.setNameAndTypeIndex(iter.nextU2Int()); + + pool.addConstantInfo(fieldRefInfo); + } else if (tag == 10) { + //CONSTANT_Methodref_info + MethodRefInfo methodRefInfo = new MethodRefInfo(pool); + methodRefInfo.setClassIndex(iter.nextU2Int()); + methodRefInfo.setNameAndTypeIndex(iter.nextU2Int()); + + pool.addConstantInfo(methodRefInfo); + } else if (tag == 12) { + //CONSTANT_NameAndType_info + NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(pool); + nameAndTypeInfo.setNameIndex(iter.nextU2Int()); + nameAndTypeInfo.setDescriptorIndex(iter.nextU2Int()); + + pool.addConstantInfo(nameAndTypeInfo); + } else { + throw new RuntimeException("constant pool hasn't this tag : " + tag); + } + + } + return pool; + } + + +} diff --git a/group27/513274874/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group27/513274874/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java index e5d2bd89c5..b3b281bc8a 100755 --- a/group27/513274874/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java +++ b/group27/513274874/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -1,5 +1,8 @@ package com.coderising.jvm.test; +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.clz.ClassIndex; +import com.coderising.jvm.constant.*; import com.coderising.jvm.loader.ClassFileLoader; import org.junit.After; import org.junit.Assert; @@ -13,9 +16,20 @@ public class ClassFileloaderTest { + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + static String path1 = "/Users/guodongchow/Desktop/coding2017/projects/mini-jvm/bin/"; static String path2 = "/Users/guodongchow/bin"; + static ClassFile clzFile = null; + static { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "com.coderising.jvm.test.EmployeeV1"; + + clzFile = loader.loadClass(className); + clzFile.print(); + } @Before @@ -87,5 +101,99 @@ private String byteToHexString(byte[] codes ){ } return buffer.toString(); } + + + + + + + @Test + public void testVersion(){ + + Assert.assertEquals(0, clzFile.getMinorVersion()); + Assert.assertEquals(52, clzFile.getMajorVersion()); + + } + + @Test + public void testConstantPool(){ + + ConstantPool pool = clzFile.getConstantPool(); + + Assert.assertEquals(53, pool.getSize()); + + { + ClassInfo clzInfo = (ClassInfo) pool.getConstantInfo(1); + Assert.assertEquals(2, clzInfo.getUtf8Index()); + + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(2); + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, utf8Info.getValue()); + } + { + ClassInfo clzInfo = (ClassInfo) pool.getConstantInfo(3); + Assert.assertEquals(4, clzInfo.getUtf8Index()); + + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(4); + Assert.assertEquals("java/lang/Object", utf8Info.getValue()); + } + { + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(5); + Assert.assertEquals("name", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(6); + Assert.assertEquals("Ljava/lang/String;", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(7); + Assert.assertEquals("age", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(8); + Assert.assertEquals("I", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(9); + Assert.assertEquals("", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(10); + Assert.assertEquals("(Ljava/lang/String;I)V", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(11); + Assert.assertEquals("Code", utf8Info.getValue()); + } + + { + MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(12); + Assert.assertEquals(3, methodRef.getClassInfoIndex()); + Assert.assertEquals(13, methodRef.getNameAndTypeIndex()); + } + + { + NameAndTypeInfo nameAndType = (NameAndTypeInfo) pool.getConstantInfo(13); + Assert.assertEquals(9, nameAndType.getNameIndex()); + Assert.assertEquals(14, nameAndType.getDescriptorIndex()); + } + //抽查几个吧 + { + MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(45); + Assert.assertEquals(1, methodRef.getClassInfoIndex()); + Assert.assertEquals(46, methodRef.getNameAndTypeIndex()); + } + + { + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(53); + Assert.assertEquals("EmployeeV1.java", utf8Info.getValue()); + } + } + @Test + public void testClassIndex(){ + + ClassIndex clzIndex = clzFile.getClzIndex(); + ClassInfo thisClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getThisClassIndex()); + ClassInfo superClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getSuperClassIndex()); + + + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); + Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); + } + + } diff --git a/group27/513274874/mini-jvm/src/com/coderising/jvm/util/Util.java b/group27/513274874/mini-jvm/src/com/coderising/jvm/util/Util.java new file mode 100755 index 0000000000..0c4cc8c57c --- /dev/null +++ b/group27/513274874/mini-jvm/src/com/coderising/jvm/util/Util.java @@ -0,0 +1,24 @@ +package com.coderising.jvm.util; + +public class Util { + public static int byteToInt(byte[] codes){ + String s1 = byteToHexString(codes); + return Integer.valueOf(s1, 16).intValue(); + } + + + + public static String byteToHexString(byte[] codes ){ + StringBuffer buffer = new StringBuffer(); + for(int i=0;i Date: Sun, 9 Apr 2017 20:09:24 +0800 Subject: [PATCH 097/203] finish JVM first week homework: ClassFileLoader.java and LRUpageFrame.java --- .../jvm/loader/ClassFileLoader.java | 101 +++++++++++ .../jvm/test/ClassFileloaderTest.java | 86 +++++++++ .../com/coderising/jvm/test/EmployeeV1.java | 29 ++++ .../src/com/coderising/lru/LRUPageFrame.java | 163 ++++++++++++++++++ .../coderising/lru/test/LRUPageFrameTest.java | 34 ++++ 5 files changed, 413 insertions(+) create mode 100644 group24/1525619747/homework_20170402/src/com/coderising/jvm/loader/ClassFileLoader.java create mode 100644 group24/1525619747/homework_20170402/src/com/coderising/jvm/test/ClassFileloaderTest.java create mode 100644 group24/1525619747/homework_20170402/src/com/coderising/jvm/test/EmployeeV1.java create mode 100644 group24/1525619747/homework_20170402/src/com/coderising/lru/LRUPageFrame.java create mode 100644 group24/1525619747/homework_20170402/src/com/coderising/lru/test/LRUPageFrameTest.java diff --git a/group24/1525619747/homework_20170402/src/com/coderising/jvm/loader/ClassFileLoader.java b/group24/1525619747/homework_20170402/src/com/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..0faf29d84b --- /dev/null +++ b/group24/1525619747/homework_20170402/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,101 @@ +package com.coderising.jvm.loader; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + + + +public class ClassFileLoader { + + private List clzPaths = new ArrayList(); + + public byte[] readBinaryCode(String className) throws IOException { + String clzFileName = ""; + byte[] byteCodes = null; + boolean classFound = false; + + for (String path : clzPaths) { + clzFileName = path + File.separatorChar + className.replace('.', File.separatorChar) + ".class"; + + if ((byteCodes = loadClassFile(clzFileName)) != null){ + classFound = true; + return byteCodes; + } + } + + if (classFound == false) { + throw new FileNotFoundException(clzFileName); + } + + return null; + } + + private byte[] loadClassFile(String clzFileName) throws IOException { + + File file = new File(clzFileName); + if(!file.exists()){ +// throw new FileNotFoundException(clzFileName); + return null; + } + + ByteArrayOutputStream bos = new ByteArrayOutputStream((int)file.length()); + BufferedInputStream in = null; + + try { + in = new BufferedInputStream(new FileInputStream(file)); + + int buf_size = 1024; + byte[] buffer = new byte[buf_size]; + int len = 0; + + while ((len = in.read(buffer, 0, buf_size)) != -1) { + bos.write(buffer, 0, len); + } + + return bos.toByteArray(); + + } catch (IOException e) { + e.printStackTrace(); + throw e; + } finally { + try { + in.close(); + } catch (IOException e) { + e.printStackTrace(); + } + bos.close(); + } + } + + + + public void addClassPath(String path) { + clzPaths.add(path); + } + + public String getClassPath_V1(){ + + return null; + } + + public String getClassPath(){ + String classPath = ""; + for (int i = 0; i < clzPaths.size(); i++) { + classPath += clzPaths.get(i); + if (i != clzPaths.size() - 1) { + classPath += ";"; + } + } + return classPath; + } + + + +} diff --git a/group24/1525619747/homework_20170402/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group24/1525619747/homework_20170402/src/com/coderising/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..3192f6596c --- /dev/null +++ b/group24/1525619747/homework_20170402/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,86 @@ +package com.coderising.jvm.test; + +import java.io.IOException; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.coderising.jvm.loader.ClassFileLoader; + + +public class ClassFileloaderTest { + + static String path1 = "F:\\Project\\Java_Project\\Java_SE\\coding2017\\group24\\1525619747\\homework_20170402\\bin"; + static String path2 = "C:\\temp"; + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testClassPath(){ + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + loader.addClassPath(path2); + + String clzPath = loader.getClassPath(); + Assert.assertEquals(path1+";"+path2,clzPath); + + } + + @Test + public void testClassFileLength() throws IOException { + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + + String className = "com.coderising.jvm.test.EmployeeV1"; + + byte[] byteCodes = loader.readBinaryCode(className); +// System.out.println(byteCodes.length); + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + Assert.assertEquals(1056, byteCodes.length); + + } + + + @Test + public void testMagicNumber() throws IOException{ + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "com.coderising.jvm.test.EmployeeV1"; + byte[] byteCodes = loader.readBinaryCode(className); + System.out.println(byteCodes[0] + " " + byteCodes[1] + " " + byteCodes[2] + " " +byteCodes[3]); + byte[] codes = new byte[]{byteCodes[0],byteCodes[1],byteCodes[2],byteCodes[3]}; + + + String acctualValue = this.byteToHexString(codes); +// System.out.println(acctualValue); + Assert.assertEquals("cafebabe", acctualValue); + } + + + + + private String byteToHexString(byte[] codes ){ + StringBuffer buffer = new StringBuffer(); + for(int i=0;i Date: Sun, 9 Apr 2017 20:57:13 +0800 Subject: [PATCH 098/203] modify jvm --- .../classfile/constant/item/impl/{Utf8Info.java => UTF8Info.java} | 0 .../parser/impl/{Utf8InfoParser.java => UTF8InfoParser.java} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/{Utf8Info.java => UTF8Info.java} (100%) rename group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/{Utf8InfoParser.java => UTF8InfoParser.java} (100%) diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/Utf8Info.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/UTF8Info.java similarity index 100% rename from group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/Utf8Info.java rename to group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/UTF8Info.java diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/Utf8InfoParser.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/UTF8InfoParser.java similarity index 100% rename from group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/Utf8InfoParser.java rename to group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/UTF8InfoParser.java From 09e724494db81d330eed017bb70d7f5ab066746f Mon Sep 17 00:00:00 2001 From: Haochen Date: Sun, 9 Apr 2017 20:57:36 +0800 Subject: [PATCH 099/203] finish StackUtil --- .../src/main/java/algorithm/StackUtil.java | 99 +++++++++++++++++++ .../test/java/algorithm/StackUtilTest.java | 94 ++++++++++++++++++ 2 files changed, 193 insertions(+) create mode 100644 group01/895457260/code/src/main/java/algorithm/StackUtil.java create mode 100644 group01/895457260/code/src/test/java/algorithm/StackUtilTest.java diff --git a/group01/895457260/code/src/main/java/algorithm/StackUtil.java b/group01/895457260/code/src/main/java/algorithm/StackUtil.java new file mode 100644 index 0000000000..1b8ecf63de --- /dev/null +++ b/group01/895457260/code/src/main/java/algorithm/StackUtil.java @@ -0,0 +1,99 @@ +package algorithm; + +import datastructure.basic.Stack; + +import java.util.Arrays; + +public class StackUtil { + + + /** + * 假设栈中的元素是Integer, 从栈顶到栈底是 : 5,4,3,2,1 调用该方法后, 元素次序变为: 1,2,3,4,5 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + */ + public static void reverse(Stack s) { + Stack reverse = new Stack(); + while (!s.isEmpty()) { + reverse.push(s.pop()); + } + Stack reverseAgain = new Stack(); + while (!reverse.isEmpty()) { + reverseAgain.push(reverse.pop()); + } + while (!reverseAgain.isEmpty()) { + s.push(reverseAgain.pop()); + } + } + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s, Object o) { + Stack temp = new Stack(); + while (!s.isEmpty()) { + Object pop = s.pop(); + if (!pop.equals(o)) { + temp.push(pop); + } + } + while (!temp.isEmpty()) { + s.push(temp.pop()); + } + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * @param len + * @return + */ + public static Object[] getTop(Stack s, int len) { + Stack temp = new Stack(); + for (int i = 0; i < len && !s.isEmpty(); ++i) { + temp.push(s.pop()); + } + Object[] result = new Object[temp.size()]; + for (int i = 0; i < result.length; ++i) { + result[i] = temp.pop(); + s.push(result[i]); + } + return result; + } + /** + * 字符串s 可能包含这些字符: ( ) [ ] { }, a,b,c... x,yz + * 使用堆栈检查字符串s中的括号是不是成对出现的。 + * 例如s = "([e{d}f])" , 则该字符串中的括号是成对出现, 该方法返回true + * 如果 s = "([b{x]y})", 则该字符串中的括号不是成对出现的, 该方法返回false; + * @param s + * @return + */ + public static boolean isValidPairs(String s) { + Stack brackets = new Stack(); + char[] chars = s.toCharArray(); + + for (char c : chars) { + if (isBracket(c)) { + if (!brackets.isEmpty() && isPair((Character) brackets.peek(), c)) { + brackets.pop(); + } else { + brackets.push(c); + } + } + } + return brackets.isEmpty(); + } + + private static boolean isBracket(char c) { + return c == '(' || c == ')' + || c == '[' || c == ']' + || c == '{' || c == '}'; + } + + private static boolean isPair(char left, char right) { + return (left == '(' && right == ')') + || (left == '[' && right == ']') + || (left == '{' && right == '}'); + } +} diff --git a/group01/895457260/code/src/test/java/algorithm/StackUtilTest.java b/group01/895457260/code/src/test/java/algorithm/StackUtilTest.java new file mode 100644 index 0000000000..8ec48fa134 --- /dev/null +++ b/group01/895457260/code/src/test/java/algorithm/StackUtilTest.java @@ -0,0 +1,94 @@ +package algorithm; + +import datastructure.basic.Stack; +import org.junit.Assert; +import org.junit.Test; +import org.junit.Before; +import org.junit.After; + +import java.util.Arrays; + +/** + * StackUtil Tester. + * + * @author + * @version 1.0 + * @since
四月 9, 2017
+ */ +public class StackUtilTest { + + @Before + public void before() throws Exception { + } + + @After + public void after() throws Exception { + } + + private Stack build(Object... args) { + Stack stack = new Stack(); + Arrays.stream(args).forEach(stack::push); + return stack; + } + + private Object[] toArray(Stack stack) { + Object[] array = new Object[stack.size()]; + for (int i = array.length - 1; i >= 0; --i) { + array[i] = stack.pop(); + } + Arrays.stream(array).forEach(stack::push); + return array; + } + + /** + * Method: reverse(Stack s) + */ + @Test + public void testReverse() throws Exception { +//TODO: Test goes here... + Stack stack = build(1, 3, 5, 7, 9); + StackUtil.reverse(stack); + Assert.assertArrayEquals(new Object[] {9, 7, 5, 3, 1}, toArray(stack)); + } + + /** + * Method: remove(Stack s, Object o) + */ + @Test + public void testRemove() throws Exception { +//TODO: Test goes here... + Stack stack = build(1, 3, 5, 7, 9, 11, 13); + StackUtil.remove(stack, 0); + Assert.assertArrayEquals(new Object[] {1, 3, 5, 7, 9, 11, 13}, toArray(stack)); + StackUtil.remove(stack, 1); + Assert.assertArrayEquals(new Object[] {3, 5, 7, 9, 11, 13}, toArray(stack)); + StackUtil.remove(stack, 13); + Assert.assertArrayEquals(new Object[] {3, 5, 7, 9, 11}, toArray(stack)); + StackUtil.remove(stack, 7); + Assert.assertArrayEquals(new Object[] {3, 5, 9, 11}, toArray(stack)); + } + + /** + * Method: getTop(Stack s, int len) + */ + @Test + public void testGetTop() throws Exception { +//TODO: Test goes here... + Stack stack = build(1, 3, 5); + Assert.assertArrayEquals(new Object[] {}, StackUtil.getTop(stack, 0)); + Assert.assertArrayEquals(new Object[] {3, 5}, StackUtil.getTop(stack, 2)); + Assert.assertArrayEquals(new Object[] {1, 3, 5}, StackUtil.getTop(stack, 3)); + Assert.assertArrayEquals(new Object[] {1, 3, 5}, StackUtil.getTop(stack, 4)); + } + + /** + * Method: isValidPairs(String s) + */ + @Test + public void testIsValidPairs() throws Exception { +//TODO: Test goes here... + Assert.assertTrue(StackUtil.isValidPairs("{sqrt[p*(p-a)*(p-b)*(p-c)]}")); + Assert.assertFalse(StackUtil.isValidPairs("{sqrt[p*[p-a)*(p-b]*(p-c)]}")); + } + +} From a900f4a05313499a57a8f916531a46d68af8c53a Mon Sep 17 00:00:00 2001 From: Haochen Date: Sun, 9 Apr 2017 21:00:39 +0800 Subject: [PATCH 100/203] finish constant pool loading --- .../main/java/jvm/classfile/ClassFile.java | 18 +++ .../main/java/jvm/classfile/ClassIndex.java | 10 +- .../main/java/jvm/classfile/ClassParser.java | 39 ++++-- .../main/java/jvm/classfile/ConstantPool.java | 8 ++ .../jvm/classfile/constant/item/Constant.java | 2 +- .../classfile/constant/item/IReference.java | 11 ++ .../constant/item/impl/ClassInfo.java | 21 +++- .../constant/item/impl/CountConstant.java | 3 +- .../constant/item/impl/DoubleInfo.java | 3 +- .../constant/item/impl/FieldRefInfo.java | 11 +- .../constant/item/impl/FloatInfo.java | 3 +- .../constant/item/impl/IntegerInfo.java | 3 +- .../item/impl/InterfaceMethodRefInfo.java | 10 +- .../constant/item/impl/InvokeDynamicInfo.java | 3 +- .../constant/item/impl/LongInfo.java | 3 +- .../constant/item/impl/MethodHandleInfo.java | 3 +- .../constant/item/impl/MethodRefInfo.java | 13 +- .../constant/item/impl/MethodTypeInfo.java | 3 +- .../constant/item/impl/NameAndTypeInfo.java | 11 +- .../constant/item/impl/StringInfo.java | 3 +- .../constant/item/impl/UTF8Info.java | 21 ++-- .../parser/ConstantParserFactory.java | 2 +- .../constant/parser/impl/UTF8InfoParser.java | 9 +- .../test/java/jvm/ClassFileLoaderTest.java | 115 ++++++++++++++++-- 24 files changed, 260 insertions(+), 68 deletions(-) create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/constant/item/IReference.java diff --git a/group01/895457260/code/src/main/java/jvm/classfile/ClassFile.java b/group01/895457260/code/src/main/java/jvm/classfile/ClassFile.java index f7b84d5185..ccdb47bcf2 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/ClassFile.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/ClassFile.java @@ -9,4 +9,22 @@ public class ClassFile { ClassIndex classIndex; AccessFlag accessFlag; ConstantPool constantPool; + int minorVersion; + int majorVersion; + + public int getMinorVersion() { + return minorVersion; + } + + public int getMajorVersion() { + return majorVersion; + } + + public ConstantPool getConstantPool() { + return constantPool; + } + + public ClassIndex getClzIndex() { + return classIndex; + } } diff --git a/group01/895457260/code/src/main/java/jvm/classfile/ClassIndex.java b/group01/895457260/code/src/main/java/jvm/classfile/ClassIndex.java index 0078e10b10..dc3891698d 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/ClassIndex.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/ClassIndex.java @@ -5,8 +5,14 @@ * TODO: */ public class ClassIndex { - int minorVersion; - int majorVersion; int thisClass; int superClass; + + public int getThisClassIndex() { + return thisClass; + } + + public int getSuperClassIndex() { + return superClass; + } } diff --git a/group01/895457260/code/src/main/java/jvm/classfile/ClassParser.java b/group01/895457260/code/src/main/java/jvm/classfile/ClassParser.java index 41365714a7..0a22134c6f 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/ClassParser.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/ClassParser.java @@ -1,6 +1,7 @@ package jvm.classfile; import jvm.classfile.constant.item.Constant; +import jvm.classfile.constant.item.IReference; import jvm.classfile.constant.item.impl.CountConstant; import jvm.classfile.constant.parser.ConstantParser; import jvm.classfile.constant.parser.ConstantParserFactory; @@ -37,15 +38,32 @@ private static class StartIndex { public static ClassFile parse(byte[] bytes) { ClassFile classFile = new ClassFile(); + + classFile.minorVersion = parseMinorVersion(bytes, index); + classFile.majorVersion = parseMajorVersion(bytes, index); classFile.constantPool = parseConstantPool(bytes, index); classFile.classIndex = parseClassIndex(bytes, index); classFile.accessFlag = parseAccessFlag(bytes, index); - restore(classFile); + linkConstantReferences(classFile); return classFile; } - private static void restore(ClassFile classFile) { - + private static int parseMinorVersion(byte[] bytes, StartIndex index) { + return ByteUtils.toInt(bytes, index.minorVersion, 2); + } + + private static int parseMajorVersion(byte[] bytes, StartIndex index) { + return ByteUtils.toInt(bytes, index.majorVersion, 2); + } + + private static void linkConstantReferences(ClassFile classFile) { + ConstantPool constantPool = classFile.constantPool; + Map constantMap = constantPool.constantMap; + constantMap.forEach((i, c) -> { + if (c instanceof IReference) { + ((IReference) c).linkReference(constantPool); + } + }); } private static ConstantPool parseConstantPool(byte[] bytes, StartIndex index) { @@ -54,21 +72,20 @@ private static ConstantPool parseConstantPool(byte[] bytes, StartIndex index) { ConstantPool constantPool = new ConstantPool(); int currentIndex = index.constantPoolCount; - index.constantIndexMap.put(1, currentIndex); + index.constantIndexMap.put(0, currentIndex); int count = ByteUtils.toInt(bytes, currentIndex, COUNT_LEN); - constantPool.constantMap.put(1, new CountConstant(count)); + constantPool.constantMap.put(0, new CountConstant(count)); currentIndex += COUNT_LEN; Map parserMap = new HashMap<>(); - for (int i = 2; i <= count; ++i) { - ConstantParser parser = ConstantParserFactory.get( - ByteUtils.toInt(bytes, currentIndex, ConstantParser.TAG_LEN), - bytes, currentIndex); + for (int i = 1; i < count; ++i) { + int tag = ByteUtils.toInt(bytes, currentIndex, ConstantParser.TAG_LEN); + ConstantParser parser = ConstantParserFactory.get(tag, bytes, currentIndex); parserMap.put(i, parser); index.constantIndexMap.put(i, currentIndex); currentIndex += parser.length(); } - for (int i = 2; i <= count; ++i) { + for (int i = 1; i < count; ++i) { ConstantParser parser = parserMap.get(i); int startIndex = index.constantIndexMap.get(i); Constant constant = parser.parse(bytes, startIndex); @@ -84,8 +101,6 @@ private static ConstantPool parseConstantPool(byte[] bytes, StartIndex index) { private static ClassIndex parseClassIndex(byte[] bytes, StartIndex index) { ClassIndex classIndex = new ClassIndex(); - classIndex.minorVersion = ByteUtils.toInt(bytes, index.minorVersion, 2); - classIndex.majorVersion = ByteUtils.toInt(bytes, index.majorVersion, 2); classIndex.thisClass = ByteUtils.toInt(bytes, index.thisClass, 2); classIndex.superClass = ByteUtils.toInt(bytes, index.superClass, 2); return classIndex; diff --git a/group01/895457260/code/src/main/java/jvm/classfile/ConstantPool.java b/group01/895457260/code/src/main/java/jvm/classfile/ConstantPool.java index 1595685533..cc9ab01c24 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/ConstantPool.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/ConstantPool.java @@ -11,4 +11,12 @@ */ public class ConstantPool { Map constantMap = new HashMap<>(); + + public int getSize() { + return constantMap.size() - 1; + } + + public Constant getConstantInfo(int index) { + return constantMap.get(index); + } } diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/Constant.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/Constant.java index 6c10479d4c..c83fbfbb28 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/Constant.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/Constant.java @@ -5,5 +5,5 @@ * TODO: */ public interface Constant { - int length(); + int size(); } diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/IReference.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/IReference.java new file mode 100644 index 0000000000..89a819aa96 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/IReference.java @@ -0,0 +1,11 @@ +package jvm.classfile.constant.item; + +import jvm.classfile.ConstantPool; + +/** + * Created by Haochen on 2017/4/9. + * TODO: + */ +public interface IReference { + void linkReference(ConstantPool constantPool); +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/ClassInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/ClassInfo.java index 0b5ad448f9..84657cd7e4 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/ClassInfo.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/ClassInfo.java @@ -1,24 +1,39 @@ package jvm.classfile.constant.item.impl; +import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.Constant; +import jvm.classfile.constant.item.IReference; /** * Created by Haochen on 2017/4/9. * TODO: */ -public class ClassInfo implements Constant { +public class ClassInfo implements Constant, IReference { private int nameIndex; + private String className; public ClassInfo(int nameIndex) { this.nameIndex = nameIndex; } @Override - public int length() { + public int size() { return 3; } - public int getNameIndex() { + @Override + public void linkReference(ConstantPool constantPool) { + Constant constant = constantPool.getConstantInfo(getUtf8Index()); + if (constant instanceof UTF8Info) { + this.className = ((UTF8Info) constant).getValue(); + } + } + + public int getUtf8Index() { return nameIndex; } + + public String getClassName() { + return className; + } } diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/CountConstant.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/CountConstant.java index 32ac16daf6..8d6593a1c0 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/CountConstant.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/CountConstant.java @@ -1,5 +1,6 @@ package jvm.classfile.constant.item.impl; +import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.Constant; /** @@ -14,7 +15,7 @@ public CountConstant(int count) { } @Override - public int length() { + public int size() { return 2; } diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/DoubleInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/DoubleInfo.java index 873d416fbf..b65e8d82db 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/DoubleInfo.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/DoubleInfo.java @@ -1,5 +1,6 @@ package jvm.classfile.constant.item.impl; +import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.Constant; /** @@ -16,7 +17,7 @@ public DoubleInfo(byte[] highBytes, byte[] lowBytes) { } @Override - public int length() { + public int size() { return 9; } diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/FieldRefInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/FieldRefInfo.java index 004f079e43..ed5ba84212 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/FieldRefInfo.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/FieldRefInfo.java @@ -1,5 +1,6 @@ package jvm.classfile.constant.item.impl; +import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.Constant; /** @@ -8,15 +9,15 @@ */ public class FieldRefInfo implements Constant { private int classIndex; - private int nameAndTypeindex; + private int nameAndTypeIndex; public FieldRefInfo(int classIndex, int nameAndTypeIndex) { this.classIndex = classIndex; - this.nameAndTypeindex = nameAndTypeIndex; + this.nameAndTypeIndex = nameAndTypeIndex; } @Override - public int length() { + public int size() { return 5; } @@ -24,7 +25,7 @@ public int getClassIndex() { return classIndex; } - public int getNameAndTypeindex() { - return nameAndTypeindex; + public int getNameAndTypeIndex() { + return nameAndTypeIndex; } } diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/FloatInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/FloatInfo.java index 57ac51a72b..707d548586 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/FloatInfo.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/FloatInfo.java @@ -1,5 +1,6 @@ package jvm.classfile.constant.item.impl; +import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.Constant; /** @@ -14,7 +15,7 @@ public FloatInfo(byte[] bytes) { } @Override - public int length() { + public int size() { return 5; } diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/IntegerInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/IntegerInfo.java index 0c544b0525..2bbc08144d 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/IntegerInfo.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/IntegerInfo.java @@ -1,5 +1,6 @@ package jvm.classfile.constant.item.impl; +import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.Constant; import jvm.util.ByteUtils; @@ -15,7 +16,7 @@ public IntegerInfo(byte[] bytes) { } @Override - public int length() { + public int size() { return 5; } diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/InterfaceMethodRefInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/InterfaceMethodRefInfo.java index 1cae4dc82e..e22f8d4a45 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/InterfaceMethodRefInfo.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/InterfaceMethodRefInfo.java @@ -8,15 +8,15 @@ */ public class InterfaceMethodRefInfo implements Constant { private int classIndex; - private int nameAndTypeindex; + private int nameAndTypeIndex; public InterfaceMethodRefInfo(int classIndex, int nameAndTypeIndex) { this.classIndex = classIndex; - this.nameAndTypeindex = nameAndTypeIndex; + this.nameAndTypeIndex = nameAndTypeIndex; } @Override - public int length() { + public int size() { return 5; } @@ -24,7 +24,7 @@ public int getClassIndex() { return classIndex; } - public int getNameAndTypeindex() { - return nameAndTypeindex; + public int getNameAndTypeIndex() { + return nameAndTypeIndex; } } diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/InvokeDynamicInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/InvokeDynamicInfo.java index 66f98ed4c6..0e8d478a2f 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/InvokeDynamicInfo.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/InvokeDynamicInfo.java @@ -1,5 +1,6 @@ package jvm.classfile.constant.item.impl; +import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.Constant; /** @@ -16,7 +17,7 @@ public InvokeDynamicInfo(int bootstrapMethodAttrIndex, int nameAndTypeIndex) { } @Override - public int length() { + public int size() { return 5; } diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/LongInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/LongInfo.java index a2ce9b9cbe..7e61808e3a 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/LongInfo.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/LongInfo.java @@ -1,5 +1,6 @@ package jvm.classfile.constant.item.impl; +import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.Constant; /** @@ -16,7 +17,7 @@ public LongInfo(byte[] highBytes, byte[] lowBytes) { } @Override - public int length() { + public int size() { return 9; } diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/MethodHandleInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/MethodHandleInfo.java index 165682bf2e..d1e32ec581 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/MethodHandleInfo.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/MethodHandleInfo.java @@ -1,5 +1,6 @@ package jvm.classfile.constant.item.impl; +import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.Constant; /** @@ -16,7 +17,7 @@ public MethodHandleInfo(int referenceKind, int referenceIndex) { } @Override - public int length() { + public int size() { return 4; } diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/MethodRefInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/MethodRefInfo.java index a311ec0821..41f1020359 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/MethodRefInfo.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/MethodRefInfo.java @@ -1,5 +1,6 @@ package jvm.classfile.constant.item.impl; +import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.Constant; /** @@ -8,23 +9,23 @@ */ public class MethodRefInfo implements Constant { private int classIndex; - private int nameAndTypeindex; + private int nameAndTypeIndex; public MethodRefInfo(int classIndex, int nameAndTypeIndex) { this.classIndex = classIndex; - this.nameAndTypeindex = nameAndTypeIndex; + this.nameAndTypeIndex = nameAndTypeIndex; } @Override - public int length() { + public int size() { return 5; } - public int getClassIndex() { + public int getClassInfoIndex() { return classIndex; } - public int getNameAndTypeindex() { - return nameAndTypeindex; + public int getNameAndTypeIndex() { + return nameAndTypeIndex; } } diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/MethodTypeInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/MethodTypeInfo.java index 4a7e59ada4..4e4df13b48 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/MethodTypeInfo.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/MethodTypeInfo.java @@ -1,5 +1,6 @@ package jvm.classfile.constant.item.impl; +import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.Constant; /** @@ -14,7 +15,7 @@ public MethodTypeInfo(int descriptorIndex) { } @Override - public int length() { + public int size() { return 3; } diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/NameAndTypeInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/NameAndTypeInfo.java index 712b7761a3..dfc9b54b28 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/NameAndTypeInfo.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/NameAndTypeInfo.java @@ -1,5 +1,6 @@ package jvm.classfile.constant.item.impl; +import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.Constant; /** @@ -16,7 +17,7 @@ public NameAndTypeInfo(int nameIndex, int descriptorIndex) { } @Override - public int length() { + public int size() { return 5; } @@ -27,4 +28,12 @@ public int getNameIndex() { public int getDescriptorIndex() { return descriptorIndex; } + + public int getIndex1() { + return nameIndex; + } + + public int getIndex2() { + return descriptorIndex; + } } diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/StringInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/StringInfo.java index 59a2a89336..c7b001c08e 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/StringInfo.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/StringInfo.java @@ -1,5 +1,6 @@ package jvm.classfile.constant.item.impl; +import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.Constant; /** @@ -14,7 +15,7 @@ public StringInfo(int stringIndex) { } @Override - public int length() { + public int size() { return 3; } diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/UTF8Info.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/UTF8Info.java index dbc983af45..42edd32e44 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/UTF8Info.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/item/impl/UTF8Info.java @@ -1,22 +1,29 @@ package jvm.classfile.constant.item.impl; +import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.Constant; +import java.io.UnsupportedEncodingException; + /** * Created by Haochen on 2017/4/9. * TODO: */ -public class Utf8Info implements Constant { +public class UTF8Info implements Constant { private int length; - private byte[] bytes; + private String value; - public Utf8Info(int length, byte[] bytes) { + public UTF8Info(int length, byte[] bytes) { this.length = length; - this.bytes = bytes; + try { + this.value = new String(bytes, "utf8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } } @Override - public int length() { + public int size() { return 3 + length; } @@ -24,7 +31,7 @@ public int getLength() { return length; } - public byte[] getBytes() { - return bytes; + public String getValue() { + return value; } } diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/ConstantParserFactory.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/ConstantParserFactory.java index 95b4de56ff..fec8930428 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/ConstantParserFactory.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/ConstantParserFactory.java @@ -48,7 +48,7 @@ public static ConstantParser get(int type, byte[] bytes, int startIndex) { case CONSTANT_UTF8: startIndex += ConstantParser.TAG_LEN; int length = ByteUtils.toInt(bytes, startIndex, 2); - return new Utf8InfoParser(length); + return new UTF8InfoParser(length); case CONSTANT_METHOD_HANDLE: return new MethodHandleInfoParser(); case CONSTANT_METHOD_TYPE: diff --git a/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/UTF8InfoParser.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/UTF8InfoParser.java index 5853db1817..108bc11642 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/UTF8InfoParser.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/UTF8InfoParser.java @@ -1,18 +1,17 @@ package jvm.classfile.constant.parser.impl; import jvm.classfile.constant.item.Constant; -import jvm.classfile.constant.item.impl.Utf8Info; +import jvm.classfile.constant.item.impl.UTF8Info; import jvm.classfile.constant.parser.ConstantParser; -import jvm.util.ByteUtils; /** * Created by Haochen on 2017/4/9. * TODO: */ -public class Utf8InfoParser implements ConstantParser { +public class UTF8InfoParser implements ConstantParser { private int length; - public Utf8InfoParser(int length) { + public UTF8InfoParser(int length) { this.length = length; } @@ -22,7 +21,7 @@ public Constant parse(byte[] bytes, int startIndex) { startIndex += 2; byte[] array = new byte[length]; System.arraycopy(bytes, startIndex, array, 0, length); - return new Utf8Info(length, array); + return new UTF8Info(length, array); } @Override diff --git a/group01/895457260/code/src/test/java/jvm/ClassFileLoaderTest.java b/group01/895457260/code/src/test/java/jvm/ClassFileLoaderTest.java index f30ee57de9..16fbfc58e5 100644 --- a/group01/895457260/code/src/test/java/jvm/ClassFileLoaderTest.java +++ b/group01/895457260/code/src/test/java/jvm/ClassFileLoaderTest.java @@ -1,6 +1,12 @@ package jvm; import jvm.classfile.ClassFile; +import jvm.classfile.ClassIndex; +import jvm.classfile.ConstantPool; +import jvm.classfile.constant.item.impl.ClassInfo; +import jvm.classfile.constant.item.impl.MethodRefInfo; +import jvm.classfile.constant.item.impl.NameAndTypeInfo; +import jvm.classfile.constant.item.impl.UTF8Info; import jvm.exception.ReadClassException; import org.junit.After; import org.junit.Assert; @@ -8,16 +14,24 @@ import org.junit.Test; public class ClassFileLoaderTest { + private static final String FULL_QUALIFIED_CLASS_NAME = "jvm/EmployeeV1"; + private static final String LOAD_CLASS_NAME = "jvm.EmployeeV1"; private static ClassFileLoader loader; private static String path1 = "target/classes"; private static String path2 = "target/test-classes"; + + private static ClassFile clzFile = null; @Before public void setUp() throws Exception { loader = new ClassFileLoader(); loader.addClassPath(path1); loader.addClassPath(path2); + + if (clzFile == null) { + clzFile = loader.load(LOAD_CLASS_NAME); + } } @After @@ -31,29 +45,20 @@ public void testClassPath() { @Test public void testClassFileLength() throws ReadClassException { - String className = "jvm.EmployeeV1"; - byte[] byteCodes = loader.readBinaryCode(className); + byte[] byteCodes = loader.readBinaryCode(LOAD_CLASS_NAME); // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 Assert.assertEquals(1016, byteCodes.length); } @Test public void testMagicNumber() throws ReadClassException { - String className = "jvm.EmployeeV1"; - byte[] byteCodes = loader.readBinaryCode(className); + byte[] byteCodes = loader.readBinaryCode(LOAD_CLASS_NAME); byte[] codes = new byte[] {byteCodes[0], byteCodes[1], byteCodes[2], byteCodes[3]}; boolean check = loader.checkMagicNumber(codes); Assert.assertTrue(check); } - @Test - public void testLoad() throws ReadClassException { - String className = "jvm.EmployeeV1"; - ClassFile classFile = loader.load(className); - System.out.println("done"); - } - private String byteToHexString(byte[] codes) { StringBuilder buffer = new StringBuilder(); for (byte b : codes) { @@ -66,4 +71,92 @@ private String byteToHexString(byte[] codes) { } return buffer.toString(); } + + + + + + @Test + public void testVersion() { + Assert.assertEquals(0, clzFile.getMinorVersion()); + Assert.assertEquals(52, clzFile.getMajorVersion()); + } + + @Test + public void testConstantPool() { + + ConstantPool pool = clzFile.getConstantPool(); + + Assert.assertEquals(53, pool.getSize()); + + { + ClassInfo clzInfo = (ClassInfo) pool.getConstantInfo(7); + Assert.assertEquals(44, clzInfo.getUtf8Index()); + + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(44); + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, utf8Info.getValue()); + } + { + ClassInfo clzInfo = (ClassInfo) pool.getConstantInfo(11); + Assert.assertEquals(48, clzInfo.getUtf8Index()); + + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(48); + Assert.assertEquals("java/lang/Object", utf8Info.getValue()); + } + { + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(12); + Assert.assertEquals("name", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(13); + Assert.assertEquals("Ljava/lang/String;", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(14); + Assert.assertEquals("age", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(15); + Assert.assertEquals("I", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(16); + Assert.assertEquals("", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(17); + Assert.assertEquals("(Ljava/lang/String;I)V", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(18); + Assert.assertEquals("Code", utf8Info.getValue()); + } + + { + MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(1); + Assert.assertEquals(11, methodRef.getClassInfoIndex()); + Assert.assertEquals(36, methodRef.getNameAndTypeIndex()); + } + + { + NameAndTypeInfo nameAndType = (NameAndTypeInfo) pool.getConstantInfo(36); + Assert.assertEquals(16, nameAndType.getIndex1()); + Assert.assertEquals(28, nameAndType.getIndex2()); + } + //抽查几个吧 + { + MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(9); + Assert.assertEquals(7, methodRef.getClassInfoIndex()); + Assert.assertEquals(46, methodRef.getNameAndTypeIndex()); + } + + { + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(35); + Assert.assertEquals("EmployeeV1.java", utf8Info.getValue()); + } + } + @Test + public void testClassIndex() { + + ClassIndex clzIndex = clzFile.getClzIndex(); + ClassInfo thisClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getThisClassIndex()); + ClassInfo superClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getSuperClassIndex()); + + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); + Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); + } } From 73fcf9f2f91279c05325d21e3bfdecaff28dfe6b Mon Sep 17 00:00:00 2001 From: Korben_CHY Date: Sun, 9 Apr 2017 21:28:16 +0800 Subject: [PATCH 101/203] finish StackUtil by Korben --- .../basic/stack/{KStack.java => Stack.java} | 6 +- .../stack/{KStackTest.java => StackTest.java} | 10 +- .../src/com/coding/basic/stack/StackUtil.java | 130 ++++++++++++++++++ .../com/coding/basic/stack/StackUtilTest.java | 82 +++++++++++ 4 files changed, 220 insertions(+), 8 deletions(-) rename group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/{KStack.java => Stack.java} (95%) rename group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/{KStackTest.java => StackTest.java} (89%) create mode 100644 group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/StackUtil.java create mode 100644 group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/StackUtilTest.java diff --git a/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/KStack.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/Stack.java similarity index 95% rename from group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/KStack.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/Stack.java index cb1fb5e5b8..a76dc3a16a 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/KStack.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/Stack.java @@ -8,12 +8,12 @@ * * Created by Korben on 18/02/2017. */ -public class KStack { +public class Stack { private int size; private Object[] dataArray = {}; - public KStack() { + public Stack() { } public int size() { @@ -47,7 +47,7 @@ public T peek() { return (T) dataArray[size - 1]; } - public boolean empty() { + public boolean isEmpty() { return size == 0; } diff --git a/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/KStackTest.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/StackTest.java similarity index 89% rename from group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/KStackTest.java rename to group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/StackTest.java index eee06600b1..9e47545014 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/KStackTest.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/StackTest.java @@ -10,13 +10,13 @@ * * Created by Korben on 18/02/2017. */ -public class KStackTest { - private KStack stack; +public class StackTest { + private Stack stack; private int initTestSize; @Before public void init() { - stack = new KStack<>(); + stack = new Stack<>(); initTestSize = 5; for (int i = 0; i < initTestSize; i++) { @@ -55,11 +55,11 @@ public void peek() throws Exception { @Test public void empty() throws Exception { - Assert.assertFalse(stack.empty()); + Assert.assertFalse(stack.isEmpty()); for (int i = 0; i < initTestSize; i++) { stack.pop(); } - Assert.assertTrue(stack.empty()); + Assert.assertTrue(stack.isEmpty()); } @Test diff --git a/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/StackUtil.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/StackUtil.java new file mode 100644 index 0000000000..a9df9b8d88 --- /dev/null +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/StackUtil.java @@ -0,0 +1,130 @@ +package com.coding.basic.stack; + +import java.util.Objects; + +public class StackUtil { + + /** + * 假设栈中的元素是Integer, 从栈顶到栈底是 : 5,4,3,2,1 调用该方法后, 元素次序变为: 1,2,3,4,5 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + */ + public static void reverse(Stack s) { + if (s == null || s.isEmpty()) { + return; + } + + Stack tmp = new Stack(); + + for (int i = 0; i < s.size(); i++) { + tmp.push(get(s, i)); + } + while (!s.isEmpty()) { + s.pop(); + } + while (!tmp.isEmpty()) { + s.push(tmp.pop()); + } + } + + private static Object get(Stack s, int indexFromBottom) { + Stack tmp = new Stack(); + int size = s.size(); + for (int i = 0; i < size - indexFromBottom - 1; i++) { + tmp.push(s.pop()); + } + + Object rtn = s.peek(); + while (!tmp.isEmpty()) { + s.push(tmp.pop()); + } + return rtn; + } + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o 被删除的对象 + */ + public static void remove(Stack s, Object o) { + if (s == null || s.isEmpty()) { + return; + } + + Stack tmp = new Stack(); + + while (!s.isEmpty()) { + Object data = s.pop(); + if (Objects.equals(data, o)) { + break; + } + + tmp.push(data); + } + + while (!tmp.isEmpty()) { + s.push(tmp.pop()); + } + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param len 长度 + */ + public static Object[] getTop(Stack s, int len) { + if (len < 0 || len >= s.size()) { + throw new IndexOutOfBoundsException(); + } + + Object[] rtn = new Object[len]; + Stack tmp = new Stack(); + for (int i = 0; i < len; i++) { + Object data = s.pop(); + rtn[i] = data; + tmp.push(data); + } + + for (int i = 0; i < len; i++) { + s.push(tmp.pop()); + } + + return rtn; + } + + /** + * 字符串s 可能包含这些字符: ( ) [ ] { }, a,b,c... x,yz + * 使用堆栈检查字符串s中的括号是不是成对出现的。 + * 例如s = "([e{d}f])" , 则该字符串中的括号是成对出现, 该方法返回true + * 如果 s = "([b{x]y})", 则该字符串中的括号不是成对出现的, 该方法返回false; + * + * @param s 输入字符串 + */ + public static boolean isValidPairs(String s) { + String[] chars = s.split(""); + + Stack stack = new Stack(); + for (int i = 0; i < chars.length; i++) { + if ("(".equals(chars[i])) { + stack.push(")"); + } else if ("[".equals(chars[i])) { + stack.push("]"); + } else if ("{".equals(chars[i])) { + stack.push("}"); + } else if (")".equals(chars[i])) { + if (!stack.pop().equals(")")) { + return false; + } + } else if ("]".equals(chars[i])) { + if (!stack.pop().equals("]")) { + return false; + } + } else if ("}".equals(chars[i])) { + if (!stack.pop().equals("}")) { + return false; + } + } + } + return true; + } +} diff --git a/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/StackUtilTest.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/StackUtilTest.java new file mode 100644 index 0000000000..77bffbf32b --- /dev/null +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/StackUtilTest.java @@ -0,0 +1,82 @@ +package com.coding.basic.stack; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * Created by Korben on 09/04/2017. + */ +public class StackUtilTest { + + private Stack stack; + + @Before + public void setUp() { + stack = new Stack(); + for (int i = 0; i < 5; i++) { + stack.push(i); + } + } + + @Test + public void reverse() throws Exception { + StackUtil.reverse(stack); + + for (int i = 0; i < 5; i++) { + Assert.assertEquals(i, stack.pop()); + } + + stack.push(1); + StackUtil.reverse(stack); + Assert.assertEquals(1, stack.pop()); + } + + @Test + public void remove() throws Exception { + StackUtil.remove(stack, 1); + Assert.assertEquals(stack.size(), 4); + for (int i = 4; i >= 0; i--) { + if (i == 1) { + continue; + } + Assert.assertEquals(i, stack.pop()); + } + + stack.push(1); + Assert.assertEquals(stack.size(), 1); + } + + @Test + public void getTop() throws Exception { + Object[] top = StackUtil.getTop(stack, 3); + Assert.assertEquals(top.length, 3); + Assert.assertEquals(top[0], 4); + Assert.assertEquals(top[1], 3); + Assert.assertEquals(top[2], 2); + + Assert.assertEquals(stack.size(), 5); + + stack.push(1); + Assert.assertEquals(stack.size(), 6); + stack.pop(); + + for (int i = 0; i < 5; i++) { + Assert.assertEquals(4 - i, stack.pop()); + } + } + + @Test + public void isValidPairs() throws Exception { + { + String str = "([e{d}f])"; + Assert.assertTrue(StackUtil.isValidPairs(str)); + } + + { + String str = "([b{x]y})"; + Assert.assertFalse(StackUtil.isValidPairs(str)); + } + + } +} \ No newline at end of file From e16c31d7b8dc9e92abdb9ae23f6ee9e5dee643d9 Mon Sep 17 00:00:00 2001 From: Date: Sun, 9 Apr 2017 21:40:11 +0800 Subject: [PATCH 102/203] test --- .../src/com/coderising/jvm/constant/ConstantPool.java | 1 + .../src/com/coderising/jvm/loader/ClassFileParser.java | 5 +++++ .../src/com/coderising/jvm/test/ClassFileloaderTest.java | 6 +++--- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/group12/382266293/src/com/coderising/jvm/constant/ConstantPool.java b/group12/382266293/src/com/coderising/jvm/constant/ConstantPool.java index 15eb086a94..8ed8bc229c 100644 --- a/group12/382266293/src/com/coderising/jvm/constant/ConstantPool.java +++ b/group12/382266293/src/com/coderising/jvm/constant/ConstantPool.java @@ -18,6 +18,7 @@ public void addConstantInfo(ConstantInfo info) { } public ConstantInfo getConstantInfo(int index) { + System.out.println("ok " + this.constantInfos.get(index)); return this.constantInfos.get(index); } diff --git a/group12/382266293/src/com/coderising/jvm/loader/ClassFileParser.java b/group12/382266293/src/com/coderising/jvm/loader/ClassFileParser.java index 84a38b1fff..1d981e1dd6 100644 --- a/group12/382266293/src/com/coderising/jvm/loader/ClassFileParser.java +++ b/group12/382266293/src/com/coderising/jvm/loader/ClassFileParser.java @@ -110,6 +110,11 @@ public ClassFile parse(byte[] codes) { } } + + ClassIndex classIndex = parseClassIndex(iter); + AccessFlag accessFlag = parseAccessFlag(iter); + clzFile.setAccessFlag(accessFlag); + clzFile.setClassIndex(classIndex); return clzFile; } diff --git a/group12/382266293/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group12/382266293/src/com/coderising/jvm/test/ClassFileloaderTest.java index b7ec06da0f..2ae3072e35 100644 --- a/group12/382266293/src/com/coderising/jvm/test/ClassFileloaderTest.java +++ b/group12/382266293/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -15,7 +15,7 @@ public class ClassFileloaderTest { - static String path1 = "C:\\Users\\Administrator\\git\\coding2017n\\group12\\382266293\\bin"; + static String path1 = "C:\\Users\\steve\\workspace\\coding2017n\\group12\\382266293\\bin"; static String path2 = "C:\temp"; String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; @@ -65,7 +65,7 @@ public void testClassFileLength() { byte[] byteCodes = loader.readBinaryCode(className); - // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + // 娉ㄦ剰锛氳繖涓瓧鑺傛暟鍙兘鍜屼綘鐨凧VM鐗堟湰鏈夊叧绯伙紝 浣犲彲浠ョ湅鐪嬬紪璇戝ソ鐨勭被鍒板簳鏈夊澶� Assert.assertEquals(1056, byteCodes.length); } @@ -160,7 +160,7 @@ public void testConstantPool() { Assert.assertEquals(9, nameAndType.getIndex1()); Assert.assertEquals(14, nameAndType.getIndex2()); } - // 抽查几个吧 + // 鎶芥煡鍑犱釜鍚� { MethodRefInfo methodRef = (MethodRefInfo) pool.getConstantInfo(45); Assert.assertEquals(1, methodRef.getClassInfoIndex()); From 04768e4c5f8befdf8e3caaaf6cef9cb1cdd37bf0 Mon Sep 17 00:00:00 2001 From: JayXu Date: Sun, 9 Apr 2017 21:41:36 +0800 Subject: [PATCH 103/203] xuweijay --- group15/1511_714512544/.idea/modules.xml | 1 + group15/1511_714512544/.idea/workspace.xml | 1105 ++++++----------- .../com/coderising/jvm/clz/AccessFlag.java | 25 + .../src/com/coderising/jvm/clz/ClassFile.java | 75 ++ .../com/coderising/jvm/clz/ClassIndex.java | 19 + .../coderising/jvm/constant/ClassInfo.java | 24 + .../coderising/jvm/constant/ConstantInfo.java | 29 + .../coderising/jvm/constant/ConstantPool.java | 29 + .../coderising/jvm/constant/FieldRefInfo.java | 54 + .../jvm/constant/MethodRefInfo.java | 55 + .../jvm/constant/NameAndTypeInfo.java | 45 + .../jvm/constant/NullConstantInfo.java | 13 + .../coderising/jvm/constant/StringInfo.java | 26 + .../com/coderising/jvm/constant/UTF8Info.java | 32 + .../jvm/loader/ByteCodeIterator.java | 5 + .../jvm/loader/ClassFileLoader.java | 140 +++ .../jvm/loader/ClassFileParser.java | 35 + .../jvm/test/ClassFileloaderTest.java | 198 +++ .../com/coderising/jvm/test/EmployeeV1.java | 27 + .../src/com/coderising/jvm/util/Util.java | 24 + .../src/com/coding/basic/LRUPageFrame.java | 148 +++ .../com/coding/basic/LRUPageFrameTest.java | 33 + 22 files changed, 1425 insertions(+), 717 deletions(-) create mode 100644 group15/1511_714512544/src/com/coderising/jvm/clz/AccessFlag.java create mode 100644 group15/1511_714512544/src/com/coderising/jvm/clz/ClassFile.java create mode 100644 group15/1511_714512544/src/com/coderising/jvm/clz/ClassIndex.java create mode 100644 group15/1511_714512544/src/com/coderising/jvm/constant/ClassInfo.java create mode 100644 group15/1511_714512544/src/com/coderising/jvm/constant/ConstantInfo.java create mode 100644 group15/1511_714512544/src/com/coderising/jvm/constant/ConstantPool.java create mode 100644 group15/1511_714512544/src/com/coderising/jvm/constant/FieldRefInfo.java create mode 100644 group15/1511_714512544/src/com/coderising/jvm/constant/MethodRefInfo.java create mode 100644 group15/1511_714512544/src/com/coderising/jvm/constant/NameAndTypeInfo.java create mode 100644 group15/1511_714512544/src/com/coderising/jvm/constant/NullConstantInfo.java create mode 100644 group15/1511_714512544/src/com/coderising/jvm/constant/StringInfo.java create mode 100644 group15/1511_714512544/src/com/coderising/jvm/constant/UTF8Info.java create mode 100644 group15/1511_714512544/src/com/coderising/jvm/loader/ByteCodeIterator.java create mode 100644 group15/1511_714512544/src/com/coderising/jvm/loader/ClassFileLoader.java create mode 100644 group15/1511_714512544/src/com/coderising/jvm/loader/ClassFileParser.java create mode 100644 group15/1511_714512544/src/com/coderising/jvm/test/ClassFileloaderTest.java create mode 100644 group15/1511_714512544/src/com/coderising/jvm/test/EmployeeV1.java create mode 100644 group15/1511_714512544/src/com/coderising/jvm/util/Util.java create mode 100644 group15/1511_714512544/src/com/coding/basic/LRUPageFrame.java create mode 100644 group15/1511_714512544/src/com/coding/basic/LRUPageFrameTest.java diff --git a/group15/1511_714512544/.idea/modules.xml b/group15/1511_714512544/.idea/modules.xml index 0ed960e3bf..77979d8e9c 100644 --- a/group15/1511_714512544/.idea/modules.xml +++ b/group15/1511_714512544/.idea/modules.xml @@ -3,6 +3,7 @@ +
\ No newline at end of file diff --git a/group15/1511_714512544/.idea/workspace.xml b/group15/1511_714512544/.idea/workspace.xml index c2d0e8bb87..630f12e7ca 100644 --- a/group15/1511_714512544/.idea/workspace.xml +++ b/group15/1511_714512544/.idea/workspace.xml @@ -1,16 +1,29 @@ - - - - -<<<<<<< HEAD - - - -======= ->>>>>>> refs/remotes/origin/master + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -106,13 +113,8 @@ -<<<<<<< HEAD - -======= - ->>>>>>> refs/remotes/origin/master @@ -153,44 +155,247 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -<<<<<<< HEAD - -======= ->>>>>>> refs/remotes/origin/master - - - - - - - - - - - - - - + + + + -<<<<<<< HEAD - -======= - ->>>>>>> refs/remotes/origin/master - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - @@ -572,7 +666,6 @@ - @@ -617,6 +710,13 @@ + + + + + + + @@ -697,12 +797,6 @@ - project - - - - - @@ -731,229 +825,64 @@ - - - - - - + + - - - - - - + + - - - - - 1488937211416 + + 1491741542361 - - 1488937445293 - - - 1489156650791 - - - 1489206126088 - - - 1489209258691 - - - 1489211483985 - - - 1489303022487 - - - 1489646535233 - - - 1489650846639 - - - 1489658647678 - - - 1489658675286 - - - 1489659000096 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<<<<<<< HEAD - - - - - - - - - + - - - - - - - - - - - - - - -<<<<<<< HEAD - -======= - ->>>>>>> refs/remotes/origin/master - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + @@ -980,14 +909,8 @@ - - - - - + @@ -995,357 +918,105 @@ - - - - - - - - - - - - - - - + - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + - - + + + - + - - + + + - + - - + + + - + - - + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - + - - + + + - + - - + + + + + - + - - + + + - + - - + + + + + diff --git a/group15/1511_714512544/src/com/coderising/jvm/clz/AccessFlag.java b/group15/1511_714512544/src/com/coderising/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..faae056835 --- /dev/null +++ b/group15/1511_714512544/src/com/coderising/jvm/clz/AccessFlag.java @@ -0,0 +1,25 @@ +package com.coderising.jvm.clz; + +public class AccessFlag { + private int flagValue; + + public AccessFlag(int value) { + this.flagValue = value; + } + + public int getFlagValue() { + return flagValue; + } + + public void setFlagValue(int flag) { + this.flagValue = flag; + } + + public boolean isPublicClass(){ + return (this.flagValue & 0x0001) != 0; + } + public boolean isFinalClass(){ + return (this.flagValue & 0x0010) != 0; + } + +} \ No newline at end of file diff --git a/group15/1511_714512544/src/com/coderising/jvm/clz/ClassFile.java b/group15/1511_714512544/src/com/coderising/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..650ca8375d --- /dev/null +++ b/group15/1511_714512544/src/com/coderising/jvm/clz/ClassFile.java @@ -0,0 +1,75 @@ +package com.coderising.jvm.clz; + +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantPool; + +public class ClassFile { + + private int minorVersion; + private int majorVersion; + + private AccessFlag accessFlag; + private ClassIndex clzIndex; + private ConstantPool pool; + + + public ClassIndex getClzIndex() { + return clzIndex; + } + public AccessFlag getAccessFlag() { + return accessFlag; + } + public void setAccessFlag(AccessFlag accessFlag) { + this.accessFlag = accessFlag; + } + + + + public ConstantPool getConstantPool() { + return pool; + } + public int getMinorVersion() { + return minorVersion; + } + public void setMinorVersion(int minorVersion) { + this.minorVersion = minorVersion; + } + public int getMajorVersion() { + return majorVersion; + } + public void setMajorVersion(int majorVersion) { + this.majorVersion = majorVersion; + } + public void setConstPool(ConstantPool pool) { + this.pool = pool; + + } + public void setClassIndex(ClassIndex clzIndex) { + this.clzIndex = clzIndex; + } + + + + + public void print(){ + + if(this.accessFlag.isPublicClass()){ + System.out.println("Access flag : public "); + } + System.out.println("Class Name:"+ getClassName()); + + System.out.println("Super Class Name:"+ getSuperClassName()); + + + } + + private String getClassName(){ + int thisClassIndex = this.clzIndex.getThisClassIndex(); + ClassInfo thisClass = (ClassInfo)this.getConstantPool().getConstantInfo(thisClassIndex); + return thisClass.getClassName(); + } + private String getSuperClassName(){ + ClassInfo superClass = (ClassInfo)this.getConstantPool().getConstantInfo(this.clzIndex.getSuperClassIndex()); + return superClass.getClassName(); + } +} diff --git a/group15/1511_714512544/src/com/coderising/jvm/clz/ClassIndex.java b/group15/1511_714512544/src/com/coderising/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..e424f284b3 --- /dev/null +++ b/group15/1511_714512544/src/com/coderising/jvm/clz/ClassIndex.java @@ -0,0 +1,19 @@ +package com.coderising.jvm.clz; + +public class ClassIndex { + private int thisClassIndex; + private int superClassIndex; + + public int getThisClassIndex() { + return thisClassIndex; + } + public void setThisClassIndex(int thisClassIndex) { + this.thisClassIndex = thisClassIndex; + } + public int getSuperClassIndex() { + return superClassIndex; + } + public void setSuperClassIndex(int superClassIndex) { + this.superClassIndex = superClassIndex; + } +} \ No newline at end of file diff --git a/group15/1511_714512544/src/com/coderising/jvm/constant/ClassInfo.java b/group15/1511_714512544/src/com/coderising/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..aea9048ea4 --- /dev/null +++ b/group15/1511_714512544/src/com/coderising/jvm/constant/ClassInfo.java @@ -0,0 +1,24 @@ +package com.coderising.jvm.constant; + +public class ClassInfo extends ConstantInfo { + private int type = ConstantInfo.CLASS_INFO; + private int utf8Index ; + public ClassInfo(ConstantPool pool) { + super(pool); + } + public int getUtf8Index() { + return utf8Index; + } + public void setUtf8Index(int utf8Index) { + this.utf8Index = utf8Index; + } + public int getType() { + return type; + } + + public String getClassName() { + int index = getUtf8Index(); + UTF8Info utf8Info = (UTF8Info)constantPool.getConstantInfo(index); + return utf8Info.getValue(); + } +} diff --git a/group15/1511_714512544/src/com/coderising/jvm/constant/ConstantInfo.java b/group15/1511_714512544/src/com/coderising/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..466b072244 --- /dev/null +++ b/group15/1511_714512544/src/com/coderising/jvm/constant/ConstantInfo.java @@ -0,0 +1,29 @@ +package com.coderising.jvm.constant; + +public abstract class ConstantInfo { + public static final int UTF8_INFO = 1; + public static final int FLOAT_INFO = 4; + public static final int CLASS_INFO = 7; + public static final int STRING_INFO = 8; + public static final int FIELD_INFO = 9; + public static final int METHOD_INFO = 10; + public static final int NAME_AND_TYPE_INFO = 12; + protected ConstantPool constantPool; + + public ConstantInfo(){ + + } + + public ConstantInfo(ConstantPool pool) { + this.constantPool = pool; + } + public abstract int getType(); + + public ConstantPool getConstantPool() { + return constantPool; + } + public ConstantInfo getConstantInfo(int index){ + return this.constantPool.getConstantInfo(index); + } + +} diff --git a/group15/1511_714512544/src/com/coderising/jvm/constant/ConstantPool.java b/group15/1511_714512544/src/com/coderising/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..86c0445695 --- /dev/null +++ b/group15/1511_714512544/src/com/coderising/jvm/constant/ConstantPool.java @@ -0,0 +1,29 @@ +package com.coderising.jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List constantInfos = new ArrayList(); + + + public ConstantPool(){ + + } + public void addConstantInfo(ConstantInfo info){ + + this.constantInfos.add(info); + + } + + public ConstantInfo getConstantInfo(int index){ + return this.constantInfos.get(index); + } + public String getUTF8String(int index){ + return ((UTF8Info)this.constantInfos.get(index)).getValue(); + } + public Object getSize() { + return this.constantInfos.size() -1; + } +} diff --git a/group15/1511_714512544/src/com/coderising/jvm/constant/FieldRefInfo.java b/group15/1511_714512544/src/com/coderising/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..65475e194c --- /dev/null +++ b/group15/1511_714512544/src/com/coderising/jvm/constant/FieldRefInfo.java @@ -0,0 +1,54 @@ +package com.coderising.jvm.constant; + +public class FieldRefInfo extends ConstantInfo{ + private int type = ConstantInfo.FIELD_INFO; + private int classInfoIndex; + private int nameAndTypeIndex; + + public FieldRefInfo(ConstantPool pool) { + super(pool); + } + public int getType() { + return type; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String toString(){ + + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + + return getClassName() +" : "+ typeInfo.getName() + ":" + typeInfo.getTypeInfo() +"]"; + } + + public String getClassName(){ + + ClassInfo classInfo = (ClassInfo) this.getConstantInfo(this.getClassInfoIndex()); + + UTF8Info utf8Info = (UTF8Info)this.getConstantInfo(classInfo.getUtf8Index()); + + return utf8Info.getValue(); + + } + + public String getFieldName(){ + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getFieldType(){ + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } +} diff --git a/group15/1511_714512544/src/com/coderising/jvm/constant/MethodRefInfo.java b/group15/1511_714512544/src/com/coderising/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..7f05870020 --- /dev/null +++ b/group15/1511_714512544/src/com/coderising/jvm/constant/MethodRefInfo.java @@ -0,0 +1,55 @@ +package com.coderising.jvm.constant; + +public class MethodRefInfo extends ConstantInfo { + + private int type = ConstantInfo.METHOD_INFO; + + private int classInfoIndex; + private int nameAndTypeIndex; + + public MethodRefInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String toString(){ + + return getClassName() +" : "+ this.getMethodName() + " : " + this.getParamAndReturnType() ; + } + public String getClassName(){ + ConstantPool pool = this.getConstantPool(); + ClassInfo clzInfo = (ClassInfo)pool.getConstantInfo(this.getClassInfoIndex()); + return clzInfo.getClassName(); + } + + public String getMethodName(){ + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo)pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getParamAndReturnType(){ + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo)pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } + + + +} diff --git a/group15/1511_714512544/src/com/coderising/jvm/constant/NameAndTypeInfo.java b/group15/1511_714512544/src/com/coderising/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..402f9dec86 --- /dev/null +++ b/group15/1511_714512544/src/com/coderising/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,45 @@ +package com.coderising.jvm.constant; + +public class NameAndTypeInfo extends ConstantInfo{ + public int type = ConstantInfo.NAME_AND_TYPE_INFO; + + private int index1; + private int index2; + + public NameAndTypeInfo(ConstantPool pool) { + super(pool); + } + + public int getIndex1() { + return index1; + } + public void setIndex1(int index1) { + this.index1 = index1; + } + public int getIndex2() { + return index2; + } + public void setIndex2(int index2) { + this.index2 = index2; + } + public int getType() { + return type; + } + + + public String getName(){ + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info1 = (UTF8Info)pool.getConstantInfo(index1); + return utf8Info1.getValue(); + } + + public String getTypeInfo(){ + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info2 = (UTF8Info)pool.getConstantInfo(index2); + return utf8Info2.getValue(); + } + + public String toString(){ + return "(" + getName() + "," + getTypeInfo()+")"; + } +} diff --git a/group15/1511_714512544/src/com/coderising/jvm/constant/NullConstantInfo.java b/group15/1511_714512544/src/com/coderising/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..936736016f --- /dev/null +++ b/group15/1511_714512544/src/com/coderising/jvm/constant/NullConstantInfo.java @@ -0,0 +1,13 @@ +package com.coderising.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo(){ + + } + @Override + public int getType() { + return -1; + } + +} diff --git a/group15/1511_714512544/src/com/coderising/jvm/constant/StringInfo.java b/group15/1511_714512544/src/com/coderising/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..f1f8eb4ed4 --- /dev/null +++ b/group15/1511_714512544/src/com/coderising/jvm/constant/StringInfo.java @@ -0,0 +1,26 @@ +package com.coderising.jvm.constant; + +public class StringInfo extends ConstantInfo{ + private int type = ConstantInfo.STRING_INFO; + private int index; + public StringInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } + + + public String toString(){ + return this.getConstantPool().getUTF8String(index); + } + +} diff --git a/group15/1511_714512544/src/com/coderising/jvm/constant/UTF8Info.java b/group15/1511_714512544/src/com/coderising/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..5cac9f04f7 --- /dev/null +++ b/group15/1511_714512544/src/com/coderising/jvm/constant/UTF8Info.java @@ -0,0 +1,32 @@ +package com.coderising.jvm.constant; + +public class UTF8Info extends ConstantInfo{ + private int type = ConstantInfo.UTF8_INFO; + private int length ; + private String value; + public UTF8Info(ConstantPool pool) { + super(pool); + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getType() { + return type; + } + @Override + public String toString() { + return "UTF8Info [type=" + type + ", length=" + length + ", value=" + value +")]"; + } + public String getValue() { + return value; + } + public void setValue(String value) { + this.value = value; + } + + + +} diff --git a/group15/1511_714512544/src/com/coderising/jvm/loader/ByteCodeIterator.java b/group15/1511_714512544/src/com/coderising/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..9c9fac2839 --- /dev/null +++ b/group15/1511_714512544/src/com/coderising/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,5 @@ +package com.coderising.jvm.loader; + +public class ByteCodeIterator { + +} diff --git a/group15/1511_714512544/src/com/coderising/jvm/loader/ClassFileLoader.java b/group15/1511_714512544/src/com/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..33185d8175 --- /dev/null +++ b/group15/1511_714512544/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,140 @@ +package com.coderising.jvm.loader; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; + +import com.coderising.jvm.clz.ClassFile; + + + + + +public class ClassFileLoader { + + private List clzPaths = new ArrayList(); + + public byte[] readBinaryCode(String className) { + + className = className.replace('.', File.separatorChar) +".class"; + + for(String path : this.clzPaths){ + + String clzFileName = path + File.separatorChar + className; + byte[] codes = loadClassFile(clzFileName); + if(codes != null){ + return codes; + } + } + + return null; + + + + } + + private byte[] loadClassFile(String clzFileName) { + + File f = new File(clzFileName); + + try { + + return IOUtils.toByteArray(new FileInputStream(f)); + + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + + + public void addClassPath(String path) { + if(this.clzPaths.contains(path)){ + return; + } + + this.clzPaths.add(path); + + } + + + + public String getClassPath(){ + return StringUtils.join(this.clzPaths,";"); + } + + public ClassFile loadClass(String className) { + byte[] codes = this.readBinaryCode(className); + ClassFileParser parser = new ClassFileParser(); + return parser.parse(codes); + + } + + + + // ------------------------------backup------------------------ + public String getClassPath_V1(){ + + StringBuffer buffer = new StringBuffer(); + for(int i=0;i", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(10); + Assert.assertEquals("(Ljava/lang/String;I)V", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(11); + Assert.assertEquals("Code", utf8Info.getValue()); + } + + { + MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(12); + Assert.assertEquals(3, methodRef.getClassInfoIndex()); + Assert.assertEquals(13, methodRef.getNameAndTypeIndex()); + } + + { + NameAndTypeInfo nameAndType = (NameAndTypeInfo) pool.getConstantInfo(13); + Assert.assertEquals(9, nameAndType.getIndex1()); + Assert.assertEquals(14, nameAndType.getIndex2()); + } + //抽查几个吧 + { + MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(45); + Assert.assertEquals(1, methodRef.getClassInfoIndex()); + Assert.assertEquals(46, methodRef.getNameAndTypeIndex()); + } + + { + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(53); + Assert.assertEquals("EmployeeV1.java", utf8Info.getValue()); + } + } + @Test + public void testClassIndex(){ + + ClassIndex clzIndex = clzFile.getClzIndex(); + ClassInfo thisClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getThisClassIndex()); + ClassInfo superClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getSuperClassIndex()); + + + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); + Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); + } + + + +} diff --git a/group15/1511_714512544/src/com/coderising/jvm/test/EmployeeV1.java b/group15/1511_714512544/src/com/coderising/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..e644b00b41 --- /dev/null +++ b/group15/1511_714512544/src/com/coderising/jvm/test/EmployeeV1.java @@ -0,0 +1,27 @@ +package com.coderising.jvm.test; + +public class EmployeeV1 { + + private String name; + private int age; + + public EmployeeV1(String name, int age) { + this.name = name; + this.age = age; + } + + public void setName(String name) { + this.name = name; + } + public void setAge(int age){ + this.age = age; + } + public void sayHello() { + System.out.println("Hello , this is class Employee "); + } + public static void main(String[] args){ + EmployeeV1 p = new EmployeeV1("Andy",29); + p.sayHello(); + + } +} \ No newline at end of file diff --git a/group15/1511_714512544/src/com/coderising/jvm/util/Util.java b/group15/1511_714512544/src/com/coderising/jvm/util/Util.java new file mode 100644 index 0000000000..0c4cc8c57c --- /dev/null +++ b/group15/1511_714512544/src/com/coderising/jvm/util/Util.java @@ -0,0 +1,24 @@ +package com.coderising.jvm.util; + +public class Util { + public static int byteToInt(byte[] codes){ + String s1 = byteToHexString(codes); + return Integer.valueOf(s1, 16).intValue(); + } + + + + public static String byteToHexString(byte[] codes ){ + StringBuffer buffer = new StringBuffer(); + for(int i=0;i= capacity) { + removeLast(); + + } + + addNewNodetoHead(node); + } + } + + private void addNewNodetoHead(Node node) { + + if(isEmpty()){ + + node.prev = null; + node.next = null; + first = node; + last = node; + + } else{ + node.prev = null; + node.next = first; + first.prev = node; + first = node; + } + this.currentSize ++; + } + + private Node find(int data){ + + Node node = first; + while(node != null){ + if(node.pageNum == data){ + return node; + } + node = node.next; + } + return null; + + } + + /** + * 删除链表尾部节点 表示 删除最少使用的缓存对象 + */ + private void removeLast() { + Node prev = last.prev; + prev.next = null; + last.prev = null; + last = prev; + this.currentSize --; + } + + /** + * 移动到链表头,表示这个节点是最新使用过的 + * + * @param node + */ + private void moveExistingNodeToHead(Node node) { + + if (node == first) { + + return; + } + else if(node == last){ + //当前节点是链表尾, 需要放到链表头 + Node prevNode = node.prev; + prevNode.next = null; + last.prev = null; + last = prevNode; + + } else{ + //node 在链表的中间, 把node 的前后节点连接起来 + Node prevNode = node.prev; + prevNode.next = node.next; + + Node nextNode = node.next; + nextNode.prev = prevNode; + + } + + node.prev = null; + node.next = first; + first.prev = node; + first = node; + + } + private boolean isEmpty(){ + return (first == null) && (last == null); + } + + public String toString(){ + StringBuilder buffer = new StringBuilder(); + Node node = first; + while(node != null){ + buffer.append(node.pageNum); + + node = node.next; + if(node != null){ + buffer.append(","); + } + } + return buffer.toString(); + } + +} diff --git a/group15/1511_714512544/src/com/coding/basic/LRUPageFrameTest.java b/group15/1511_714512544/src/com/coding/basic/LRUPageFrameTest.java new file mode 100644 index 0000000000..9ea9809f10 --- /dev/null +++ b/group15/1511_714512544/src/com/coding/basic/LRUPageFrameTest.java @@ -0,0 +1,33 @@ +package com.coding.basic; + +import org.junit.Assert; + +import org.junit.Test; + +public class LRUPageFrameTest { + + @Test + public void testAccess() { + LRUPageFrame frame = new LRUPageFrame(3); + frame.access(7); + frame.access(0); + frame.access(1); + Assert.assertEquals("1,0,7", frame.toString()); + frame.access(2); + Assert.assertEquals("2,1,0", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1", frame.toString()); + frame.access(3); + Assert.assertEquals("3,0,2", frame.toString()); + frame.access(0); + Assert.assertEquals("0,3,2", frame.toString()); + frame.access(4); + Assert.assertEquals("4,0,3", frame.toString()); + frame.access(5); + Assert.assertEquals("5,4,0", frame.toString()); + + } + +} From f48f98ded2a7d7d041d65e73f40b5a07cd132bf3 Mon Sep 17 00:00:00 2001 From: maishihang <446031103@qq.com> Date: Sun, 9 Apr 2017 22:04:44 +0800 Subject: [PATCH 104/203] update JVM WORK1 --- .../jvm/loader/ClassFileLoader.java | 53 +++++- .../jvm/test/ClassFileloaderTest.java | 5 +- .../datastructure/linklist/LRUPageFrame.java | 164 +++++++++++++++++- .../datastructure/{basic => stack}/Stack.java | 2 +- .../com/datastructure/stack/StackUtil.java | 41 +++++ 5 files changed, 249 insertions(+), 16 deletions(-) rename group12/446031103/src/com/datastructure/{basic => stack}/Stack.java (97%) create mode 100644 group12/446031103/src/com/datastructure/stack/StackUtil.java diff --git a/group12/446031103/src/com/coderising/jvm/loader/ClassFileLoader.java b/group12/446031103/src/com/coderising/jvm/loader/ClassFileLoader.java index e021b94d38..27f98c8714 100644 --- a/group12/446031103/src/com/coderising/jvm/loader/ClassFileLoader.java +++ b/group12/446031103/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -1,39 +1,76 @@ package com.coderising.jvm.loader; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; import java.util.ArrayList; import java.util.List; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; public class ClassFileLoader { - + private List clzPaths = new ArrayList(); public byte[] readBinaryCode(String className) { - return null; + className = className.replace('.', File.separatorChar) +".class"; + for(String path : this.clzPaths){ + + String clzFileName = path + File.separatorChar + className; + byte[] codes = loadClassFile(clzFileName); + if(codes != null){ + return codes; + } + } + return null; } private byte[] loadClassFile(String clzFileName) { - return null; + File f = new File(clzFileName); + + try { + + return IOUtils.toByteArray(new FileInputStream(f)); + + } catch (IOException e) { + e.printStackTrace(); + return null; + } } public void addClassPath(String path) { + if(this.clzPaths.contains(path)){ + return; + } + + this.clzPaths.add(path); } - public String getClassPath_V1(){ - - return null; + public String getClassPath_V1(){ + + StringBuffer buffer = new StringBuffer(); + for(int i=0;i= capacity) { + removeLast(); + + } + + addNewNodetoHead(node); + + + + + } + } + + private void addNewNodetoHead(Node node) { + + if(isEmpty()){ + + node.prev = null; + node.next = null; + first = node; + last = node; + + } else{ + node.prev = null; + node.next = first; + first.prev = node; + first = node; + } + this.currentSize ++; + } + + private Node find(int data){ + + Node node = first; + while(node != null){ + if(node.pageNum == data){ + return node; + } + node = node.next; + } + return null; + + } + + + + + + + /** + * 删除链表尾部节点 表示 删除最少使用的缓存对象 + */ + private void removeLast() { + Node prev = last.prev; + prev.next = null; + last.prev = null; + last = prev; + this.currentSize --; + } + + /** + * 移动到链表头,表示这个节点是最新使用过的 + * + * @param node + */ + private void moveExistingNodeToHead(Node node) { + + if (node == first) { + + return; + } + else if(node == last){ + //当前节点是链表尾, 需要放到链表头 + Node prevNode = node.prev; + prevNode.next = null; + last.prev = null; + last = prevNode; + + } else{ + //node 在链表的中间, 把node 的前后节点连接起来 + Node prevNode = node.prev; + prevNode.next = node.next; + + Node nextNode = node.next; + nextNode.prev = prevNode; + + + } + + node.prev = null; + node.next = first; + first.prev = node; + first = node; + + } + private boolean isEmpty(){ + return (first == null) && (last == null); + } + + public String toString(){ + StringBuilder buffer = new StringBuilder(); + Node node = first; + while(node != null){ + buffer.append(node.pageNum); + + node = node.next; + if(node != null){ + buffer.append(","); + } + } + return buffer.toString(); + } + + /*private static class Node { Node prev; Node next; @@ -38,12 +194,12 @@ public LRUPageFrame(int capacity) { first = new Node(); } - /** + *//** * 获取缓存中对象 * * @param key * @return - */ + *//* public void access(int pageNum) { if(null==this.last){ this.last = new Node(this.first,null,pageNum); @@ -153,6 +309,6 @@ public String toString(){ } } return buffer.toString(); - } + }*/ } \ No newline at end of file diff --git a/group12/446031103/src/com/datastructure/basic/Stack.java b/group12/446031103/src/com/datastructure/stack/Stack.java similarity index 97% rename from group12/446031103/src/com/datastructure/basic/Stack.java rename to group12/446031103/src/com/datastructure/stack/Stack.java index 3088b0a000..82cdf178a6 100644 --- a/group12/446031103/src/com/datastructure/basic/Stack.java +++ b/group12/446031103/src/com/datastructure/stack/Stack.java @@ -1,4 +1,4 @@ -package com.datastructure.basic; +package com.datastructure.stack; import com.datastructure.array.ArrayList; diff --git a/group12/446031103/src/com/datastructure/stack/StackUtil.java b/group12/446031103/src/com/datastructure/stack/StackUtil.java new file mode 100644 index 0000000000..64c3bb07e7 --- /dev/null +++ b/group12/446031103/src/com/datastructure/stack/StackUtil.java @@ -0,0 +1,41 @@ +package com.datastructure.stack; + +public class StackUtil { + /** + * 假设栈中的元素是Integer, 从栈顶到栈底是 : 5,4,3,2,1 调用该方法后, 元素次序变为: 1,2,3,4,5 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + */ + public static void reverse(Stack s) { + + } + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s,Object o) { + + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * @param len + * @return + */ + public static Object[] getTop(Stack s,int len) { + return null; + } + /** + * 字符串s 可能包含这些字符: ( ) [ ] { }, a,b,c... x,yz + * 使用堆栈检查字符串s中的括号是不是成对出现的。 + * 例如s = "([e{d}f])" , 则该字符串中的括号是成对出现, 该方法返回true + * 如果 s = "([b{x]y})", 则该字符串中的括号不是成对出现的, 该方法返回false; + * @param s + * @return + */ + public static boolean isValidPairs(String s){ + return false; + } +} From 86eac03cb91b5f91be8032f006092676a9c5ede0 Mon Sep 17 00:00:00 2001 From: gabywong Date: Sun, 9 Apr 2017 22:08:49 +0800 Subject: [PATCH 105/203] =?UTF-8?q?4=E6=9C=889=E4=BD=9C=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coding/basic/stuck/StackUtil.java | 105 ++++++++++ .../src/coderising/jvm/clz/AccessFlag.java | 25 +++ .../src/coderising/jvm/clz/ClassFile.java | 75 +++++++ .../src/coderising/jvm/clz/ClassIndex.java | 19 ++ .../coderising/jvm/constant/ClassInfo.java | 24 +++ .../coderising/jvm/constant/ConstantInfo.java | 29 +++ .../coderising/jvm/constant/ConstantPool.java | 29 +++ .../coderising/jvm/constant/FieldRefInfo.java | 54 +++++ .../jvm/constant/MethodRefInfo.java | 55 +++++ .../jvm/constant/NameAndTypeInfo.java | 45 ++++ .../jvm/constant/NullConstantInfo.java | 13 ++ .../coderising/jvm/constant/StringInfo.java | 26 +++ .../src/coderising/jvm/constant/UTF8Info.java | 32 +++ .../jvm/loader/ByteCodeIterator.java | 32 +++ .../jvm/loader/ClassFileLoader.java | 136 ++++++++++++ .../jvm/loader/ClassFileParser.java | 105 ++++++++++ .../jvm/test/ClassFileloaderTest.java | 198 ++++++++++++++++++ .../src/coderising/jvm/test/EmployeeV1.java | 28 +++ .../src/coderising/jvm/util/Util.java | 24 +++ 19 files changed, 1054 insertions(+) create mode 100644 group15/1513_121469918/HomeWork/src/task0409/coding/basic/stuck/StackUtil.java create mode 100644 group15/1513_121469918/mini-jvm/src/coderising/jvm/clz/AccessFlag.java create mode 100644 group15/1513_121469918/mini-jvm/src/coderising/jvm/clz/ClassFile.java create mode 100644 group15/1513_121469918/mini-jvm/src/coderising/jvm/clz/ClassIndex.java create mode 100644 group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/ClassInfo.java create mode 100644 group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/ConstantInfo.java create mode 100644 group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/ConstantPool.java create mode 100644 group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/FieldRefInfo.java create mode 100644 group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/MethodRefInfo.java create mode 100644 group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/NameAndTypeInfo.java create mode 100644 group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/NullConstantInfo.java create mode 100644 group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/StringInfo.java create mode 100644 group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/UTF8Info.java create mode 100644 group15/1513_121469918/mini-jvm/src/coderising/jvm/loader/ByteCodeIterator.java create mode 100644 group15/1513_121469918/mini-jvm/src/coderising/jvm/loader/ClassFileLoader.java create mode 100644 group15/1513_121469918/mini-jvm/src/coderising/jvm/loader/ClassFileParser.java create mode 100644 group15/1513_121469918/mini-jvm/src/coderising/jvm/test/ClassFileloaderTest.java create mode 100644 group15/1513_121469918/mini-jvm/src/coderising/jvm/test/EmployeeV1.java create mode 100644 group15/1513_121469918/mini-jvm/src/coderising/jvm/util/Util.java diff --git a/group15/1513_121469918/HomeWork/src/task0409/coding/basic/stuck/StackUtil.java b/group15/1513_121469918/HomeWork/src/task0409/coding/basic/stuck/StackUtil.java new file mode 100644 index 0000000000..db2726b278 --- /dev/null +++ b/group15/1513_121469918/HomeWork/src/task0409/coding/basic/stuck/StackUtil.java @@ -0,0 +1,105 @@ +package task0409.coding.basic.stuck; + +import java.util.Stack; + +public class StackUtil { + /** + * 假设栈中的元素是Integer, 从栈顶到栈底是 : 5,4,3,2,1 调用该方法后, 元素次序变为: 1,2,3,4,5 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + */ + public static void reverse(Stack s) { + if(null == s){ + return; + } + Stack temp1 = new Stack(); + Stack temp2 = new Stack(); + while(!s.isEmpty()){ + temp1.push(s.pop()); + } + while(!temp1.isEmpty()){ + temp2.push(temp1.pop()); + } + while(!temp2.isEmpty()){ + s.push(temp2.pop()); + } + + } + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s, Object o) { + if(null == o|| null == s){ + return; + } + if(!s.isEmpty()){ + Object top = s.pop(); + remove(s,o); + if(top.equals(o)){ + return; + }else{ + s.push(top); + } + } + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, + * 可以使用另外一个栈来辅助 + * + * @param len + * @return + */ + public static Object[] getTop(Stack s, int len) { + if(len<=0){ + return null; + } + Object[] result = new Object[len]; + Stack temp = new Stack(); + while(len>0){ + temp.push(s.pop()); + len--; + result[len] = temp.peek(); + } + while(!temp.isEmpty()){ + s.push(temp.pop()); + } + return result; + } + + /** + * 字符串s 可能包含这些字符: ( ) [ ] { }, a,b,c... x,yz 使用堆栈检查字符串s中的括号是不是成对出现的。 例如s = + * "([e{d}f])" , 则该字符串中的括号是成对出现, 该方法返回true 如果 s = "([b{x]y})", + * 则该字符串中的括号不是成对出现的, 该方法返回false; + * + * @param s + * @return + */ + public static boolean isValidPairs(String s) { + char[] chs = s.toCharArray(); + Stack left = new Stack(); + Stack right = new Stack(); + + for(int i=0;i constantInfos = new ArrayList(); + + + public ConstantPool(){ + + } + public void addConstantInfo(ConstantInfo info){ + + this.constantInfos.add(info); + + } + + public ConstantInfo getConstantInfo(int index){ + return this.constantInfos.get(index); + } + public String getUTF8String(int index){ + return ((UTF8Info)this.constantInfos.get(index)).getValue(); + } + public Object getSize() { + return this.constantInfos.size() -1; + } +} diff --git a/group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/FieldRefInfo.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..7b1662b050 --- /dev/null +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/FieldRefInfo.java @@ -0,0 +1,54 @@ +package coderising.jvm.constant; + +public class FieldRefInfo extends ConstantInfo{ + private int type = ConstantInfo.FIELD_INFO; + private int classInfoIndex; + private int nameAndTypeIndex; + + public FieldRefInfo(ConstantPool pool) { + super(pool); + } + public int getType() { + return type; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String toString(){ + + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + + return getClassName() +" : "+ typeInfo.getName() + ":" + typeInfo.getTypeInfo() +"]"; + } + + public String getClassName(){ + + ClassInfo classInfo = (ClassInfo) this.getConstantInfo(this.getClassInfoIndex()); + + UTF8Info utf8Info = (UTF8Info)this.getConstantInfo(classInfo.getUtf8Index()); + + return utf8Info.getValue(); + + } + + public String getFieldName(){ + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getFieldType(){ + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } +} diff --git a/group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/MethodRefInfo.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..f051473836 --- /dev/null +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/MethodRefInfo.java @@ -0,0 +1,55 @@ +package coderising.jvm.constant; + +public class MethodRefInfo extends ConstantInfo { + + private int type = ConstantInfo.METHOD_INFO; + + private int classInfoIndex; + private int nameAndTypeIndex; + + public MethodRefInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String toString(){ + + return getClassName() +" : "+ this.getMethodName() + " : " + this.getParamAndReturnType() ; + } + public String getClassName(){ + ConstantPool pool = this.getConstantPool(); + ClassInfo clzInfo = (ClassInfo)pool.getConstantInfo(this.getClassInfoIndex()); + return clzInfo.getClassName(); + } + + public String getMethodName(){ + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo)pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getParamAndReturnType(){ + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo)pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } + + + +} diff --git a/group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/NameAndTypeInfo.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..af711bd28e --- /dev/null +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,45 @@ +package coderising.jvm.constant; + +public class NameAndTypeInfo extends ConstantInfo{ + public int type = ConstantInfo.NAME_AND_TYPE_INFO; + + private int index1; + private int index2; + + public NameAndTypeInfo(ConstantPool pool) { + super(pool); + } + + public int getIndex1() { + return index1; + } + public void setIndex1(int index1) { + this.index1 = index1; + } + public int getIndex2() { + return index2; + } + public void setIndex2(int index2) { + this.index2 = index2; + } + public int getType() { + return type; + } + + + public String getName(){ + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info1 = (UTF8Info)pool.getConstantInfo(index1); + return utf8Info1.getValue(); + } + + public String getTypeInfo(){ + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info2 = (UTF8Info)pool.getConstantInfo(index2); + return utf8Info2.getValue(); + } + + public String toString(){ + return "(" + getName() + "," + getTypeInfo()+")"; + } +} diff --git a/group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/NullConstantInfo.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..cfbe82ac9d --- /dev/null +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/NullConstantInfo.java @@ -0,0 +1,13 @@ +package coderising.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo(){ + + } + @Override + public int getType() { + return -1; + } + +} diff --git a/group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/StringInfo.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..8582ac7ac5 --- /dev/null +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/StringInfo.java @@ -0,0 +1,26 @@ +package coderising.jvm.constant; + +public class StringInfo extends ConstantInfo{ + private int type = ConstantInfo.STRING_INFO; + private int index; + public StringInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } + + + public String toString(){ + return this.getConstantPool().getUTF8String(index); + } + +} diff --git a/group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/UTF8Info.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..f17afdc541 --- /dev/null +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/UTF8Info.java @@ -0,0 +1,32 @@ +package coderising.jvm.constant; + +public class UTF8Info extends ConstantInfo{ + private int type = ConstantInfo.UTF8_INFO; + private int length ; + private String value; + public UTF8Info(ConstantPool pool) { + super(pool); + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getType() { + return type; + } + @Override + public String toString() { + return "UTF8Info [type=" + type + ", length=" + length + ", value=" + value +")]"; + } + public String getValue() { + return value; + } + public void setValue(String value) { + this.value = value; + } + + + +} diff --git a/group15/1513_121469918/mini-jvm/src/coderising/jvm/loader/ByteCodeIterator.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..cf01b4d9e1 --- /dev/null +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,32 @@ +package coderising.jvm.loader; + +import coderising.jvm.util.Util; + +public class ByteCodeIterator { + private byte[] codes; + private int pos =0; + public ByteCodeIterator(byte[] codes){ + this.codes = codes; + } + public String nextU4ToHexString() { + byte[] bys = new byte[]{codes[pos++],codes[pos++],codes[pos++],codes[pos++]}; + return Util.byteToHexString(bys); + } + + public int nextU1ToInt(){ + byte[] bys = new byte[]{codes[pos++]}; + return Util.byteToInt(bys); + } + public int nextU2ToInt(){ + byte[] bys = new byte[]{codes[pos++],codes[pos++]}; + return Util.byteToInt(bys); + } + public String nextString(int len){ + byte[] bys = new byte[len]; + for (int i = 0; i < bys.length; i++) { + bys[i]=codes[pos++]; + } + String result = new String(bys); + return result; + } +} diff --git a/group15/1513_121469918/mini-jvm/src/coderising/jvm/loader/ClassFileLoader.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..c268287a98 --- /dev/null +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,136 @@ +package coderising.jvm.loader; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; + +import coderising.jvm.clz.ClassFile; + +public class ClassFileLoader { + + private List clzPaths = new ArrayList(); + + public byte[] readBinaryCode(String className) { + + className = className.replace('.', File.separatorChar) +".class"; + + for(String path : this.clzPaths){ + + String clzFileName = path + File.separatorChar + className; + byte[] codes = loadClassFile(clzFileName); + if(codes != null){ + return codes; + } + } + + return null; + + + + } + + private byte[] loadClassFile(String clzFileName) { + + File f = new File(clzFileName); + + try { + + return IOUtils.toByteArray(new FileInputStream(f)); + + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + + + public void addClassPath(String path) { + if(this.clzPaths.contains(path)){ + return; + } + + this.clzPaths.add(path); + + } + + + + public String getClassPath(){ + return StringUtils.join(this.clzPaths,";"); + } + + public ClassFile loadClass(String className) { + byte[] codes = this.readBinaryCode(className); + ClassFileParser parser = new ClassFileParser(); + return parser.parse(codes); + + } + + + + // ------------------------------backup------------------------ + public String getClassPath_V1(){ + + StringBuffer buffer = new StringBuffer(); + for(int i=0;i", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(10); + Assert.assertEquals("(Ljava/lang/String;I)V", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(11); + Assert.assertEquals("Code", utf8Info.getValue()); + } + + { + MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(12); + Assert.assertEquals(3, methodRef.getClassInfoIndex()); + Assert.assertEquals(13, methodRef.getNameAndTypeIndex()); + } + + { + NameAndTypeInfo nameAndType = (NameAndTypeInfo) pool.getConstantInfo(13); + Assert.assertEquals(9, nameAndType.getIndex1()); + Assert.assertEquals(14, nameAndType.getIndex2()); + } + //抽查几个吧 + { + MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(45); + Assert.assertEquals(1, methodRef.getClassInfoIndex()); + Assert.assertEquals(46, methodRef.getNameAndTypeIndex()); + } + + { + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(53); + Assert.assertEquals("EmployeeV1.java", utf8Info.getValue()); + } + } + @Test + public void testClassIndex(){ + + ClassIndex clzIndex = clzFile.getClzIndex(); + ClassInfo thisClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getThisClassIndex()); + ClassInfo superClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getSuperClassIndex()); + + + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); + Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); + } + + + +} diff --git a/group15/1513_121469918/mini-jvm/src/coderising/jvm/test/EmployeeV1.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..2261019193 --- /dev/null +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/test/EmployeeV1.java @@ -0,0 +1,28 @@ +package coderising.jvm.test; + +public class EmployeeV1 { + + + private String name; + private int age; + + public EmployeeV1(String name, int age) { + this.name = name; + this.age = age; + } + + public void setName(String name) { + this.name = name; + } + public void setAge(int age){ + this.age = age; + } + public void sayHello() { + System.out.println("Hello , this is class Employee "); + } + public static void main(String[] args){ + EmployeeV1 p = new EmployeeV1("Andy",29); + p.sayHello(); + + } +} \ No newline at end of file diff --git a/group15/1513_121469918/mini-jvm/src/coderising/jvm/util/Util.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/util/Util.java new file mode 100644 index 0000000000..ce3848b9df --- /dev/null +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/util/Util.java @@ -0,0 +1,24 @@ +package coderising.jvm.util; + +public class Util { + public static int byteToInt(byte[] codes){ + String s1 = byteToHexString(codes); + return Integer.valueOf(s1, 16).intValue(); + } + + + + public static String byteToHexString(byte[] codes ){ + StringBuffer buffer = new StringBuffer(); + for(int i=0;i Date: Sun, 9 Apr 2017 22:08:52 +0800 Subject: [PATCH 106/203] =?UTF-8?q?update=20jvm=20work=20=E7=BC=BAsatck=20?= =?UTF-8?q?util?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/coderising/jvm/clz/AccessFlag.java | 25 ++++ .../src/com/coderising/jvm/clz/ClassFile.java | 75 ++++++++++ .../com/coderising/jvm/clz/ClassIndex.java | 19 +++ .../coderising/jvm/constant/ClassInfo.java | 24 +++ .../coderising/jvm/constant/ConstantInfo.java | 29 ++++ .../coderising/jvm/constant/ConstantPool.java | 29 ++++ .../coderising/jvm/constant/FieldRefInfo.java | 54 +++++++ .../jvm/constant/MethodRefInfo.java | 55 +++++++ .../jvm/constant/NameAndTypeInfo.java | 45 ++++++ .../jvm/constant/NullConstantInfo.java | 13 ++ .../coderising/jvm/constant/StringInfo.java | 26 ++++ .../com/coderising/jvm/constant/UTF8Info.java | 32 ++++ .../jvm/loader/ByteCodeIterator.java | 5 + .../jvm/loader/ClassFileLoader.java | 90 ++++++++++-- .../jvm/loader/ClassFileParser.java | 44 ++++++ .../jvm/test/ClassFileloaderTest.java | 139 ++++++++++++++++-- .../com/coderising/jvm/test/EmployeeV1.java | 2 +- .../src/com/coderising/jvm/util/Util.java | 24 +++ 18 files changed, 700 insertions(+), 30 deletions(-) create mode 100644 group12/446031103/src/com/coderising/jvm/clz/AccessFlag.java create mode 100644 group12/446031103/src/com/coderising/jvm/clz/ClassFile.java create mode 100644 group12/446031103/src/com/coderising/jvm/clz/ClassIndex.java create mode 100644 group12/446031103/src/com/coderising/jvm/constant/ClassInfo.java create mode 100644 group12/446031103/src/com/coderising/jvm/constant/ConstantInfo.java create mode 100644 group12/446031103/src/com/coderising/jvm/constant/ConstantPool.java create mode 100644 group12/446031103/src/com/coderising/jvm/constant/FieldRefInfo.java create mode 100644 group12/446031103/src/com/coderising/jvm/constant/MethodRefInfo.java create mode 100644 group12/446031103/src/com/coderising/jvm/constant/NameAndTypeInfo.java create mode 100644 group12/446031103/src/com/coderising/jvm/constant/NullConstantInfo.java create mode 100644 group12/446031103/src/com/coderising/jvm/constant/StringInfo.java create mode 100644 group12/446031103/src/com/coderising/jvm/constant/UTF8Info.java create mode 100644 group12/446031103/src/com/coderising/jvm/loader/ByteCodeIterator.java create mode 100644 group12/446031103/src/com/coderising/jvm/loader/ClassFileParser.java create mode 100644 group12/446031103/src/com/coderising/jvm/util/Util.java diff --git a/group12/446031103/src/com/coderising/jvm/clz/AccessFlag.java b/group12/446031103/src/com/coderising/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..faae056835 --- /dev/null +++ b/group12/446031103/src/com/coderising/jvm/clz/AccessFlag.java @@ -0,0 +1,25 @@ +package com.coderising.jvm.clz; + +public class AccessFlag { + private int flagValue; + + public AccessFlag(int value) { + this.flagValue = value; + } + + public int getFlagValue() { + return flagValue; + } + + public void setFlagValue(int flag) { + this.flagValue = flag; + } + + public boolean isPublicClass(){ + return (this.flagValue & 0x0001) != 0; + } + public boolean isFinalClass(){ + return (this.flagValue & 0x0010) != 0; + } + +} \ No newline at end of file diff --git a/group12/446031103/src/com/coderising/jvm/clz/ClassFile.java b/group12/446031103/src/com/coderising/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..650ca8375d --- /dev/null +++ b/group12/446031103/src/com/coderising/jvm/clz/ClassFile.java @@ -0,0 +1,75 @@ +package com.coderising.jvm.clz; + +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantPool; + +public class ClassFile { + + private int minorVersion; + private int majorVersion; + + private AccessFlag accessFlag; + private ClassIndex clzIndex; + private ConstantPool pool; + + + public ClassIndex getClzIndex() { + return clzIndex; + } + public AccessFlag getAccessFlag() { + return accessFlag; + } + public void setAccessFlag(AccessFlag accessFlag) { + this.accessFlag = accessFlag; + } + + + + public ConstantPool getConstantPool() { + return pool; + } + public int getMinorVersion() { + return minorVersion; + } + public void setMinorVersion(int minorVersion) { + this.minorVersion = minorVersion; + } + public int getMajorVersion() { + return majorVersion; + } + public void setMajorVersion(int majorVersion) { + this.majorVersion = majorVersion; + } + public void setConstPool(ConstantPool pool) { + this.pool = pool; + + } + public void setClassIndex(ClassIndex clzIndex) { + this.clzIndex = clzIndex; + } + + + + + public void print(){ + + if(this.accessFlag.isPublicClass()){ + System.out.println("Access flag : public "); + } + System.out.println("Class Name:"+ getClassName()); + + System.out.println("Super Class Name:"+ getSuperClassName()); + + + } + + private String getClassName(){ + int thisClassIndex = this.clzIndex.getThisClassIndex(); + ClassInfo thisClass = (ClassInfo)this.getConstantPool().getConstantInfo(thisClassIndex); + return thisClass.getClassName(); + } + private String getSuperClassName(){ + ClassInfo superClass = (ClassInfo)this.getConstantPool().getConstantInfo(this.clzIndex.getSuperClassIndex()); + return superClass.getClassName(); + } +} diff --git a/group12/446031103/src/com/coderising/jvm/clz/ClassIndex.java b/group12/446031103/src/com/coderising/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..e424f284b3 --- /dev/null +++ b/group12/446031103/src/com/coderising/jvm/clz/ClassIndex.java @@ -0,0 +1,19 @@ +package com.coderising.jvm.clz; + +public class ClassIndex { + private int thisClassIndex; + private int superClassIndex; + + public int getThisClassIndex() { + return thisClassIndex; + } + public void setThisClassIndex(int thisClassIndex) { + this.thisClassIndex = thisClassIndex; + } + public int getSuperClassIndex() { + return superClassIndex; + } + public void setSuperClassIndex(int superClassIndex) { + this.superClassIndex = superClassIndex; + } +} \ No newline at end of file diff --git a/group12/446031103/src/com/coderising/jvm/constant/ClassInfo.java b/group12/446031103/src/com/coderising/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..aea9048ea4 --- /dev/null +++ b/group12/446031103/src/com/coderising/jvm/constant/ClassInfo.java @@ -0,0 +1,24 @@ +package com.coderising.jvm.constant; + +public class ClassInfo extends ConstantInfo { + private int type = ConstantInfo.CLASS_INFO; + private int utf8Index ; + public ClassInfo(ConstantPool pool) { + super(pool); + } + public int getUtf8Index() { + return utf8Index; + } + public void setUtf8Index(int utf8Index) { + this.utf8Index = utf8Index; + } + public int getType() { + return type; + } + + public String getClassName() { + int index = getUtf8Index(); + UTF8Info utf8Info = (UTF8Info)constantPool.getConstantInfo(index); + return utf8Info.getValue(); + } +} diff --git a/group12/446031103/src/com/coderising/jvm/constant/ConstantInfo.java b/group12/446031103/src/com/coderising/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..466b072244 --- /dev/null +++ b/group12/446031103/src/com/coderising/jvm/constant/ConstantInfo.java @@ -0,0 +1,29 @@ +package com.coderising.jvm.constant; + +public abstract class ConstantInfo { + public static final int UTF8_INFO = 1; + public static final int FLOAT_INFO = 4; + public static final int CLASS_INFO = 7; + public static final int STRING_INFO = 8; + public static final int FIELD_INFO = 9; + public static final int METHOD_INFO = 10; + public static final int NAME_AND_TYPE_INFO = 12; + protected ConstantPool constantPool; + + public ConstantInfo(){ + + } + + public ConstantInfo(ConstantPool pool) { + this.constantPool = pool; + } + public abstract int getType(); + + public ConstantPool getConstantPool() { + return constantPool; + } + public ConstantInfo getConstantInfo(int index){ + return this.constantPool.getConstantInfo(index); + } + +} diff --git a/group12/446031103/src/com/coderising/jvm/constant/ConstantPool.java b/group12/446031103/src/com/coderising/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..86c0445695 --- /dev/null +++ b/group12/446031103/src/com/coderising/jvm/constant/ConstantPool.java @@ -0,0 +1,29 @@ +package com.coderising.jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List constantInfos = new ArrayList(); + + + public ConstantPool(){ + + } + public void addConstantInfo(ConstantInfo info){ + + this.constantInfos.add(info); + + } + + public ConstantInfo getConstantInfo(int index){ + return this.constantInfos.get(index); + } + public String getUTF8String(int index){ + return ((UTF8Info)this.constantInfos.get(index)).getValue(); + } + public Object getSize() { + return this.constantInfos.size() -1; + } +} diff --git a/group12/446031103/src/com/coderising/jvm/constant/FieldRefInfo.java b/group12/446031103/src/com/coderising/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..65475e194c --- /dev/null +++ b/group12/446031103/src/com/coderising/jvm/constant/FieldRefInfo.java @@ -0,0 +1,54 @@ +package com.coderising.jvm.constant; + +public class FieldRefInfo extends ConstantInfo{ + private int type = ConstantInfo.FIELD_INFO; + private int classInfoIndex; + private int nameAndTypeIndex; + + public FieldRefInfo(ConstantPool pool) { + super(pool); + } + public int getType() { + return type; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String toString(){ + + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + + return getClassName() +" : "+ typeInfo.getName() + ":" + typeInfo.getTypeInfo() +"]"; + } + + public String getClassName(){ + + ClassInfo classInfo = (ClassInfo) this.getConstantInfo(this.getClassInfoIndex()); + + UTF8Info utf8Info = (UTF8Info)this.getConstantInfo(classInfo.getUtf8Index()); + + return utf8Info.getValue(); + + } + + public String getFieldName(){ + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getFieldType(){ + NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } +} diff --git a/group12/446031103/src/com/coderising/jvm/constant/MethodRefInfo.java b/group12/446031103/src/com/coderising/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..7f05870020 --- /dev/null +++ b/group12/446031103/src/com/coderising/jvm/constant/MethodRefInfo.java @@ -0,0 +1,55 @@ +package com.coderising.jvm.constant; + +public class MethodRefInfo extends ConstantInfo { + + private int type = ConstantInfo.METHOD_INFO; + + private int classInfoIndex; + private int nameAndTypeIndex; + + public MethodRefInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String toString(){ + + return getClassName() +" : "+ this.getMethodName() + " : " + this.getParamAndReturnType() ; + } + public String getClassName(){ + ConstantPool pool = this.getConstantPool(); + ClassInfo clzInfo = (ClassInfo)pool.getConstantInfo(this.getClassInfoIndex()); + return clzInfo.getClassName(); + } + + public String getMethodName(){ + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo)pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getParamAndReturnType(){ + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo)pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } + + + +} diff --git a/group12/446031103/src/com/coderising/jvm/constant/NameAndTypeInfo.java b/group12/446031103/src/com/coderising/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..402f9dec86 --- /dev/null +++ b/group12/446031103/src/com/coderising/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,45 @@ +package com.coderising.jvm.constant; + +public class NameAndTypeInfo extends ConstantInfo{ + public int type = ConstantInfo.NAME_AND_TYPE_INFO; + + private int index1; + private int index2; + + public NameAndTypeInfo(ConstantPool pool) { + super(pool); + } + + public int getIndex1() { + return index1; + } + public void setIndex1(int index1) { + this.index1 = index1; + } + public int getIndex2() { + return index2; + } + public void setIndex2(int index2) { + this.index2 = index2; + } + public int getType() { + return type; + } + + + public String getName(){ + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info1 = (UTF8Info)pool.getConstantInfo(index1); + return utf8Info1.getValue(); + } + + public String getTypeInfo(){ + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info2 = (UTF8Info)pool.getConstantInfo(index2); + return utf8Info2.getValue(); + } + + public String toString(){ + return "(" + getName() + "," + getTypeInfo()+")"; + } +} diff --git a/group12/446031103/src/com/coderising/jvm/constant/NullConstantInfo.java b/group12/446031103/src/com/coderising/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..936736016f --- /dev/null +++ b/group12/446031103/src/com/coderising/jvm/constant/NullConstantInfo.java @@ -0,0 +1,13 @@ +package com.coderising.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo(){ + + } + @Override + public int getType() { + return -1; + } + +} diff --git a/group12/446031103/src/com/coderising/jvm/constant/StringInfo.java b/group12/446031103/src/com/coderising/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..f1f8eb4ed4 --- /dev/null +++ b/group12/446031103/src/com/coderising/jvm/constant/StringInfo.java @@ -0,0 +1,26 @@ +package com.coderising.jvm.constant; + +public class StringInfo extends ConstantInfo{ + private int type = ConstantInfo.STRING_INFO; + private int index; + public StringInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } + + + public String toString(){ + return this.getConstantPool().getUTF8String(index); + } + +} diff --git a/group12/446031103/src/com/coderising/jvm/constant/UTF8Info.java b/group12/446031103/src/com/coderising/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..5cac9f04f7 --- /dev/null +++ b/group12/446031103/src/com/coderising/jvm/constant/UTF8Info.java @@ -0,0 +1,32 @@ +package com.coderising.jvm.constant; + +public class UTF8Info extends ConstantInfo{ + private int type = ConstantInfo.UTF8_INFO; + private int length ; + private String value; + public UTF8Info(ConstantPool pool) { + super(pool); + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getType() { + return type; + } + @Override + public String toString() { + return "UTF8Info [type=" + type + ", length=" + length + ", value=" + value +")]"; + } + public String getValue() { + return value; + } + public void setValue(String value) { + this.value = value; + } + + + +} diff --git a/group12/446031103/src/com/coderising/jvm/loader/ByteCodeIterator.java b/group12/446031103/src/com/coderising/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..9c9fac2839 --- /dev/null +++ b/group12/446031103/src/com/coderising/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,5 @@ +package com.coderising.jvm.loader; + +public class ByteCodeIterator { + +} diff --git a/group12/446031103/src/com/coderising/jvm/loader/ClassFileLoader.java b/group12/446031103/src/com/coderising/jvm/loader/ClassFileLoader.java index 27f98c8714..33185d8175 100644 --- a/group12/446031103/src/com/coderising/jvm/loader/ClassFileLoader.java +++ b/group12/446031103/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -1,19 +1,24 @@ package com.coderising.jvm.loader; +import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStream; import java.util.ArrayList; import java.util.List; + import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; +import com.coderising.jvm.clz.ClassFile; + + + public class ClassFileLoader { - + private List clzPaths = new ArrayList(); public byte[] readBinaryCode(String className) { @@ -30,6 +35,9 @@ public byte[] readBinaryCode(String className) { } return null; + + + } private byte[] loadClassFile(String clzFileName) { @@ -57,24 +65,76 @@ public void addClassPath(String path) { } - public String getClassPath_V1(){ - - StringBuffer buffer = new StringBuffer(); - for(int i=0;i", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(10); + Assert.assertEquals("(Ljava/lang/String;I)V", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(11); + Assert.assertEquals("Code", utf8Info.getValue()); + } + + { + MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(12); + Assert.assertEquals(3, methodRef.getClassInfoIndex()); + Assert.assertEquals(13, methodRef.getNameAndTypeIndex()); + } + + { + NameAndTypeInfo nameAndType = (NameAndTypeInfo) pool.getConstantInfo(13); + Assert.assertEquals(9, nameAndType.getIndex1()); + Assert.assertEquals(14, nameAndType.getIndex2()); + } + //抽查几个吧 + { + MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(45); + Assert.assertEquals(1, methodRef.getClassInfoIndex()); + Assert.assertEquals(46, methodRef.getNameAndTypeIndex()); + } + + { + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(53); + Assert.assertEquals("EmployeeV1.java", utf8Info.getValue()); + } + } + @Test + public void testClassIndex(){ + + ClassIndex clzIndex = clzFile.getClzIndex(); + ClassInfo thisClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getThisClassIndex()); + ClassInfo superClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getSuperClassIndex()); + + + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); + Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); + } + + } diff --git a/group12/446031103/src/com/coderising/jvm/test/EmployeeV1.java b/group12/446031103/src/com/coderising/jvm/test/EmployeeV1.java index 5e2bd8668f..12e3d7efdd 100644 --- a/group12/446031103/src/com/coderising/jvm/test/EmployeeV1.java +++ b/group12/446031103/src/com/coderising/jvm/test/EmployeeV1.java @@ -25,4 +25,4 @@ public static void main(String[] args){ p.sayHello(); } -} +} \ No newline at end of file diff --git a/group12/446031103/src/com/coderising/jvm/util/Util.java b/group12/446031103/src/com/coderising/jvm/util/Util.java new file mode 100644 index 0000000000..0c4cc8c57c --- /dev/null +++ b/group12/446031103/src/com/coderising/jvm/util/Util.java @@ -0,0 +1,24 @@ +package com.coderising.jvm.util; + +public class Util { + public static int byteToInt(byte[] codes){ + String s1 = byteToHexString(codes); + return Integer.valueOf(s1, 16).intValue(); + } + + + + public static String byteToHexString(byte[] codes ){ + StringBuffer buffer = new StringBuffer(); + for(int i=0;i Date: Sun, 9 Apr 2017 23:37:05 +0800 Subject: [PATCH 107/203] post blog by Korben --- group20/1107837739/korben.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/group20/1107837739/korben.md b/group20/1107837739/korben.md index 1259561cb0..927e364da5 100644 --- a/group20/1107837739/korben.md +++ b/group20/1107837739/korben.md @@ -7,3 +7,5 @@ | [初窥计算机程序的运行](http://korben-chy.github.io/2017/02/26/%E5%88%9D%E7%AA%A5%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A8%8B%E5%BA%8F%E7%9A%84%E8%BF%90%E8%A1%8C/) | 2017/02/26 | | [程序在计算机中的运行过程简析](http://korben-chy.github.io/2017/03/06/%E7%A8%8B%E5%BA%8F%E5%9C%A8%E8%AE%A1%E7%AE%97%E6%9C%BA%E4%B8%AD%E7%9A%84%E8%BF%90%E8%A1%8C%E8%BF%87%E7%A8%8B%E7%AE%80%E6%9E%90) | 2017/03/05 | | [并发编程之-Volatile浅析](http://korben-chy.github.io/2017/03/12/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B%E4%B9%8B-Volatile%E6%B5%85%E6%9E%90) | 2017/03/12 | +| [并发编程之-synchronized浅析](http://blog.korbenc.space/2017/03/29/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B%E4%B9%8B-synchronized%E6%B5%85%E6%9E%90/) | 2017/03/29 | +| [Java类加载器--Classloader](http://blog.korbenc.space/2017/04/09/Java%E7%B1%BB%E5%8A%A0%E8%BD%BD%E5%99%A8-Classloader/) | 2017/04/09 | From 656bbf8fb3300f7eabb6be4f9af594499f9bdd71 Mon Sep 17 00:00:00 2001 From: johnChnia Date: Mon, 10 Apr 2017 02:11:00 +0800 Subject: [PATCH 108/203] =?UTF-8?q?=E5=AE=8C=E6=88=90stackutil?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coding2017/basic/{ => stack}/Stack.java | 2 +- .../coding2017/basic/stack/StackUtil.java | 122 ++++++++++++++++++ .../johnChnia/coding2017/basic/StackTest.java | 1 + .../coding2017/basic/stack/StackUtilTest.java | 66 ++++++++++ 4 files changed, 190 insertions(+), 1 deletion(-) rename group24/315863321/src/main/java/com/johnChnia/coding2017/basic/{ => stack}/Stack.java (97%) create mode 100644 group24/315863321/src/main/java/com/johnChnia/coding2017/basic/stack/StackUtil.java create mode 100644 group24/315863321/src/test/java/com/johnChnia/coding2017/basic/stack/StackUtilTest.java diff --git a/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/Stack.java b/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/stack/Stack.java similarity index 97% rename from group24/315863321/src/main/java/com/johnChnia/coding2017/basic/Stack.java rename to group24/315863321/src/main/java/com/johnChnia/coding2017/basic/stack/Stack.java index 3ddab60493..c8f1ce7d15 100644 --- a/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/Stack.java +++ b/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/stack/Stack.java @@ -1,4 +1,4 @@ -package com.johnChnia.coding2017.basic; +package com.johnChnia.coding2017.basic.stack; import com.johnChnia.coding2017.basic.linklist.LinkedList; diff --git a/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/stack/StackUtil.java b/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/stack/StackUtil.java new file mode 100644 index 0000000000..4b7c4687d7 --- /dev/null +++ b/group24/315863321/src/main/java/com/johnChnia/coding2017/basic/stack/StackUtil.java @@ -0,0 +1,122 @@ +package com.johnChnia.coding2017.basic.stack; + +/** + * Created by john on 2017/4/7. + */ +public class StackUtil { + + + /** + * 假设栈中的元素是Integer, 从栈顶到栈底是 : 5,4,3,2,1 调用该方法后, 元素次序变为: 1,2,3,4,5 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + */ + public static void reverse(Stack s) { + if (s.empty()) { + return; + } + E item = s.pop(); + reverse(s); + insertAtBottom(item, s); + } + + /** + * @param item 插入底部的元素 + * @param s 栈对象引用 + */ + private static void insertAtBottom(E item, Stack s) { + if (s.empty()) { + s.push(item); + } else { + E temp = s.pop(); + insertAtBottom(item, s); + s.push(temp); + } + } + + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s, Object o) { + if (s.empty()) { + return; + } + E item = s.pop(); + if (!o.equals(item)) { //没有考虑o为null的情况 + remove(s, o); + s.push(item); + } + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param len + * @return + */ + public static Object[] getTop(Stack s, int len) { + if (len > s.size()) { + throw new IllegalArgumentException("Len: " + len + ", Size" + s.size()); + } + Object[] array = new Object[len]; + int index = 0; + getArray(s, array, index); + return array; + } + + /** + * 采用递归的方式把len个元素加到数组中,且保持原栈中元素不变。 + * + * @param s 栈 + * @param array Object数组 + * @param index 数组索引 + */ + private static void getArray(Stack s, Object[] array, int index) { + if (s.empty() || index == array.length) { + return; + } + E item = s.pop(); + array[index++] = item; + getArray(s, array, index); + s.push(item); + } + + /** + * 字符串s 可能包含这些字符: ( ) [ ] { }, a,b,c... x,yz + * 使用堆栈检查字符串s中的括号是不是成对出现的。 + * 例如s = "([e{d}f])" , 则该字符串中的括号是成对出现, 该方法返回true + * 如果 s = "([b{x]y})", 则该字符串中的括号不是成对出现的, 该方法返回false; + * + * @param s + * @return + */ + public static boolean isValidPairs(String s) { // last unclosed first closed + Stack stack = new Stack<>(); + for (int i = 0; i < s.length(); i++) { + String subStr = s.substring(i, i + 1); + if ("([{".contains(subStr)) { + stack.push(subStr); + } else if (")]}".contains(subStr)) { + if (stack.empty()) { + return false; + } + String left = stack.pop(); + if (subStr.equals(")")) { + if(!left.equals("(")) + return false; + }else if(subStr.equals("]")){ + if(!left.equals("[")) + return false; + }else if(subStr.equals("}")){ + if(!left.equals("{")) + return false; + } + } + } + return stack.empty(); + } + +} \ No newline at end of file diff --git a/group24/315863321/src/test/java/com/johnChnia/coding2017/basic/StackTest.java b/group24/315863321/src/test/java/com/johnChnia/coding2017/basic/StackTest.java index 9d84f7367a..c6f4ec1b2c 100644 --- a/group24/315863321/src/test/java/com/johnChnia/coding2017/basic/StackTest.java +++ b/group24/315863321/src/test/java/com/johnChnia/coding2017/basic/StackTest.java @@ -1,5 +1,6 @@ package com.johnChnia.coding2017.basic; +import com.johnChnia.coding2017.basic.stack.Stack; import org.junit.Before; import org.junit.Test; diff --git a/group24/315863321/src/test/java/com/johnChnia/coding2017/basic/stack/StackUtilTest.java b/group24/315863321/src/test/java/com/johnChnia/coding2017/basic/stack/StackUtilTest.java new file mode 100644 index 0000000000..0a2f277d49 --- /dev/null +++ b/group24/315863321/src/test/java/com/johnChnia/coding2017/basic/stack/StackUtilTest.java @@ -0,0 +1,66 @@ +package com.johnChnia.coding2017.basic.stack; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import static com.johnChnia.coding2017.basic.stack.StackUtil.*; + + +/** + * Created by john on 2017/4/7. + */ +public class StackUtilTest { + + Stack s1; + Stack s2; + Stack s3; + + @Before + public void setUp() throws Exception { + s1 = new Stack<>(); + s2 = new Stack<>(); + s3 = new Stack<>(); + + } + + @Test + public void testReverse() throws Exception { + for (int i = 0; i < 4; i++) { + s1.push(i); + } + reverse(s1); + Assert.assertEquals("0→1→2→3", s1.toString()); + } + + @Test + public void testRemove() throws Exception { + for (int i = 0; i < 4; i++) { + s2.push(i); + } + remove(s2, 1); + Assert.assertEquals("3→2→0", s2.toString()); + } + + @Test + public void testGetTop() throws Exception { + for (int i = 0; i < 4; i++) { + s3.push(i); + } + Object[] array = getTop(s3, 2); + Assert.assertEquals(array.length, 2); + Assert.assertEquals(array[0], 3); + Assert.assertEquals(array[1], 2); + Assert.assertEquals("3→2→1→0", s3.toString()); + + } + + @Test + public void testIsValidPairs() throws Exception { + String s1 = "([e{d}f])"; + Assert.assertTrue(isValidPairs(s1)); + String s2 = "([b{x]y})"; + Assert.assertFalse(isValidPairs(s2)); + } + +} \ No newline at end of file From 6d5919072c6f13e281bd0c3f30c4fda4e1424a6b Mon Sep 17 00:00:00 2001 From: PikachuHy <2931408816@qq.com> Date: Mon, 10 Apr 2017 03:49:09 +0800 Subject: [PATCH 109/203] =?UTF-8?q?=E6=88=91=E6=B2=A1=E6=9C=89=E5=88=A0?= =?UTF-8?q?=E4=BB=BB=E4=BD=95=E4=B8=9C=E8=A5=BF=EF=BC=8C=E5=8F=AA=E6=98=AF?= =?UTF-8?q?=E6=8A=8A=E6=88=91=E8=87=AA=E5=B7=B1=E7=9A=84=E6=8B=B7=E8=B4=9D?= =?UTF-8?q?=E8=BF=9B=E5=8E=BB=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../3.1/taskArtifacts/cache.properties.lock | Bin 17 -> 17 bytes .../.gradle/3.1/taskArtifacts/fileHashes.bin | Bin 25247 -> 26447 bytes .../3.1/taskArtifacts/fileSnapshots.bin | Bin 98555 -> 114738 bytes .../3.1/taskArtifacts/taskArtifacts.bin | Bin 35726 -> 43221 bytes group13/2931408816/.idea/compiler.xml | 4 + group13/2931408816/.idea/gradle.xml | 2 + group13/2931408816/.idea/modules.xml | 11 +- group13/2931408816/.idea/workspace.xml | 1659 ++++++++++------- ...=> BinaryTreeNode.java~CoderXLoong_master} | 0 .../com/coding/basic/BinaryTreeNode.java~HEAD | 32 + ....java => Iterator.java~CoderXLoong_master} | 0 .../java/com/coding/basic/Iterator.java~HEAD | 7 + ...List.java => List.java~CoderXLoong_master} | 0 .../main/java/com/coding/basic/List.java~HEAD | 9 + ...ack.java => Stack.java~CoderXLoong_master} | 0 .../java/com/coding/basic/Stack.java~HEAD | 24 + group13/2931408816/lesson5/build.gradle | 31 + .../com/coderising/jvm/clz/AccessFlag.java | 25 + .../com/coderising/jvm/clz/ClassFile.java | 75 + .../com/coderising/jvm/clz/ClassIndex.java | 19 + .../coderising/jvm/constant/ClassInfo.java | 24 + .../coderising/jvm/constant/ConstantInfo.java | 29 + .../coderising/jvm/constant/ConstantPool.java | 29 + .../coderising/jvm/constant/FieldRefInfo.java | 54 + .../jvm/constant/MethodRefInfo.java | 55 + .../jvm/constant/NameAndTypeInfo.java | 45 + .../jvm/constant/NullConstantInfo.java | 13 + .../coderising/jvm/constant/StringInfo.java | 26 + .../com/coderising/jvm/constant/UTF8Info.java | 32 + .../jvm/loader/ByteCodeIterator.java | 37 + .../jvm/loader/ClassFileLoader.java | 140 ++ .../jvm/loader/ClassFileParser.java | 177 ++ .../com/coderising/jvm/test/EmployeeV1.java | 28 + .../java/com/coderising/jvm/test/Main.java | 7 + .../java/com/coderising/jvm/util/Util.java | 24 + .../java/com/coding/basic/BinaryTreeNode.java | 32 + .../main/java/com/coding/basic/Iterator.java | 7 + .../src/main/java/com/coding/basic/List.java | 9 + .../src/main/java/com/coding/basic/Queue.java | 19 + .../com/coding/basic/array/ArrayList.java | 35 + .../com/coding/basic/array/ArrayUtil.java | 96 + .../java/com/coding/basic/stack/Stack.java | 35 + .../com/coding/basic/stack/StackUtil.java | 134 ++ .../jvm/loader/test/ClassFileloaderTest.java | 197 ++ .../com/coding/basic/stack/StackUtilTest.java | 61 + group13/2931408816/settings.gradle | 1 + group13/2931408816/src/main/kotlin/main.kt | 13 + 47 files changed, 2588 insertions(+), 669 deletions(-) rename group13/2931408816/lesson4/src/main/java/com/coding/basic/{BinaryTreeNode.java => BinaryTreeNode.java~CoderXLoong_master} (100%) create mode 100644 group13/2931408816/lesson4/src/main/java/com/coding/basic/BinaryTreeNode.java~HEAD rename group13/2931408816/lesson4/src/main/java/com/coding/basic/{Iterator.java => Iterator.java~CoderXLoong_master} (100%) create mode 100644 group13/2931408816/lesson4/src/main/java/com/coding/basic/Iterator.java~HEAD rename group13/2931408816/lesson4/src/main/java/com/coding/basic/{List.java => List.java~CoderXLoong_master} (100%) create mode 100644 group13/2931408816/lesson4/src/main/java/com/coding/basic/List.java~HEAD rename group13/2931408816/lesson4/src/main/java/com/coding/basic/{Stack.java => Stack.java~CoderXLoong_master} (100%) create mode 100644 group13/2931408816/lesson4/src/main/java/com/coding/basic/Stack.java~HEAD create mode 100644 group13/2931408816/lesson5/build.gradle create mode 100644 group13/2931408816/lesson5/src/main/java/com/coderising/jvm/clz/AccessFlag.java create mode 100644 group13/2931408816/lesson5/src/main/java/com/coderising/jvm/clz/ClassFile.java create mode 100644 group13/2931408816/lesson5/src/main/java/com/coderising/jvm/clz/ClassIndex.java create mode 100644 group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/ClassInfo.java create mode 100644 group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/ConstantInfo.java create mode 100644 group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/ConstantPool.java create mode 100644 group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/FieldRefInfo.java create mode 100644 group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/MethodRefInfo.java create mode 100644 group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/NameAndTypeInfo.java create mode 100644 group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/NullConstantInfo.java create mode 100644 group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/StringInfo.java create mode 100644 group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/UTF8Info.java create mode 100644 group13/2931408816/lesson5/src/main/java/com/coderising/jvm/loader/ByteCodeIterator.java create mode 100644 group13/2931408816/lesson5/src/main/java/com/coderising/jvm/loader/ClassFileLoader.java create mode 100644 group13/2931408816/lesson5/src/main/java/com/coderising/jvm/loader/ClassFileParser.java create mode 100644 group13/2931408816/lesson5/src/main/java/com/coderising/jvm/test/EmployeeV1.java create mode 100644 group13/2931408816/lesson5/src/main/java/com/coderising/jvm/test/Main.java create mode 100644 group13/2931408816/lesson5/src/main/java/com/coderising/jvm/util/Util.java create mode 100644 group13/2931408816/lesson5/src/main/java/com/coding/basic/BinaryTreeNode.java create mode 100644 group13/2931408816/lesson5/src/main/java/com/coding/basic/Iterator.java create mode 100644 group13/2931408816/lesson5/src/main/java/com/coding/basic/List.java create mode 100644 group13/2931408816/lesson5/src/main/java/com/coding/basic/Queue.java create mode 100644 group13/2931408816/lesson5/src/main/java/com/coding/basic/array/ArrayList.java create mode 100644 group13/2931408816/lesson5/src/main/java/com/coding/basic/array/ArrayUtil.java create mode 100644 group13/2931408816/lesson5/src/main/java/com/coding/basic/stack/Stack.java create mode 100644 group13/2931408816/lesson5/src/main/java/com/coding/basic/stack/StackUtil.java create mode 100644 group13/2931408816/lesson5/src/test/java/com/coderising/jvm/loader/test/ClassFileloaderTest.java create mode 100644 group13/2931408816/lesson5/src/test/java/com/coding/basic/stack/StackUtilTest.java create mode 100644 group13/2931408816/src/main/kotlin/main.kt diff --git a/group13/2931408816/.gradle/3.1/taskArtifacts/cache.properties.lock b/group13/2931408816/.gradle/3.1/taskArtifacts/cache.properties.lock index e5268516195466f629277262edb14ab9301a67a3..3c3d84d35b2883e40cb29ce5f86e80ae1b94936c 100644 GIT binary patch literal 17 VcmZRcJpKB1vxRZVkBA9%7vaM8rz`>@f?p*dMtPsJ}-p#F2 zI~n<1c5L0Q)Zz^hOi7$f>CyUBi2yiU?-5zj9@d!jPMSrrZ zTz~*i<(GQ}nkL;)!K0gd$d8&MafMNP_!3|doZ$kuAKThUV z$mCC|{m{uRu^6h*baJkOBEMvVkV=>bFGMVD=jK)g4MqXqoUG{@{1@vXqUo}emnsJG zv(;s@r_Y@W)jf0aTg4v&5&zOfb?4qsfocz(d{^m&K&r8vLQ|PW0#xPS$#a!w@=Iy- z&v0UX3=vD2JXu#oL7*V+NSmo(BRf>^`(#(3V7XT7?#7NJXk?`BpBxJmtSp!vTe#&m zG>FrbCzq-eG4cJ}sQ5#Cqk#hFW=D@Wsd{6eIhsJM2*LuYg_EWW{hK-a!ZmfSvX5`R zF)%Pj-SJ=g17eveC<^pYb$E;ITFaMtC{px?%N7Us7rkH|f!xq25VpY7v2gl2uPg8P zVi_++hujl>e2wD(QFkk-mZ0+>lEwFNY4*0 z>d!9%jfhqkV!02|!8!?32ZPmYkt=^o5+&Z)mG^TKc#S<@HuqJifGrVbI|0_gz%d_93s8q|#EN;sH?E(3`tF8TMO{=4RL2>J z4i<&Uf(fcD(dxqNldTe@6^uVew$7G$oRMVk&BRip#1*JIGFLA$9ITqFhv6W%+1RIF`WG`rgLs9%+PZSS`@nB@~ZpO zwy;$|oWsEk(ZSUYat4f^ZE_&X(c6r%FLv>u6d@(^P$o8i~=e%Vn`8&>PDalVez6mOM9ctVJOygvf zuSPhnu7BIldaCB;X)9ok1^Q5!&kUl2t9J7H5LI4~h&fawbn@O1ReO+#B}9ZJAJbHG ztH-6QuXi&!aetnrvb!-7)l|+WlY>LSp}=P`xi(ZPOk|G#&3n~1K4kUBvao)z>O)n| ik&9_T;CAsvXTNGH8eN;E`_}gP6sQhah?AI$Kso?$9(Mcy delta 128 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 diff --git a/group13/2931408816/.gradle/3.1/taskArtifacts/taskArtifacts.bin b/group13/2931408816/.gradle/3.1/taskArtifacts/taskArtifacts.bin index 69a7010d727c6d79d4cf023d84b078e91b37e390..3c70119c9fc29591000bc38a56b659d752454308 100644 GIT binary patch delta 2095 zcmeC1&UE!6(*_d>M)Ap}5*`}Mn^$DXzMA}w0SxAG{fB}TDGc1ZLf`#?h|f7Nxm2P- z;HT4jgLT?Y&me+RPECF*ks+Y5dZ&oRC39(rU@y;PUr7rAtG8b4A30@{@CkXxfbisuPpMIHCLwb*W`nK(e>vkba+Z?L26z~YF=`sZgOIBM(SzO z%#+0k30M&1CT8YMW~>UD91!3*`9h?`=7|9*EKVh$IJ5;~QxFD+Nq=@?L5VXc9#e~f z(KGeEx!bHOLQ^I{g4DmXq@c6}DDM2c;GB3sXyfGbaf-@M_U%-dxn~nscX@tMHZYQa z^7iQyQzOm>X*4#smCP@i6hHZ3adQ0)(tLyA8HgKzDIvEYGbhy>9LX`om3hgabmfFE zJ#scI)~GgJQ!WIJ;JWi~CCtR7%CRKKq*ck^j%UZs+3U==^QQSj0h%Pp!f*l!a+Msr zyyo0fdQkT+POgreKW&9NI6?Ywh`qOSU1p4yAYY}_{mFQ(HB;?hbhq%0Q>owtNn!%R z2y$5ZDFJ3$G7>j0O17N*u`&ru0(1n%o+SulOMqo;Vzbg67x17bK*u+?{{3A2%NLvg zeY_5Y{YaMPM@oRoUT)K3-o4@~-8<{&uE(nN-~@PwstGUz7$#_m&<&UfxefvGE)WL! zhh=h7ett=DNl{{f^W^>p4zp)dGqYdZ^$wVloS2uAnUYwN3eIhAz!Y6*2^f#&Cx?DY0H-HIr28?%Z16Bjk1C{FRwggkyyL;;JUM4y@U>?u9^HHT6A)6 zC&%QHMzi`06b2F~spu9#oE8J(TqnuEdd%V+!^9Y%=M#%6FOp<1rn%6-0z0x8OafzU z^V=q2Mn;p(j4e4#EX?js-jhE7i(!+^_U&GbHs)m3OXW-qF_Z6fq!{SCTEzqu<);@V r<|=@rJjM%D#bu>r8|qo;8N?eJ8iG6ruK4s)D^fQ<$k1eB;yMlh?(ho# delta 61 zcmcb5k*RMw(*_d>MuEwu5+0M+N>og?l}wntRnlPcUrC9{x>6E6|Dk|^fpOwS#UJ7u N4LZa&J9_v!0{{xo8YBP! diff --git a/group13/2931408816/.idea/compiler.xml b/group13/2931408816/.idea/compiler.xml index 3d1b215f42..602f0772b0 100644 --- a/group13/2931408816/.idea/compiler.xml +++ b/group13/2931408816/.idea/compiler.xml @@ -10,6 +10,10 @@ + + + + \ No newline at end of file diff --git a/group13/2931408816/.idea/gradle.xml b/group13/2931408816/.idea/gradle.xml index 4a7350459a..246a806334 100644 --- a/group13/2931408816/.idea/gradle.xml +++ b/group13/2931408816/.idea/gradle.xml @@ -13,6 +13,8 @@ diff --git a/group13/2931408816/.idea/modules.xml b/group13/2931408816/.idea/modules.xml index b8bbae7f40..762aea64c1 100644 --- a/group13/2931408816/.idea/modules.xml +++ b/group13/2931408816/.idea/modules.xml @@ -3,7 +3,7 @@ - + @@ -12,9 +12,16 @@ - + + + + + + + + \ No newline at end of file diff --git a/group13/2931408816/.idea/workspace.xml b/group13/2931408816/.idea/workspace.xml index 5491e4d0a1..38a332457d 100644 --- a/group13/2931408816/.idea/workspace.xml +++ b/group13/2931408816/.idea/workspace.xml @@ -11,6 +11,10 @@ + + + + - -