From e5c0da0533f6347a953b9becc631f49712bf8bf7 Mon Sep 17 00:00:00 2001 From: fengyuxia <474772605@qq.com> Date: Sun, 5 Mar 2017 21:39:10 +0800 Subject: [PATCH 001/287] no message --- group04/474772605/.classpath | 4 + .../com/coderising/action/LoginAction.java | 40 +++++ .../src/com/coderising/action/Struts.java | 167 ++++++++++++++++++ .../src/com/coderising/action/StrutsTest.java | 43 +++++ .../src/com/coderising/action/View.java | 23 +++ .../src/com/coderising/action/struts.xml | 11 ++ .../src/com/coderising/array/ArrayUtil.java | 146 +++++++++++++++ .../src/com/coding/basic/LinkedList.java | 1 + .../474772605/src/com/coding/basic/List.java | 2 +- .../474772605/src/com/coding/basic/Node.java | 12 ++ .../474772605/src/com/coding/basic/Stack.java | 34 ++-- .../com/coding/basic/Testclassextends.java | 17 ++ .../src/com/coding/basic/testarraylist.java | 7 +- .../src/com/coding/iostreams/inteface.java | 11 ++ .../src/com/coding/iostreams/readfile.java | 67 +++++++ .../src/com/coding/iostreams/test.java | 14 ++ group04/474772605/src/struts.xml | 11 ++ group04/474772605/test/Test.java | 50 ++++++ .../test/com/coding/basic/Heros.java | 51 ++++++ .../474772605/test/com/coding/basic/Test.java | 43 +++++ .../test/com/coding/basic/TestStack.java | 35 ++++ .../test/com/coding/basic/Testarray.java | 22 +++ .../test/com/coding/basic/teest.java | 24 +++ 23 files changed, 817 insertions(+), 18 deletions(-) create mode 100644 group04/474772605/src/com/coderising/action/LoginAction.java create mode 100644 group04/474772605/src/com/coderising/action/Struts.java create mode 100644 group04/474772605/src/com/coderising/action/StrutsTest.java create mode 100644 group04/474772605/src/com/coderising/action/View.java create mode 100644 group04/474772605/src/com/coderising/action/struts.xml create mode 100644 group04/474772605/src/com/coderising/array/ArrayUtil.java create mode 100644 group04/474772605/src/com/coding/basic/Node.java create mode 100644 group04/474772605/src/com/coding/basic/Testclassextends.java create mode 100644 group04/474772605/src/com/coding/iostreams/inteface.java create mode 100644 group04/474772605/src/com/coding/iostreams/readfile.java create mode 100644 group04/474772605/src/com/coding/iostreams/test.java create mode 100644 group04/474772605/src/struts.xml create mode 100644 group04/474772605/test/Test.java create mode 100644 group04/474772605/test/com/coding/basic/Heros.java create mode 100644 group04/474772605/test/com/coding/basic/Test.java create mode 100644 group04/474772605/test/com/coding/basic/TestStack.java create mode 100644 group04/474772605/test/com/coding/basic/Testarray.java create mode 100644 group04/474772605/test/com/coding/basic/teest.java diff --git a/group04/474772605/.classpath b/group04/474772605/.classpath index 28e2b79383..8d7ead9fe8 100644 --- a/group04/474772605/.classpath +++ b/group04/474772605/.classpath @@ -1,7 +1,11 @@ + + + + diff --git a/group04/474772605/src/com/coderising/action/LoginAction.java b/group04/474772605/src/com/coderising/action/LoginAction.java new file mode 100644 index 0000000000..69ad2750c0 --- /dev/null +++ b/group04/474772605/src/com/coderising/action/LoginAction.java @@ -0,0 +1,40 @@ +package com.coderising.action; + +/** + * 这是一个用来展示登录的业务类, 其中的用户名和密码都是硬编码的。 + * @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/group04/474772605/src/com/coderising/action/Struts.java b/group04/474772605/src/com/coderising/action/Struts.java new file mode 100644 index 0000000000..e2098dff74 --- /dev/null +++ b/group04/474772605/src/com/coderising/action/Struts.java @@ -0,0 +1,167 @@ +package com.coderising.action; + +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.dom4j.Attribute; +import org.dom4j.DocumentException; +import org.dom4j.Element; +import org.dom4j.io.SAXReader; + + + +public class Struts { + + + + public static void main(String[] args) throws DocumentException { +String actionName = "com.coderising.action.LoginAction"; + + Map params = new HashMap(); + params.put("name","test"); + params.put("password","1234"); + + + View view = Struts.runAction(actionName,params); + } + + + +/* //遍历当前节点下的所有节点 + public static void listNodes(Element node){ + System.out.println("当前节点的名称:" + node.getName()); + //首先获取当前节点的所有属性节点 + List list = node.attributes(); + //遍历属性节点 + for(Attribute attribute : list){ + System.out.println("属性"+attribute.getName() +":" + attribute.getValue()); + } + //如果当前节点内容不为空,则输出 + if(!(node.getTextTrim().equals(""))){ + System.out.println( node.getName() + ":" + node.getText()); + } + //同时迭代当前节点下面的所有子节点 + //使用递归 + Iterator iterator = node.elementIterator(); + while(iterator.hasNext()){ + Element e = iterator.next(); + listNodes(e); + } + } */ + + public static View runAction(String actionName, Map parameters) { + + SAXReader reader = new SAXReader(); + //读取文件 转换成Document + org.dom4j.Document document; + try { + document = reader.read(new File("src/struts.xml")); + Element root = document.getRootElement(); + List childList2 = root.elements("action"); + Iterator it = childList2.iterator(); + /* while (it.hasNext()){ + Element element = it.next(); + System.out.println("节点的名称" + element.getName() + "节点的值" + element.getText()); + + }*/ + for (int i = 0; i < childList2.size(); i++) { + List list = childList2.get(i).attributes(); + Iterator it1 = list.iterator(); + while(it1.hasNext()){ + + Attribute attribute1 = it1.next(); + System.out.println(attribute1.getName()); + System.out.println(attribute1.getValue()); + System.out.println("=============="); + + } + + for(Attribute attribute : list){ + + if(actionName.equals(attribute.getValue())){ + + String clazz = null; + + clazz = attribute.getValue(); + try { + Object o = Class.forName(clazz).newInstance(); + try { + Method m = o.getClass().getMethod("setName", String.class); + Method m1 = o.getClass().getMethod("setPassword", String.class); + Method m3 = o.getClass().getMethod("execute"); + try { + m.invoke(o, parameters.get("name")); + m1.invoke(o, parameters.get("password")); + String result = (String) m3.invoke(o); + System.out.println(result); + } catch (IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } catch (SecurityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (NoSuchMethodException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + + } catch (InstantiationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ClassNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } //根据class生成实例 + } + + + } + + } + } catch (DocumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + //获取根节点元素对象 + + + + + /* + + 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字段中。 + + */ + + return null; + } + +} diff --git a/group04/474772605/src/com/coderising/action/StrutsTest.java b/group04/474772605/src/com/coderising/action/StrutsTest.java new file mode 100644 index 0000000000..c161c0f932 --- /dev/null +++ b/group04/474772605/src/com/coderising/action/StrutsTest.java @@ -0,0 +1,43 @@ +package com.coderising.action; + +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 = "com.coderising.action.LoginAction"; + + 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/group04/474772605/src/com/coderising/action/View.java b/group04/474772605/src/com/coderising/action/View.java new file mode 100644 index 0000000000..11cb1872e5 --- /dev/null +++ b/group04/474772605/src/com/coderising/action/View.java @@ -0,0 +1,23 @@ +package com.coderising.action; + +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/group04/474772605/src/com/coderising/action/struts.xml b/group04/474772605/src/com/coderising/action/struts.xml new file mode 100644 index 0000000000..a6cfe43e6c --- /dev/null +++ b/group04/474772605/src/com/coderising/action/struts.xml @@ -0,0 +1,11 @@ + + + + /jsp/homepage.jsp + /jsp/showLogin.jsp + + + /jsp/welcome.jsp + /jsp/error.jsp + + \ No newline at end of file diff --git a/group04/474772605/src/com/coderising/array/ArrayUtil.java b/group04/474772605/src/com/coderising/array/ArrayUtil.java new file mode 100644 index 0000000000..ddb00c17b6 --- /dev/null +++ b/group04/474772605/src/com/coderising/array/ArrayUtil.java @@ -0,0 +1,146 @@ +package com.coderising.array; + +import java.util.ArrayList; +import java.util.Stack; + +import com.coding.basic.LinkedList; + +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){ + Stack stack = new Stack(); + for (int i = 0; i < origin.length; i++) { + stack.add(origin[i]); + } + + for (int j = 0; j < stack.size(); j++) { + origin[j] = (Integer) stack.pop(); + } + + } + + /** + * 现在有如下的一个数组: 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){ + ArrayList newarray = new ArrayList(); + for (int i = 0; i < oldArray.length; i++) { + if(0!=oldArray[i]){ + newarray.add(oldArray[i]); + } + } + int result [] = new int [newarray.size()]; + for (int j = 0; j < result.length; j++) { + result[j]=newarray.get(j); + } + + return result; + } + + /** + * 给定两个已经排序好的整形数组, 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){ + ArrayList newarray = new ArrayList(); + for (int i = 0; i < array1.length; i++) { + newarray.add(i, array1[i]); + } + for (int j = 0; j < array2.length; j++) { + if (newarray.get(j)>array2[j]&&newarray.get(j+1)>array2[j]) { + newarray.add(j+1, array2[j]); + } + } + + int result [] = new int [newarray.size()]; + for (int z = 0; z < result.length; z++) { + result[z]=newarray.get(z); + } + return result; + } + /** + * 把一个已经存满数据的数组 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){ + ArrayList newarray = new ArrayList(); + for (int i = 0; i < oldArray.length; i++) { + newarray.add(i, oldArray[i]); + } + while (newarray.size()='A'&&(char)num <='z'){ + n1++; + } + if((char)num >='A'&&(char)num <='Z'){ + n2++; + } + } + } + reader.close(); + System.out.println(n1+""+n2); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + + + public float method(){ + return 13.21f; + } + + + + + } + + + + + + + + + + + diff --git a/group04/474772605/src/com/coding/iostreams/test.java b/group04/474772605/src/com/coding/iostreams/test.java new file mode 100644 index 0000000000..1bd474ca7b --- /dev/null +++ b/group04/474772605/src/com/coding/iostreams/test.java @@ -0,0 +1,14 @@ +package com.coding.iostreams; + +public interface test { + public float method(); + +} + + + + + + + + diff --git a/group04/474772605/src/struts.xml b/group04/474772605/src/struts.xml new file mode 100644 index 0000000000..90cf18b7da --- /dev/null +++ b/group04/474772605/src/struts.xml @@ -0,0 +1,11 @@ + + + + /jsp/homepage.jsp + /jsp/showLogin.jsp + + + /jsp/welcome.jsp + /jsp/error.jsp + + \ No newline at end of file diff --git a/group04/474772605/test/Test.java b/group04/474772605/test/Test.java new file mode 100644 index 0000000000..8c0f62930b --- /dev/null +++ b/group04/474772605/test/Test.java @@ -0,0 +1,50 @@ + + + import java.io.File; + import java.io.FileInputStream; + import java.io.InputStreamReader; + import java.io.Reader; + + + + + public class Test{ + static int n1 =0 ; + static int n2 =0 ; + + public static void main(String[] args) throws Exception{ + + Test.readFileByChars("D://Text.txt"); + + System.out.println("字母个数为:"+n1+" 字母个数为"+n2); + + } + + public static void readFileByChars(String fileName) { + File file = new File(fileName); + Reader reader = null; + try { + System.out.println("以字符为单位读取文件内容,一次读一个字节:"); + // 一次读一个字符 + reader = new InputStreamReader(new FileInputStream(file)); + int tempchar; + while ((tempchar = reader.read()) != -1) { + // 对于windows下,\r\n这两个字符在一起时,表示一个换行。 + // 但如果这两个字符分开显示时,会换两次行。 + // 因此,屏蔽掉\r,或者屏蔽\n。否则,将会多出很多空行。 + if (((char) tempchar) != '\r') { + System.out.print((char) tempchar); + n1++; + if((char)tempchar >='A'&&(char)tempchar<='Z'){ + n2++; + } + + } + } + reader.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + diff --git a/group04/474772605/test/com/coding/basic/Heros.java b/group04/474772605/test/com/coding/basic/Heros.java new file mode 100644 index 0000000000..878204aede --- /dev/null +++ b/group04/474772605/test/com/coding/basic/Heros.java @@ -0,0 +1,51 @@ +package com.coding.basic; + +import java.lang.reflect.Method; + +public class Heros { + private String name;//名字 + private String type;//类型 + private int camp;//0,近卫;1,天灾 + public Heros(){ + + } + /* + public Heros(String name, String type, int camp) { + + super(); + + this.name = name; + this.type = type; + this.camp = camp; + }*/ + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public int getCamp() { + return camp; + } + + public void setCamp(int camp) { + this.camp = camp; + } + + @Override + public String toString() { + return "Heros [\n name=" + name + ", \n type=" + type + ", \n camp=" + camp + "\n]"; + } + +} \ No newline at end of file diff --git a/group04/474772605/test/com/coding/basic/Test.java b/group04/474772605/test/com/coding/basic/Test.java new file mode 100644 index 0000000000..97f7254c82 --- /dev/null +++ b/group04/474772605/test/com/coding/basic/Test.java @@ -0,0 +1,43 @@ +package com.coding.basic; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class Test { + + public static void main(String args[]) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + Foo foo = new Foo("这个一个Foo对象!"); + Class clazz = foo.getClass(); + Field[] abc =clazz.getDeclaredFields(); + + // Object value = getFieldValueByName(key, obj);  + Method m1 = clazz.getDeclaredMethod("outInfo"); + Method m2 = clazz.getDeclaredMethod("setMsg", String.class); + Method m3 = clazz.getDeclaredMethod("getMsg"); + m1.invoke(foo); + m2.invoke(foo, "重新设置msg信息!"); + String msg = (String) m3.invoke(foo); + System.out.println(msg); + } +} + +class Foo { + private String msg; + + public Foo(String msg) { + this.msg = msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public String getMsg() { + return msg; + } + + public void outInfo() { + System.out.println("这是测试Java反射的测试类"); + } +} diff --git a/group04/474772605/test/com/coding/basic/TestStack.java b/group04/474772605/test/com/coding/basic/TestStack.java new file mode 100644 index 0000000000..e4caa84d98 --- /dev/null +++ b/group04/474772605/test/com/coding/basic/TestStack.java @@ -0,0 +1,35 @@ +package com.coding.basic; + +import junit.framework.TestCase; + +public class TestStack extends TestCase{ +private Stack stack; + + +public void setUp() throws Exception { + stack = new Stack(); + +} + +public void testpop(){ +// Stack stack = new Stack(); + Object o = null ; + try { + stack.push(o); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + + + +} + + + + + + + +} diff --git a/group04/474772605/test/com/coding/basic/Testarray.java b/group04/474772605/test/com/coding/basic/Testarray.java new file mode 100644 index 0000000000..19edb9f85d --- /dev/null +++ b/group04/474772605/test/com/coding/basic/Testarray.java @@ -0,0 +1,22 @@ +package com.coding.basic; + +import junit.framework.TestCase; + +public class Testarray extends TestCase{ + + public void testararry(){ + Throwable tx = null; + try { + ArrayList n = new ArrayList(); + Object o = null ; + + n.add(o); + fail(); + } catch (Exception e) { + tx =e; + assertEquals(Exception.class, tx.getClass()); + assertEquals("对象不能为空", e.getMessage()); + } + } + +} diff --git a/group04/474772605/test/com/coding/basic/teest.java b/group04/474772605/test/com/coding/basic/teest.java new file mode 100644 index 0000000000..e8004c14b6 --- /dev/null +++ b/group04/474772605/test/com/coding/basic/teest.java @@ -0,0 +1,24 @@ +package com.coding.basic; + +import java.lang.reflect.Method; + +public class teest { + public static void main(String[] args) { + Class herosClass = Heros.class; + try { + Method m1 = herosClass.getMethod("setName",String.class); + Method m3 = herosClass.getMethod("setCamp",int.class); + Method m2 = herosClass.getMethod("getName"); + + + Object userInfo = herosClass.newInstance(); + System.out.println("调用构造函数:"+userInfo); + m1.invoke(userInfo,"影魔"); + m3.invoke(userInfo, 1); + System.out.println("调用set方法:"+userInfo); + System.out.println("调用get方法:"+m2.invoke(userInfo)); + } catch (Exception e) { + e.printStackTrace(); + } + } +} From b85819a5c6ac1ff35a367eee9bf21472e87622ee Mon Sep 17 00:00:00 2001 From: Samson Shenglu Cao Date: Mon, 6 Mar 2017 11:53:18 +0800 Subject: [PATCH 002/287] 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 f67fec97bd72576af1f9bac00419f8ffcfa9f895 Mon Sep 17 00:00:00 2001 From: dudy Date: Tue, 7 Mar 2017 20:01:06 +0800 Subject: [PATCH 003/287] sortdemo singleton --- .../com/dudy/learn01/base/MyLinkedList.java | 12 ++ .../singleton/EnumSingleton.java | 40 +++++++ .../singleton/SingletonDemo1.java | 66 +++++++++++ .../singleton/StaticClassInnerSingleton.java | 63 +++++++++++ .../com/dudy/learn01/utils/ArraySortDemo.java | 107 ++++++++++++++++++ 5 files changed, 288 insertions(+) create mode 100644 group04/1796244932/learn01/src/main/java/com/dudy/learn01/designPattern/singleton/EnumSingleton.java create mode 100644 group04/1796244932/learn01/src/main/java/com/dudy/learn01/designPattern/singleton/SingletonDemo1.java create mode 100644 group04/1796244932/learn01/src/main/java/com/dudy/learn01/designPattern/singleton/StaticClassInnerSingleton.java create mode 100644 group04/1796244932/learn01/src/main/java/com/dudy/learn01/utils/ArraySortDemo.java diff --git a/group04/1796244932/learn01/src/main/java/com/dudy/learn01/base/MyLinkedList.java b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/base/MyLinkedList.java index 60254997aa..e0dbe9aae8 100644 --- a/group04/1796244932/learn01/src/main/java/com/dudy/learn01/base/MyLinkedList.java +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/base/MyLinkedList.java @@ -89,6 +89,17 @@ public Object removeLast() { return tmp.data; } + /** + * 链表逆序 + */ + public void reverse(){ + + } + + + + + public MyIterator iterator() { return new MyLinkedListItr(); } @@ -108,6 +119,7 @@ public Object next() { } } + private static class Node { Object data; Node next; diff --git a/group04/1796244932/learn01/src/main/java/com/dudy/learn01/designPattern/singleton/EnumSingleton.java b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/designPattern/singleton/EnumSingleton.java new file mode 100644 index 0000000000..84e9bd5d2c --- /dev/null +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/designPattern/singleton/EnumSingleton.java @@ -0,0 +1,40 @@ +package com.dudy.learn01.designPattern.singleton; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * Created by dudy on 2017/3/6. + */ +public enum EnumSingleton { + + SINGLETON; + private EnumSingleton(){} + + + public static void main(String[] args) { + + ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 6000 * 10, TimeUnit.MILLISECONDS, + new ArrayBlockingQueue(5)); + + + for (int i = 0; i< 16; i++){ + executor.execute(new EnumSingletonTest()); + } + + executor.shutdown(); + + + } +} + + +class EnumSingletonTest implements Runnable{ + + @Override + public void run() { + EnumSingleton singleton = EnumSingleton.SINGLETON; + System.out.println(singleton.hashCode()); + } +} \ No newline at end of file diff --git a/group04/1796244932/learn01/src/main/java/com/dudy/learn01/designPattern/singleton/SingletonDemo1.java b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/designPattern/singleton/SingletonDemo1.java new file mode 100644 index 0000000000..8de831c354 --- /dev/null +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/designPattern/singleton/SingletonDemo1.java @@ -0,0 +1,66 @@ +package com.dudy.learn01.designPattern.singleton; + +import java.io.Serializable; +import java.util.concurrent.*; + +/** + * Created by dudy on 2017/3/6. + * 双检索 方式 + * jdk1.5 以后 其实是线程安全的。 + * 序列化会 破坏 单利 + * + */ +public class SingletonDemo1 implements Serializable{ + + private static volatile SingletonDemo1 singleton = null; // 加 volatile 是为了 可见性,另一个就是 避免重排序 + + private SingletonDemo1(){} + + public static SingletonDemo1 getIntance(){ + + if (singleton == null){// 第一个避免 在 synchronized 中 一直排队 + synchronized (SingletonDemo1.class){ + + if (singleton == null){// 如果对象为空,才被创建 + singleton = new SingletonDemo1(); + } + + } + } + + return singleton; + } + + + /** + * 解决 反序列化的问题 + * @return + */ + private Object readResolve() { + return singleton; + } + + public static void main(String[] args) { + + ExecutorService threadPool = Executors.newFixedThreadPool(10); + + for (int i= 0 ;i < 5; i++){ + threadPool.execute(new TestRunable()); + } + + threadPool.shutdown(); + + //new ThreadPoolExecutor(10,20,1000*2,new BlockingQueue(),) + + + } + +} + + class TestRunable implements Runnable{ + + public void run() { + SingletonDemo1 intance = SingletonDemo1.getIntance(); + System.out.println(intance.hashCode()); + } + } diff --git a/group04/1796244932/learn01/src/main/java/com/dudy/learn01/designPattern/singleton/StaticClassInnerSingleton.java b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/designPattern/singleton/StaticClassInnerSingleton.java new file mode 100644 index 0000000000..d8b484cd15 --- /dev/null +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/designPattern/singleton/StaticClassInnerSingleton.java @@ -0,0 +1,63 @@ +package com.dudy.learn01.designPattern.singleton; + +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * Created by dudy on 2017/3/6. + * + * 静态内部类方式 实现 + * + * 这种方式同样利用了classloder的机制来保证初始化instance时只有一个线程, + * 它跟饿汉式不同的是(很细微的差别):饿汉式是只要Singleton类被装载了, + * 那么instance就会被实例化(没有达到lazy loading效果),而这种方式是Singleton类被装载了, + * instance不一定被初始化。因为SingletonHolder类没有被主动使用, + * 只有显示通过调用getInstance方法时,才会显示装载SingletonHolder类, + * 从而实例化instance。想象一下,如果实例化instance很消耗资源,我想让他延迟加载, + * 另外一方面,我不希望在Singleton类加载时就实例化, + * 因为我不能确保Singleton类还可能在其他的地方被主动使用从而被加载, + * 那么这个时候实例化instance显然是不合适的。这个时候,这种方式相比饿汉式更加合理 + * + */ +public class StaticClassInnerSingleton { + + // 构造器 私有化 + private StaticClassInnerSingleton(){} + + private static class SingletonHolder{ + private static final StaticClassInnerSingleton INSTANCE = new StaticClassInnerSingleton(); + } + + + public static StaticClassInnerSingleton getInstance(){ + return SingletonHolder.INSTANCE; + } + + + public static void main(String[] args) { + + + ThreadPoolExecutor pool = new ThreadPoolExecutor(10, 10, + 6000 * 10, TimeUnit.MILLISECONDS, + new LinkedBlockingDeque()); + + for (int i= 0; i<20; i++){ + pool.execute(new StaicSingletonTest()); + //System.out.println(StaticClassInnerSingleton.getInstance().hashCode()); + } + + pool.shutdown(); + } + + + +} + +class StaicSingletonTest implements Runnable{ + + public void run() { + StaticClassInnerSingleton intance = StaticClassInnerSingleton.getInstance(); + System.out.println(intance.hashCode()); + } +} \ No newline at end of file diff --git a/group04/1796244932/learn01/src/main/java/com/dudy/learn01/utils/ArraySortDemo.java b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/utils/ArraySortDemo.java new file mode 100644 index 0000000000..a26790375a --- /dev/null +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/utils/ArraySortDemo.java @@ -0,0 +1,107 @@ +package com.dudy.learn01.utils; + +import java.util.Arrays; + +/** + * Created by dudy on 2017/3/6. + * 练习数组的各种排序 + * 参考:http://wiki.jikexueyuan.com/project/java-special-topic/sort.html + * http://www.cnblogs.com/liuling/p/2013-7-24-01.html + * + * 内排序有可以分为以下几类: + +   (1)、插入排序:直接插入排序、二分法插入排序、希尔排序。 + +   (2)、选择排序:简单选择排序、堆排序。 + +   (3)、交换排序:冒泡排序、快速排序。 + +   (4)、归并排序 + +   (5)、基数排序 + * + */ +public class ArraySortDemo { + + + /** + * 二分法查找 插入 + * 和 直接插入排序不同的是: 查找 要插入的位置的方式不同 + * 二分法前提是有序的** + * + * + * + */ + public static void dichotomySort(int src[]){ + + for (int i = 0; i< src.length ; i++){ + int temp = src[i]; + int right = i - 1; + int mid = 0; + int left = 0; + while (left <= right){ + mid = (left + right)/2; + if (temp > src[mid]){ + left = mid + 1; + } else { + right = mid - 1; + } + } + + for (int j = i-1;j>=left ; j--){ + src[j+1] = src[j]; + } + + System.out.println("left = " + left +" ,mid = " + mid + " ,right = " + right); + src[left] = temp; + + } + } + + + + + /** + * 直接插入排序 + * 思想:假定前边是有序地部分, 后边无序的插入到前边部分 + * 可以转变思想: 从后往前遍历, 将有序部分大于当前的值 往后移 + * @param src + */ + public static void directInsertSort(int[] src){ + + for (int i = 1;i < src.length ; i++){ + // 待插入的元素 + int temp = src[i]; + int j; + for ( j = i -1; j >= 0; j--){ + // 大于 temp的往后移动 + if (src[j] > temp){ + src[j+1] = src[j]; + } else { + break; + } + }// 此时遍历完 j+1 为要插入的位置 + src[j+1] = temp; + } + + } + + + + public static void main(String[] args) { + int a[] = new int[]{46,89,14,44,90,32,25,67,23}; + // 14,23,25,32,44,46,67,89,90 + //Arrays.sort(a); + + + //directInsertSort(a); + + dichotomySort(a); + + for (int i = 0; i< a.length ; i++){ + System.out.print(a[i] + ","); + } + + } + +} From 4c61b24c65f4c10d0ec206108ee2bfb8b94306a6 Mon Sep 17 00:00:00 2001 From: x_zhaohu Date: Tue, 7 Mar 2017 21:41:52 +0800 Subject: [PATCH 004/287] 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 7d464ac089e796c247ee733a0f8471f02c2fcd66 Mon Sep 17 00:00:00 2001 From: fengyuxia <474772605@qq.com> Date: Tue, 7 Mar 2017 22:47:59 +0800 Subject: [PATCH 005/287] =?UTF-8?q?=E7=AC=AC=E4=BA=8C=E6=AC=A1=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group04/474772605/jsp/homepage.jsp | 12 ++ group04/474772605/jsp/showLogin.jsp | 12 ++ .../com/coderising/action/LogoutAction.java | 40 ++++ .../src/com/coderising/action/Struts.java | 181 +++++++----------- group04/474772605/src/struts.xml | 2 +- 5 files changed, 133 insertions(+), 114 deletions(-) create mode 100644 group04/474772605/jsp/homepage.jsp create mode 100644 group04/474772605/jsp/showLogin.jsp create mode 100644 group04/474772605/src/com/coderising/action/LogoutAction.java diff --git a/group04/474772605/jsp/homepage.jsp b/group04/474772605/jsp/homepage.jsp new file mode 100644 index 0000000000..83fa84db7d --- /dev/null +++ b/group04/474772605/jsp/homepage.jsp @@ -0,0 +1,12 @@ +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" + pageEncoding="ISO-8859-1"%> + + + + +homepage + + + + + \ No newline at end of file diff --git a/group04/474772605/jsp/showLogin.jsp b/group04/474772605/jsp/showLogin.jsp new file mode 100644 index 0000000000..1e6cda01b1 --- /dev/null +++ b/group04/474772605/jsp/showLogin.jsp @@ -0,0 +1,12 @@ +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" + pageEncoding="ISO-8859-1"%> + + + + +showLogin + + + + + \ No newline at end of file diff --git a/group04/474772605/src/com/coderising/action/LogoutAction.java b/group04/474772605/src/com/coderising/action/LogoutAction.java new file mode 100644 index 0000000000..10e4eb37c7 --- /dev/null +++ b/group04/474772605/src/com/coderising/action/LogoutAction.java @@ -0,0 +1,40 @@ +package com.coderising.action; + +/** + * 这是一个用来展示登录的业务类, 其中的用户名和密码都是硬编码的。 + * @author liuxin + * + */ +public class LogoutAction{ + 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 "success1"; + } + 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/group04/474772605/src/com/coderising/action/Struts.java b/group04/474772605/src/com/coderising/action/Struts.java index e2098dff74..7db0e4687f 100644 --- a/group04/474772605/src/com/coderising/action/Struts.java +++ b/group04/474772605/src/com/coderising/action/Struts.java @@ -21,126 +21,81 @@ public class Struts { public static void main(String[] args) throws DocumentException { -String actionName = "com.coderising.action.LoginAction"; + String actionName = "login"; Map params = new HashMap(); params.put("name","test"); - params.put("password","1234"); - - - View view = Struts.runAction(actionName,params); + params.put("password","1234"); + View view = Struts.runAction(actionName,params); + System.out.println(view.getJsp()); + System.out.println(view.getParameters()); } - -/* //遍历当前节点下的所有节点 - public static void listNodes(Element node){ - System.out.println("当前节点的名称:" + node.getName()); - //首先获取当前节点的所有属性节点 - List list = node.attributes(); - //遍历属性节点 - for(Attribute attribute : list){ - System.out.println("属性"+attribute.getName() +":" + attribute.getValue()); - } - //如果当前节点内容不为空,则输出 - if(!(node.getTextTrim().equals(""))){ - System.out.println( node.getName() + ":" + node.getText()); - } - //同时迭代当前节点下面的所有子节点 - //使用递归 - Iterator iterator = node.elementIterator(); - while(iterator.hasNext()){ - Element e = iterator.next(); - listNodes(e); - } - } */ - public static View runAction(String actionName, Map parameters) { - - SAXReader reader = new SAXReader(); + View view = new View(); + SAXReader reader = new SAXReader(); //读取文件 转换成Document - org.dom4j.Document document; - try { - document = reader.read(new File("src/struts.xml")); - Element root = document.getRootElement(); - List childList2 = root.elements("action"); - Iterator it = childList2.iterator(); - /* while (it.hasNext()){ - Element element = it.next(); - System.out.println("节点的名称" + element.getName() + "节点的值" + element.getText()); - - }*/ - for (int i = 0; i < childList2.size(); i++) { - List list = childList2.get(i).attributes(); - Iterator it1 = list.iterator(); - while(it1.hasNext()){ - - Attribute attribute1 = it1.next(); - System.out.println(attribute1.getName()); - System.out.println(attribute1.getValue()); - System.out.println("=============="); - - } - - for(Attribute attribute : list){ - - if(actionName.equals(attribute.getValue())){ - - String clazz = null; - - clazz = attribute.getValue(); - try { - Object o = Class.forName(clazz).newInstance(); - try { - Method m = o.getClass().getMethod("setName", String.class); - Method m1 = o.getClass().getMethod("setPassword", String.class); - Method m3 = o.getClass().getMethod("execute"); - try { - m.invoke(o, parameters.get("name")); - m1.invoke(o, parameters.get("password")); - String result = (String) m3.invoke(o); - System.out.println(result); - } catch (IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (InvocationTargetException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } catch (SecurityException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (NoSuchMethodException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + org.dom4j.Document document; + try { + document = reader.read(new File("src/struts.xml")); + Element root = document.getRootElement(); + @SuppressWarnings("unchecked") + List elements = root.elements(); + for (Element element : elements) { + Attribute actionAttribute = element.attribute("name"); + Attribute classAttribute = element.attribute("class"); + if(actionName.equals(actionAttribute.getValue())){ + String clazz = null; + clazz = classAttribute.getValue(); + Object o = Class.forName(clazz).newInstance(); + for (Map.Entry entry : parameters.entrySet()) { + String name = entry.getKey(); + String value =entry.getValue(); + String methodname = "set"+name.substring(0,1).toUpperCase()+name.substring(1); + Method m = o.getClass().getMethod(methodname, String.class); + m.invoke(o, value); + + } + Method m3 = o.getClass().getMethod("execute"); + String result = (String) m3.invoke(o); + String jspPath = null; + List element1s = element.elements("result"); + if(result.equals("success")){ + for (int i = 0; i < element1s.size(); i++) { + Attribute attribute2 = element1s.get(i).attribute("name"); + if (attribute2.getValue().equals("success")) { + jspPath = element1s.get(i).getStringValue(); + } + } + }else if(result.equals("fail")){ + for (int i = 0; i < element1s.size(); i++) { + Attribute attribute2 = element1s.get(i).attribute("name"); + if (attribute2.getValue().equals("fail")) { + jspPath = element1s.get(i).getStringValue(); } - - - } catch (InstantiationException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (ClassNotFoundException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } //根据class生成实例 - } - - - } - - } - } catch (DocumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - //获取根节点元素对象 - - - - + } + } + HashMapviewparamterHashMap = new HashMap(); + Method[]methods = o.getClass().getMethods(); + String methodname; + for (int j = 0; j < o.getClass().getMethods().length; j++) { + methodname = methods[j].getName(); + if(methodname.startsWith("get")&&!methodname.equals("getClass")){ + String methodname1 = methods[j].getName(); + methodname1 = methodname.substring(3,4).toUpperCase()+methodname1.substring(4); + viewparamterHashMap.put(methodname1, methods[j].invoke(o)); + } + } + view.setJsp(jspPath); + view.setParameters(viewparamterHashMap); + return view; + } + } + } catch (Exception e) { + // TODO: handle exception + } + return null; /* 0. 读取配置文件struts.xml @@ -161,7 +116,7 @@ public static View runAction(String actionName, Map parameters) */ - return null; - } + + } } diff --git a/group04/474772605/src/struts.xml b/group04/474772605/src/struts.xml index 90cf18b7da..8bd00bb1f0 100644 --- a/group04/474772605/src/struts.xml +++ b/group04/474772605/src/struts.xml @@ -6,6 +6,6 @@ /jsp/welcome.jsp - /jsp/error.jsp + /jsp/error.jsp \ No newline at end of file From e01ba89120b5c5b347b17d3989d76a3c333c4811 Mon Sep 17 00:00:00 2001 From: Samson Shenglu Cao Date: Sun, 12 Mar 2017 01:41:21 +0800 Subject: [PATCH 006/287] 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 fb079fa52524dc983f7954bc9a709c8a69ef0545 Mon Sep 17 00:00:00 2001 From: Administrator Date: Sun, 12 Mar 2017 08:55:30 +0800 Subject: [PATCH 007/287] =?UTF-8?q?add=20=E6=95=B0=E6=8D=AE=E7=BB=93?= =?UTF-8?q?=E6=9E=84(=E4=B8=89)=20=E5=8D=95=E5=90=91=E9=93=BE=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../one/src/org/coding/one/LinkedList.java | 3 + .../one/src/org/coding/three/list/List.java | 9 + .../coding/three/list/impl/LinkedList.java | 422 ++++++++++++++++ .../three/list/impl/LinkedListTest.java | 477 ++++++++++++++++++ 4 files changed, 911 insertions(+) create mode 100644 group04/498654356/one/src/org/coding/three/list/List.java create mode 100644 group04/498654356/one/src/org/coding/three/list/impl/LinkedList.java create mode 100644 group04/498654356/one/test/org/coding/three/list/impl/LinkedListTest.java diff --git a/group04/498654356/one/src/org/coding/one/LinkedList.java b/group04/498654356/one/src/org/coding/one/LinkedList.java index 183f634418..3f98db326f 100644 --- a/group04/498654356/one/src/org/coding/one/LinkedList.java +++ b/group04/498654356/one/src/org/coding/one/LinkedList.java @@ -1,5 +1,8 @@ package org.coding.one; +/** + * 双链表/双向链表 + */ public class LinkedList implements List { private Node first; diff --git a/group04/498654356/one/src/org/coding/three/list/List.java b/group04/498654356/one/src/org/coding/three/list/List.java new file mode 100644 index 0000000000..d06cf962da --- /dev/null +++ b/group04/498654356/one/src/org/coding/three/list/List.java @@ -0,0 +1,9 @@ +package org.coding.three.list; + +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/group04/498654356/one/src/org/coding/three/list/impl/LinkedList.java b/group04/498654356/one/src/org/coding/three/list/impl/LinkedList.java new file mode 100644 index 0000000000..ef38ca811d --- /dev/null +++ b/group04/498654356/one/src/org/coding/three/list/impl/LinkedList.java @@ -0,0 +1,422 @@ +package org.coding.three.list.impl; + +import java.util.Arrays; +import java.util.Iterator; + +import org.coding.three.list.List; +/** + * 单链表/单向链表 + */ +public class LinkedList implements List { + /** + * 0. head 节点存储数据 + * 1. 这里的 head 第一次添加之后 "引用" 将不再改变;"值" 可以被修改已表示往首节点插入新的值。 + * 2. 可以将 head 修改为对 node 引用, 不存储任何数据。 + */ + private Node head; + + public void add(Object o){ + Node node = new Node(o); + if(head == null){ //第一次 + head = node; + } else { + getNode(size() - 1).next = node; + } + } + + private Node getNode(int index) { + checkIndex(index); + Node node = head; + for(int i = 0; i < index; i++) { + node = node.next; + } + return node; + } + + private void checkIndex(int index) { + int size = size(); + if(index < 0 || index > (size - 1)) { + throw new IndexOutOfBoundsException("size = " + size + ", index = " + index); + } + } + public void add(int index , Object o){ + checkIndex(index); + if(index == 0) { //更新 head 的值, 将旧值创建新的Node插入到 head 后 + Object data = head.data; + head.data = o; + Node node = new Node(data); + node.next = head.next; + head.next = node; + } else { + Node pre = getNode(index - 1); + Node node = new Node(o); + node.next = pre.next; + pre.next = node; + } + } + public Object get(int index){ + checkIndex(index); + return getNode(index).data; + } + public Object remove(int index){ + checkIndex(index); + Object data = null; + if(index == 0) { + Node next = head.next; + data = head.data; + if(next == null) { + head = null; + } else { + head.data = next.data; + head.next = next.next; + next.next = null; + } + } else { + Node pre = getNode(index - 1); + Node node = pre.next; + pre.next = node.next; + node.next = null; + data = node.data; + } + return data; + } + + public int size(){ + Node temp = head; + int size = 0; + while(temp != null) { + size++; + temp = temp.next; + } + return size; + } + + public void addFirst(Object o){ + add(0, o); + } + public void addLast(Object o){ + add(o); + } + public Object removeFirst(){ + return remove(0); + } + public Object removeLast(){ + return remove(size() - 1); + } + public Iterator iterator(){ + return new LinkedIterator(); + } + + class LinkedIterator implements Iterator { + int cursor = 0; + int lastRet = -1; + @Override + public boolean hasNext() { + return cursor != LinkedList.this.size(); + } + + @Override + public Object next() { + int i = cursor; + Object data = LinkedList.this.get(i); + lastRet = i; + cursor = i + 1; + return data; + } + + @Override + public void remove() { + if(lastRet < - 1) { + throw new RuntimeException("非法操作"); + } + LinkedList.this.remove(lastRet); + cursor--; + lastRet = -1; + } + } + + private static class Node{ + Object data; + Node next; + public Node(Object data) { + super(); + this.data = data; + } + + } + + /** + * 把该链表逆置 + * 例如链表为 3->7->10 , 逆置后变为 10->7->3 + */ + public void reverse(){ + int size = size(); + if(size < 2) { + return ; + } + int preIndex = 0; + int behindIndex = size - 1; + Node preNode = head; + while(preIndex < behindIndex) { + Node behindNode = getNode(behindIndex); + Object temp = preNode.data; + preNode.data = behindNode.data; + behindNode.data = temp; + preIndex++; + behindIndex--; + preNode = preNode.next; + } + } + + /** + * 删除一个单链表的前半部分 + * 例如:list = 2->5->7->8 , 删除以后的值为 7->8 + * 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10 + + */ + public void removeFirstHalf(){ + if(size() < 2) { + return; + } + int count = size() / 2; + Node preNode = getNode(count - 1); + Node nextNode = preNode.next; + preNode.next = null; + head.data = nextNode.data; + head.next = nextNode.next; + nextNode.next = null; + } + + /** + * 从第i个元素开始, 删除length 个元素 , 注意i从0开始 + * @param i + * @param length + */ + public void remove(int index, int length){ + checkIndex(index); + int size = size(); + if(index + length > size) { + length = size; + } + if(index == 0 && length == size) { + head = null; + return; + } + int tempIndex = index + length - 1; + Node endNode = getNode(tempIndex); + Node nextNode = endNode.next; + endNode.next = null; + if(index == 0) { //head + Node nnextNode = nextNode.next; + nextNode.next = null; + head.data = nextNode.data; + head.next = nnextNode; + } else { + Node preStartNode = getNode(index - 1); + preStartNode.next = nextNode; + } + } + /** + * 假定当前链表和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){ + Iterator it = list.iterator(); + int[] array = new int[list.size()]; + int size = size(); + int length = 0; + while(it.hasNext()) { + int index = (int) it.next(); + if(index >= size) { + break; + } + array[length++] = (int) get(index); + } + if(length == array.length) { + return array; + } else { + return Arrays.copyOf(array, length); + } + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 从当前链表中中删除在listB中出现的元素 + + * @param list + */ + + public void subtract(LinkedList list){ + Iterator it = list.iterator(); + while(it.hasNext()) { + Object next = it.next(); + Iterator iterator = this.iterator(); + while(iterator.hasNext()) { + if(next.equals(iterator.next())) { + iterator.remove(); + } + } + } + } + + /** + * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) + */ + public void removeDuplicateValues(){ + if(size() < 2) { + return; + } + Iterator it = iterator(); + Object pre = null; + while(it.hasNext()){ + Object data = it.next(); + if(pre != null && pre.equals(data)) { + it.remove(); + } else { + pre = data; + } + } + + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 试写一高效的算法,删除表中所有值大于min且小于max的元素(若表中存在这样的元素) + * @param min + * @param max + */ + public void removeRange(int min, int max){ + int size = size(); + if(size < 1) { + return; + } + int minVal = (int)get(0); + int maxVal = (int)get(size - 1); + if(minVal > min && maxVal < max) { //直接清空 + this.head = null; + return; + } + if(max <= minVal) { + return; + } + if(min >= maxVal) { + return; + } + int startIndex = getMinIndex(min, size); + int endIndex = getMaxIndex(max, size); + if(endIndex - startIndex < 0) { + return; + } + remove(startIndex, (endIndex - startIndex) + 1); + + } + + private int getMaxIndex(int max, int size) { + int start = 0; + int end = size - 1; + while(start < end) { + int index = (end + start) / 2; + int midVal = (int) get(index); + if(midVal == max) { + return index - 1; +// index = index - 1; +// Node node = getNode(index); +// if((int)node.data < maxVal) { +// return index ; +// }//不考虑重复 TODO + } + if(midVal > max) { + end = index - 1; + } else { + start = index + 1; + } + } + if((int)get(end) >= max) { + return 0; + } + return end; + } + + private int getMinIndex(int min, int size) { + int start = 0; + int end = size - 1; + while(start < end) { + int index = (end + start) / 2; + int midVal = (int) get(index); + if(midVal == min) { + return index + 1; +// Node node = getNode(index); //暂无考虑重复 TODO +// if(node.next != null && (int)node.next.data > midVal) { +// return index + 1; +// } else { +// while(node.next != null && (int)node.next.data == midVal) { // 重复值 +// node = node.next; +// index++; +// } +// return index; +// +// } + } + if(midVal > min) { + end = index - 1; + } else { + start = index + 1; + } + } + if((int)get(start) <= min) { + return size; + } + return start; + } + + /** + * 假设当前链表和参数list指定的链表均以元素依值递增有序排列(同一表中的元素值各不相同) + * 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列 + * @param list + */ + public LinkedList intersection( LinkedList list){ + LinkedList linkedList = new LinkedList(); + if(list == null || size() == 0 || list.size() == 0) { + return linkedList; + } + Iterator it = iterator(); + int index = 0; + boolean iseqFlag = false; + boolean isgtFlag = false; + while(it.hasNext()) { + int v1 = (int) it.next(); + if(index != 0) { + if(iseqFlag) { + list.remove(0, index + 1); + iseqFlag = false; + } + if(isgtFlag) { + list.remove(0, index); + isgtFlag = false; + } + } + Iterator it2 = list.iterator(); + while(it2.hasNext()) { + int v2 = (int) it2.next(); + if(v2 == v1) { + linkedList.add(v1); + iseqFlag = true; + break; + } else if(v2 > v1) { + isgtFlag = true; + break; + } + index++; + } + if(index == list.size()) { //第二个链表中的值是否全部小于现在第一个链表中正在进行比较的值 + break; + } + } + return linkedList; + } +} diff --git a/group04/498654356/one/test/org/coding/three/list/impl/LinkedListTest.java b/group04/498654356/one/test/org/coding/three/list/impl/LinkedListTest.java new file mode 100644 index 0000000000..88a8bdf9b3 --- /dev/null +++ b/group04/498654356/one/test/org/coding/three/list/impl/LinkedListTest.java @@ -0,0 +1,477 @@ +package org.coding.three.list.impl; + +import static org.junit.Assert.fail; + +import java.util.Iterator; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class LinkedListTest { + private LinkedList linkedList; + + @Before + public void setUp() throws Exception { + linkedList = new LinkedList(); + } + + @After + public void tearDown() throws Exception { + linkedList = null; + } + + @Test + public void testAddObject() { + int expected = 0; + int actual = linkedList.size(); + Assert.assertEquals(expected, actual); + + linkedList.add(1); + expected = 1; + actual = linkedList.size(); + Assert.assertEquals(expected, actual); + + linkedList.add(2); + expected = 2; + actual = linkedList.size(); + Assert.assertEquals(expected, actual); + } + + @Test + public void testAddIntObject() { + linkedList.add(1); + linkedList.add(2); + linkedList.add(3); + + linkedList.add(0, 4); + int expected = 4; + int actual = (int) linkedList.get(0); + Assert.assertEquals(expected, actual); + Assert.assertEquals(4, linkedList.size()); + + linkedList.add(2, 5); + Assert.assertEquals(5, linkedList.size()); + expected = 5; + actual = (int) linkedList.get(2); + Assert.assertEquals(expected, actual); + + } + + @Test + public void testGet() { + linkedList.add(1); + linkedList.add(2); + linkedList.add(3); + + int expected = 1; + int actual = (int) linkedList.get(0); + Assert.assertEquals(expected, actual); + + expected = 2; + actual = (int) linkedList.get(1); + Assert.assertEquals(expected, actual); + + expected = 3; + actual = (int) linkedList.get(2); + Assert.assertEquals(expected, actual); + } + + @Test + public void testRemoveInt() { + linkedList.add(1); + + int v = (int) linkedList.remove(0); + Assert.assertEquals(1, v); + Assert.assertEquals(0, linkedList.size()); + + linkedList.add(1); + linkedList.add(2); + linkedList.add(3); + + v = (int) linkedList.remove(1); + Assert.assertEquals(2, v); + Assert.assertEquals(2, linkedList.size()); + + linkedList.add(4); + linkedList.add(5); + linkedList.add(6); + + v = (int) linkedList.remove(linkedList.size() - 1); + Assert.assertEquals(6, v); + Assert.assertEquals(4, linkedList.size()); + } + + @Test + public void testSize() { + Assert.assertEquals(0, linkedList.size()); + linkedList.add(1); + Assert.assertEquals(1, linkedList.size()); + linkedList.remove(0); + Assert.assertEquals(0, linkedList.size()); + } + + @Test + public void testAddFirst() { + linkedList.add(4); + linkedList.add(5); + linkedList.add(6); + linkedList.addFirst(1); + Assert.assertEquals(4, linkedList.size()); + Assert.assertEquals(1, linkedList.get(0)); + } + + @Test + public void testAddLast() { + linkedList.addLast(1); + Assert.assertEquals(1, linkedList.size()); + Assert.assertEquals(1, linkedList.get(0)); + linkedList.addLast(2); + Assert.assertEquals(2, linkedList.size()); + Assert.assertEquals(2, linkedList.get(1)); + } + + @Test + public void testRemoveFirst() { + linkedList.add(4); + linkedList.add(5); + linkedList.add(6); + int v = (int) linkedList.removeFirst(); + Assert.assertEquals(2, linkedList.size()); + Assert.assertEquals(4, v); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testRemoveFirstException() { + linkedList.removeFirst(); + } + + @Test + public void testRemoveLast() { + linkedList.add(4); + int v = (int) linkedList.removeLast(); + Assert.assertEquals(0, linkedList.size()); + Assert.assertEquals(4, v); + + linkedList.add(5); + linkedList.add(6); + v = (int) linkedList.removeLast(); + Assert.assertEquals(1, linkedList.size()); + Assert.assertEquals(6, v); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testRemoveLastException() { + linkedList.removeLast(); + } + @Test + public void testIterator() { + linkedList.add(1); + linkedList.add(2); + linkedList.add(3); + Iterator it = linkedList.iterator(); + int expected = 1; + while(it.hasNext()) { + Object v = it.next(); + Assert.assertEquals(expected++, v); + } + + } + + @Test + public void testIteratorRemove() { + linkedList.add(1); + linkedList.add(2); + linkedList.add(3); + Iterator it = linkedList.iterator(); + while(it.hasNext()) { + it.next(); + it.remove(); + } + Assert.assertEquals(0, linkedList.size()); + + } + @Test + public void testReverse() { + linkedList.add(3); + linkedList.add(7); + linkedList.add(10); + linkedList.reverse(); + Assert.assertEquals(10, linkedList.get(0)); + Assert.assertEquals(7, linkedList.get(1)); + Assert.assertEquals(3, linkedList.get(2)); + } + + @Test + public void testReverse2() { + linkedList.add(3); + linkedList.reverse(); + Assert.assertEquals(3, linkedList.get(0)); + } + + @Test + public void testReverse3() { + linkedList.add(3); + linkedList.add(7); + linkedList.reverse(); + Assert.assertEquals(7, linkedList.get(0)); + Assert.assertEquals(3, linkedList.get(1)); + } + + + + @Test + public void testRemoveFirstHalf() { + linkedList.add(2); + linkedList.add(5); + linkedList.add(7); + linkedList.add(8); + linkedList.removeFirstHalf(); + Assert.assertEquals(7, linkedList.get(0)); + Assert.assertEquals(8, linkedList.get(1)); + } + + @Test + public void testRemoveFirstHalf2() { + linkedList.add(2); + linkedList.add(5); + linkedList.add(7); + linkedList.add(8); + linkedList.add(10); + linkedList.removeFirstHalf(); + Assert.assertEquals(7, linkedList.get(0)); + Assert.assertEquals(8, linkedList.get(1)); + Assert.assertEquals(10, linkedList.get(2)); + } + + @Test + public void testRemoveIntInt() { + linkedList.add(2); + linkedList.add(5); + linkedList.add(7); + linkedList.add(8); + linkedList.add(10); + linkedList.remove(1, 2); + Assert.assertEquals(3, linkedList.size()); + Assert.assertEquals(2, linkedList.get(0)); + Assert.assertEquals(8, linkedList.get(1)); + Assert.assertEquals(10, linkedList.get(2)); + } + + + @Test + public void testRemoveIntIntFull() { + linkedList.add(2); + linkedList.add(5); + linkedList.add(7); + linkedList.add(8); + linkedList.add(10); + linkedList.remove(0, 10); + Assert.assertEquals(0, linkedList.size()); + } + + + @Test + public void testRemoveIntIntHead() { + linkedList.add(2); + linkedList.add(5); + linkedList.add(7); + linkedList.add(8); + linkedList.add(10); + linkedList.remove(0, 2); + Assert.assertEquals(3, linkedList.size()); + Assert.assertEquals(7, linkedList.get(0)); + Assert.assertEquals(8, linkedList.get(1)); + Assert.assertEquals(10, linkedList.get(2)); + } + + @Test + public void testGetElements() { +// 11->101->201->301->401->501->601->701 + linkedList.add(11); + linkedList.add(101); + linkedList.add(201); + linkedList.add(301); + linkedList.add(401); + linkedList.add(501); + linkedList.add(601); + linkedList.add(701); +// 1->3->4->6 + LinkedList list = new LinkedList(); + list.add(1); + list.add(3); + list.add(4); + list.add(6); + int[] actuals = linkedList.getElements(list ); + int[] expecteds = {101,301,401,601}; + Assert.assertArrayEquals(expecteds, actuals); + } + + + @Test + public void testGetElements2() { +// 11->101->201->301->401->501->601->701 + linkedList.add(11); + linkedList.add(101); + linkedList.add(201); + linkedList.add(301); + linkedList.add(401); + linkedList.add(501); + linkedList.add(601); + linkedList.add(701); +// 1->3->4->20 + LinkedList list = new LinkedList(); + list.add(1); + list.add(3); + list.add(4); + list.add(20); + int[] actuals = linkedList.getElements(list ); + int[] expecteds = {101,301,401}; + Assert.assertArrayEquals(expecteds, actuals); + } + + @Test + public void testSubtract() { + linkedList.add(11); + linkedList.add(101); + linkedList.add(201); + linkedList.add(301); + linkedList.add(401); + linkedList.add(501); + linkedList.add(601); + linkedList.add(701); + LinkedList list = new LinkedList(); + list.add(11); + list.add(201); + list.add(501); + linkedList.subtract(list ); + Assert.assertEquals(5, linkedList.size()); + + } + + @Test + public void testSubtract2() { + linkedList.add(11); + linkedList.add(101); + LinkedList list = new LinkedList(); + list.add(11); + list.add(201); + list.add(501); + linkedList.subtract(list ); + Assert.assertEquals(1, linkedList.size()); + + } + + + @Test + public void testRemoveDuplicateValues() { + linkedList.add(11); + linkedList.add(101); + linkedList.add(201); + linkedList.add(201); + linkedList.add(201); + linkedList.add(301); + linkedList.add(301); + linkedList.add(401); + Assert.assertEquals(8, linkedList.size()); + linkedList.removeDuplicateValues(); + Assert.assertEquals(5, linkedList.size()); + Assert.assertEquals(301, linkedList.get(linkedList.size() - 2)); + Assert.assertEquals(201, linkedList.get(linkedList.size() - 3)); + + } + + @Test + public void testRemoveRange() { + linkedList.add(1); + linkedList.add(3); + linkedList.add(5); + linkedList.removeRange(4, 6); + Assert.assertEquals(2, linkedList.size()); + + } + + @Test + public void testRemoveRange2() { + linkedList.add(1); + linkedList.add(3); + linkedList.add(5); + linkedList.removeRange(0, 6); + Assert.assertEquals(0, linkedList.size()); + + } + + @Test + public void testRemoveRange3() { + linkedList.add(1); + linkedList.add(3); + linkedList.add(5); + linkedList.removeRange(3, 5); + Assert.assertEquals(3, linkedList.size()); + + } + + @Test + public void testRemoveRange4() { + linkedList.add(1); + linkedList.add(3); + linkedList.add(5); + linkedList.removeRange(1, 3); + Assert.assertEquals(3, linkedList.size()); + + } + + @Test + public void testRemoveRange5() { + linkedList.add(1); + linkedList.add(3); + linkedList.add(5); + linkedList.add(6); + linkedList.removeRange(3, 5); + Assert.assertEquals(4, linkedList.size()); + + } + + @Test + public void testIntersection() { + linkedList.add(1); + linkedList.add(3); + linkedList.add(5); + linkedList.add(6); + LinkedList list = new LinkedList(); + list.add(1); + list.add(3); + LinkedList newList = linkedList.intersection(list ); + Assert.assertEquals(2, newList.size()); + Assert.assertEquals(1, newList.get(0)); + Assert.assertEquals(3, newList.get(1)); + } + + @Test + public void testIntersection2() { + linkedList.add(1); + linkedList.add(3); + linkedList.add(5); + linkedList.add(6); + LinkedList list = new LinkedList(); + list.add(10); + list.add(13); + LinkedList newList = linkedList.intersection(list ); + Assert.assertEquals(0, newList.size()); + } + + @Test + public void testIntersection3() { + linkedList.add(3); + linkedList.add(5); + linkedList.add(6); + LinkedList list = new LinkedList(); + list.add(1); + list.add(2); + LinkedList newList = linkedList.intersection(list ); + Assert.assertEquals(0, newList.size()); + } + +} From 1ad824f439475f991ae3bbac1400803efca40d57 Mon Sep 17 00:00:00 2001 From: '1299310140' <'13437282785@163.com'> Date: Sun, 12 Mar 2017 22:17:43 +0800 Subject: [PATCH 008/287] LinkedList&&download --- .../coderising/download/DownloadThread.java | 38 +++ .../coderising/download/FileDownloader.java | 83 ++++++ .../download/impl/ConnectionImpl.java | 59 ++++ .../download/impl/ConnectionManagerImpl.java | 31 ++ .../src/com/coding/basic/LinkedList.java | 281 ++++++++++++++++++ 5 files changed, 492 insertions(+) create mode 100644 group04/1299310140/src/com/coderising/download/DownloadThread.java create mode 100644 group04/1299310140/src/com/coderising/download/FileDownloader.java create mode 100644 group04/1299310140/src/com/coderising/download/impl/ConnectionImpl.java create mode 100644 group04/1299310140/src/com/coderising/download/impl/ConnectionManagerImpl.java diff --git a/group04/1299310140/src/com/coderising/download/DownloadThread.java b/group04/1299310140/src/com/coderising/download/DownloadThread.java new file mode 100644 index 0000000000..ba5dab2a78 --- /dev/null +++ b/group04/1299310140/src/com/coderising/download/DownloadThread.java @@ -0,0 +1,38 @@ +package com.coderising.download; + +import java.io.FileOutputStream; +import java.io.IOException; + +import com.coderising.download.api.Connection; + +public class DownloadThread extends Thread{ + + Connection conn; + int startPos; + int endPos; + byte[] result; + + public DownloadThread( Connection conn, int startPos, int endPos, byte[] result){ + + this.conn = conn; + this.startPos = startPos; + this.endPos = endPos; + this.result = result; + + } + public void run(){ + try { + byte[] download = this.conn.read(this.startPos, this.endPos); + //synchronized(this.result){ + System.arraycopy(download, 0, this.result, this.startPos, download.length); + System.out.println(this.startPos+" "+this.endPos); + //} + FileOutputStream fos = new FileOutputStream("C:\\b.jpg"); + fos.write(this.result); + fos.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } +} diff --git a/group04/1299310140/src/com/coderising/download/FileDownloader.java b/group04/1299310140/src/com/coderising/download/FileDownloader.java new file mode 100644 index 0000000000..23520a9bd3 --- /dev/null +++ b/group04/1299310140/src/com/coderising/download/FileDownloader.java @@ -0,0 +1,83 @@ +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 = new ConnectionManagerImpl(); + + 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 connOne = null; + Connection connTwo = null; + Connection connThree = null; + try { + + connOne = cm.open(this.url); + connTwo = cm.open(this.url); + connThree = cm.open(this.url); + + int length = connOne.getContentLength(); + + byte[] result = new byte[length]; + new DownloadThread(connOne,0,length/3,result).start(); + new DownloadThread(connTwo,length/3+1,length/2,result).start(); + new DownloadThread(connThree,length/2+1,length-1,result).start(); + + } catch (ConnectionException e) { + e.printStackTrace(); + }finally{ + if(connOne != null){ + connOne.close(); + } + if(connTwo != null){ + connTwo.close(); + } + if(connThree != null){ + connThree.close(); + } + } + + } + + public void setListener(DownloadListener listener) { + this.listener = listener; + } + + public void setConnectionManager(ConnectionManager ucm){ + this.cm = ucm; + } + + public DownloadListener getListener(){ + return this.listener; + } + + public static void main(String[] args){ + new FileDownloader("http://img1.gtimg.com/17/1724/172495/17249563_980x1200_281.jpg").execute(); + } + +} diff --git a/group04/1299310140/src/com/coderising/download/impl/ConnectionImpl.java b/group04/1299310140/src/com/coderising/download/impl/ConnectionImpl.java new file mode 100644 index 0000000000..3628dd486f --- /dev/null +++ b/group04/1299310140/src/com/coderising/download/impl/ConnectionImpl.java @@ -0,0 +1,59 @@ +package com.coderising.download.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; + +import com.coderising.download.api.Connection; + +public class ConnectionImpl implements Connection{ + private URLConnection urlconn; + private InputStream fis; + + public ConnectionImpl(URLConnection urlconn) { + super(); + this.urlconn = urlconn; + } + + @Override + public byte[] read(int startPos, int endPos) throws IOException{ + this.fis = this.urlconn.getURL().openStream(); + byte[] buffer = new byte[512]; + int count = 0;//某次read的字节数 + int sum = 0;//read的总字节数 + int length = endPos - startPos + 1;//当前线程需读取的字节数 + byte[] download = new byte[length]; + fis.skip(startPos); + while((count = fis.read(buffer)) != -1){ + if(sum + count >= length){ + System.arraycopy(buffer, 0, download, sum, length - sum); + sum = length; + break; + }else{ + System.arraycopy(buffer, 0, download, sum, count); + sum = sum + count; + } + } + return download; + } + + @Override + public int getContentLength() { + return this.urlconn.getContentLength(); + } + + @Override + public void close() { + if(this.fis != null){ + try { + this.fis.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + +} diff --git a/group04/1299310140/src/com/coderising/download/impl/ConnectionManagerImpl.java b/group04/1299310140/src/com/coderising/download/impl/ConnectionManagerImpl.java new file mode 100644 index 0000000000..3035ce9459 --- /dev/null +++ b/group04/1299310140/src/com/coderising/download/impl/ConnectionManagerImpl.java @@ -0,0 +1,31 @@ +package com.coderising.download.impl; + +import java.io.IOException; +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 myurl = new URL("http://img1.gtimg.com/17/1724/172495/17249563_980x1200_281.jpg"); + URLConnection urlconn = myurl.openConnection(); + ConnectionImpl conn = new ConnectionImpl(urlconn); + return conn; + } catch (MalformedURLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return null; + } + +} diff --git a/group04/1299310140/src/com/coding/basic/LinkedList.java b/group04/1299310140/src/com/coding/basic/LinkedList.java index 4636bbd279..3e908613db 100644 --- a/group04/1299310140/src/com/coding/basic/LinkedList.java +++ b/group04/1299310140/src/com/coding/basic/LinkedList.java @@ -208,4 +208,285 @@ public String toString(){ return result; } } + + /** + * 把该链表逆置 + * 例如链表为 3->7->10 , 逆置后变为 10->7->3 + */ + public void reverse(){ + if(this.size <= 1){ + return; + } + Node before = null; + Node pres = this.head; + Node after = pres.next; + while(after != null){ + pres.next = before; + before = pres; + pres = after; + after = after.next; + } + //此时pres指向最后一个节点 + pres.next = before; + this.head = pres; + } + + /** + * 删除一个单链表的前半部分 + * 例如:list = 2->5->7->8 , 删除以后的值为 7->8 + * 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10 + */ + public void removeFirstHalf(){ + if(this.size <= 1){ + return; + } + Node pres = this.head; + Node temp = pres; + for(int i = 0;i < this.size / 2;i++){ + temp = pres; + pres = pres.next; + temp.data = null; + temp.next = null; + } + this.head = pres; + this.size = this.size - this.size / 2; + } + + /** + * 从第i个元素开始, 删除length 个元素 , 注意i从0开始 + * @param index + * @param length + */ + public void remove(int index, int length){//若length太大,size不够,则取到末尾 + if(index < 0 || index >= this.size || length <= 0){//index小于0or大于等于size,length小于等于0,参数错误 + return; + } + if(this.size <= 0){ + return; + } + if(index == 0){ + //此时index=0&&length>0&&size>0 + Node temp = this.head; + for(int i = 0;i < length;i++){ + temp = temp.next; + if(temp == null){ + break; + } + } + this.head = temp; + if(temp == null){ + this.size = 0; + }else{ + this.size = this.size - length; + } + }else{ + //此时00&&size>0 + Node start = this.head; + for(int j = 0;j < index-1;j++){ + start = start.next; + }//start指向index-1 + + Node end = start; + for(int l = 0;l <= length;l++){ + end = end.next; + if(end == null){ + break; + } + }//end指向index+length + start.next = end; + if(end == null){ + this.size = index; + }else{ + this.size = this.size - 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){//若listB中的index不在0~this.size-1之中,则返回-1 + if(this.size <= 0 || list == null || list.size <= 0){ + return null; + } + + int[] result = new int[list.size()]; + Node presIndex = list.head; + int index = (int)presIndex.data; + for(int i = 0;i < list.size();i++){ + if(index < 0 || index >= this.size){ + result[i] = -1; + }else{//index:0~this.size-1 + result[i] = (int)this.get(index); + } + presIndex = presIndex.next; + if(presIndex != null){ + index = (int)presIndex.data; + } + } + return result; + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 从当前链表中中删除在listB中出现的元素 + * @param list + */ + public void subtract(LinkedList list){//当前链表以及参数列表均递增有序,可有重复值 + if(this.size == 0 || list == null || list.size() == 0){ + return; + } + + //头节点的删除比较特殊,先不予考虑 + Node thisPres = this.head.next;//指向被删除节点 + Node thisPresBefore = this.head;//指向被删除节点的前一个节点 + Node listPres = list.head; + while(thisPres != null && listPres != null){ + if((int)thisPres.data > (int)listPres.data){ + listPres = listPres.next; + }else if((int)thisPres.data < (int)listPres.data){ + thisPresBefore = thisPresBefore.next; + thisPres = thisPres.next; + }else{//(int)thisPres.data == (int)listPres.data + thisPresBefore.next = thisPres.next; + thisPres = thisPres.next; + this.size--; + } + } + + //最后考虑头节点的删除情况 + Node first = this.head; + Node listPresTwo = list.head; + while((int)first.data > (int)listPresTwo.data){ + listPresTwo = listPresTwo.next; + } + if((int)first.data == (int)listPresTwo.data){//删除头节点 + this.head = this.head.next; + this.size--; + } + } + + /** + * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) + */ + public void removeDuplicateValues(){ + if(this.size <= 1){ + return; + } + + Node start = this.head; + Node end = start.next; + while(end != null){ + if((int)start.data != (int)end.data){ + start = end; + end = end.next; + }else{//start.data == end.data + while((int)start.data == (int)end.data){ + end = end.next; + if(end == null){ + break; + } + } + start.next = end; + } + } + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 试写一高效的算法,删除表中所有值大于min且小于max的元素(若表中存在这样的元素) + * @param min + * @param max + */ + public void removeRange(int min, int max){ + if(this.size == 0 || max - min < 2 || (int)this.head.data >= max){ + return; + } + + //this.size >= 1 && max - min >= 2 && this.head.data < max + int thisHeadData = (int)this.head.data; + if(thisHeadData > min && thisHeadData < max){ + //this.size >= 1 && max - min >= 2 && + //min < this.head.data < max + //找到新的头节点即可,this.size减小 + Node notSmallToMax = this.head.next; + int sizeDec = 1; + while(notSmallToMax != null){ + if((int)notSmallToMax.data >= max){ + break; + } + notSmallToMax = notSmallToMax.next; + sizeDec++; + } + this.head = notSmallToMax; + this.size = this.size - sizeDec; + }else{ + //this.size >= 1 && max - min >= 2 && + //this.head.data <= min + Node startBefore = this.head;//第一个>min节点的前一个节点 + Node start = startBefore.next;//第一个>min的节点 + while(start != null){ + if((int)start.data > min){ + break; + } + startBefore = start; + start = start.next; + } + if(start == null || (int)start.data >= max){ + //链表中不存在满足删除条件的元素 + return; + } + + //至少有一个元素需要被删除 + int sizeDec = 1; + Node end = start;//最后一个= max){ + break; + } + end = endAfter; + endAfter = endAfter.next; + sizeDec++; + } + startBefore.next = endAfter; + this.size = this.size - sizeDec; + } + } + + /** + * 假设当前链表和参数list指定的链表均以元素依值递增有序排列(同一表中的元素值各不相同) + * 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列 + * @param list + */ + public LinkedList intersection(LinkedList list){ + if(list == null || list.size() == 0){ + return new LinkedList(); + } + if(this.size == 0){ + return new LinkedList(); + } + LinkedList result = new LinkedList(); + Node thisPres = this.head; + Node listPres = list.head; + while(thisPres != null && listPres != null){ + if((int)thisPres.data < (int)listPres.data){ + thisPres = thisPres.next; + }else if((int)thisPres.data > (int)listPres.data){ + listPres = listPres.next; + }else{ + //(int)thisPres.data == (int)listPres.data + result.add(thisPres.data); + thisPres = thisPres.next; + listPres = listPres.next; + } + } + return result; + } } From 043093264b23b0f7945d219577371ca504d36b43 Mon Sep 17 00:00:00 2001 From: zj <2258659044@qq.com> Date: Mon, 13 Mar 2017 10:55:49 +0800 Subject: [PATCH 009/287] =?UTF-8?q?=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/coderising/download/NotifyCaller.java | 2 +- .../download/impl/ConnectionImpl.java | 34 ++++++++++++------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/group12/2258659044/zj-2017/src/com/coderising/download/NotifyCaller.java b/group12/2258659044/zj-2017/src/com/coderising/download/NotifyCaller.java index 03f4149688..df49a92a07 100644 --- a/group12/2258659044/zj-2017/src/com/coderising/download/NotifyCaller.java +++ b/group12/2258659044/zj-2017/src/com/coderising/download/NotifyCaller.java @@ -65,7 +65,7 @@ private String getDownloadSpeed(int timeDiff){ if(num==null||num.isEmpty()){ num = "0"; } - return num+"M/s"; + return num+"Mb/s"; } /** diff --git a/group12/2258659044/zj-2017/src/com/coderising/download/impl/ConnectionImpl.java b/group12/2258659044/zj-2017/src/com/coderising/download/impl/ConnectionImpl.java index ec8e503fe9..0ec6bf08e7 100644 --- a/group12/2258659044/zj-2017/src/com/coderising/download/impl/ConnectionImpl.java +++ b/group12/2258659044/zj-2017/src/com/coderising/download/impl/ConnectionImpl.java @@ -18,19 +18,8 @@ public class ConnectionImpl implements Connection{ @Override public byte[] read(int startPos, int endPos) throws IOException { - byte[] data = null; InputStream is = getDownloadStream(startPos,endPos); - if(is !=null){ - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - byte[] buffer = new byte[1024]; - int length = -1; - while ((length = is.read(buffer)) != -1) { - baos.write(buffer, 0, length); - } - baos.flush(); - data = baos.toByteArray(); - } - return data; + return inputStremCovertToArray(is); } @Override @@ -53,6 +42,27 @@ public void close() { httpConnection.disconnect(); } + /** + * 将输入流转换为byte数组 + * @param is + * @return + * @throws IOException + */ + private byte[] inputStremCovertToArray(InputStream is) throws IOException{ + + byte[] data = null; + if(is !=null){ + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int length = -1; + while ((length = is.read(buffer)) != -1) { + baos.write(buffer, 0, length); + } + baos.flush(); + data = baos.toByteArray(); + } + return data; + } public void setHttpConnection(HttpURLConnection httpConnection) { this.httpConnection = httpConnection; } From 3192aec0cee8950f9cd9b1707237d26f99baf9a3 Mon Sep 17 00:00:00 2001 From: zj <2258659044@qq.com> Date: Mon, 13 Mar 2017 11:00:12 +0800 Subject: [PATCH 010/287] =?UTF-8?q?=E5=9C=A8=E6=9B=B4=E6=96=B0=E4=B8=80?= =?UTF-8?q?=E9=81=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group12/2258659044/zj-2017/src/com/coding/basic/LinkedList.java | 1 - 1 file changed, 1 deletion(-) diff --git a/group12/2258659044/zj-2017/src/com/coding/basic/LinkedList.java b/group12/2258659044/zj-2017/src/com/coding/basic/LinkedList.java index 3bf26a1a1c..86a90383f4 100644 --- a/group12/2258659044/zj-2017/src/com/coding/basic/LinkedList.java +++ b/group12/2258659044/zj-2017/src/com/coding/basic/LinkedList.java @@ -180,7 +180,6 @@ public void remove(int i, int length){ if(length<(size-i)){ getPointNode(i-1).next = getPointNode(i+length); size = size-length; - size = size-length; }else{ getPointNode(i-1).next = null; size = i; From 67dd53acb2a81b374cbb13a9385653189124634c Mon Sep 17 00:00:00 2001 From: dudy Date: Mon, 13 Mar 2017 17:14:33 +0800 Subject: [PATCH 011/287] download --- group04/1796244932/learn01/1.png | Bin 0 -> 281 bytes group04/1796244932/learn01/pom.xml | 26 +++- .../com/dudy/learn01/base/MyLinkedList.java | 129 +++++++++++++++--- .../dudy/learn01/download/DownloadThread.java | 59 ++++++++ .../dudy/learn01/download/FileDownloader.java | 93 +++++++++++++ .../dudy/learn01/download/api/Connection.java | 23 ++++ .../download/api/ConnectionException.java | 5 + .../download/api/ConnectionManager.java | 13 ++ .../download/api/DownloadListener.java | 5 + .../learn01/download/impl/ConnectionImpl.java | 89 ++++++++++++ .../download/impl/ConnectionManagerImpl.java | 25 ++++ .../com/dudy/learn01/juc/ThreadLocalTest.java | 64 +++++++++ .../com/dudy/learn01/litestruts/Struts.java | 1 + .../litestruts/format/Configuration.java | 113 +++++++++++++++ .../format/ConfigurationException.java | 21 +++ .../litestruts/format/ConfigurationTest.java | 50 +++++++ .../litestruts/format/LoginAction.java | 39 ++++++ .../litestruts/format/ReflectionUtil.java | 123 +++++++++++++++++ .../litestruts/format/ReflectionUtilTest.java | 113 +++++++++++++++ .../learn01/litestruts/format/Struts.java | 68 +++++++++ .../learn01/litestruts/format/StrutsTest.java | 43 ++++++ .../dudy/learn01/litestruts/format/View.java | 23 ++++ .../dudy/learn01/litestruts/format/struts.xml | 11 ++ .../com/dudy/learn01/utils/ArraySortDemo.java | 3 - .../dudy/learn01/base/MyLinkedListTest.java | 59 ++++++++ .../learn01/download/FileDownloaderTest.java | 53 +++++++ 26 files changed, 1221 insertions(+), 30 deletions(-) create mode 100644 group04/1796244932/learn01/1.png create mode 100644 group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/DownloadThread.java create mode 100644 group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/FileDownloader.java create mode 100644 group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/api/Connection.java create mode 100644 group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/api/ConnectionException.java create mode 100644 group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/api/ConnectionManager.java create mode 100644 group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/api/DownloadListener.java create mode 100644 group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/impl/ConnectionImpl.java create mode 100644 group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/impl/ConnectionManagerImpl.java create mode 100644 group04/1796244932/learn01/src/main/java/com/dudy/learn01/juc/ThreadLocalTest.java create mode 100755 group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/Configuration.java create mode 100755 group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/ConfigurationException.java create mode 100755 group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/ConfigurationTest.java create mode 100755 group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/LoginAction.java create mode 100755 group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/ReflectionUtil.java create mode 100755 group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/ReflectionUtilTest.java create mode 100755 group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/Struts.java create mode 100755 group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/StrutsTest.java create mode 100755 group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/View.java create mode 100755 group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/struts.xml create mode 100644 group04/1796244932/learn01/src/test/java/com/dudy/learn01/download/FileDownloaderTest.java diff --git a/group04/1796244932/learn01/1.png b/group04/1796244932/learn01/1.png new file mode 100644 index 0000000000000000000000000000000000000000..a25be7d057e9083652fcd595edf131048107baf3 GIT binary patch literal 281 zcmeAS@N?(olHy`uVBq!ia0vp^3xU{;gAGV75%|&rq$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~-c747zPaSW-r_2!bJAOi!(VS@wvpDQNMcX3)jJ7vL3l>;p^ m0+@U{I8_H5W5HWi2?oA>%$@Jfdom4j 1.6 + + + + + org.jdom + jdom + 2.0.2 + + + junit junit - 4.11 - test + 4.12 - - org.junit.jupiter - junit-jupiter-api - RELEASE - + + + + io.netty + netty + 4.0.0.Alpha8 + + diff --git a/group04/1796244932/learn01/src/main/java/com/dudy/learn01/base/MyLinkedList.java b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/base/MyLinkedList.java index e0dbe9aae8..a425f54e81 100644 --- a/group04/1796244932/learn01/src/main/java/com/dudy/learn01/base/MyLinkedList.java +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/base/MyLinkedList.java @@ -1,6 +1,13 @@ package com.dudy.learn01.base; +import java.util.LinkedList; + +/** + * 单链表: + * 因为没有尾节点 + * 存放时 add 1 2 3 4 实际是 4 3 2 1 + */ public class MyLinkedList implements MyList { private int size = 0; @@ -24,6 +31,7 @@ public void add(int index, Object o) { } private Node getCurrentNode(int index) {// 获取当前节点 + checkRange(index); Node current = head; for(int i = 0; i< size-index -1; i++){ current = current.next; @@ -56,7 +64,7 @@ public Object remove(int index) { return node.data; } - public int size() { + public int size() { return size; } @@ -89,17 +97,6 @@ public Object removeLast() { return tmp.data; } - /** - * 链表逆序 - */ - public void reverse(){ - - } - - - - - public MyIterator iterator() { return new MyLinkedListItr(); } @@ -130,15 +127,107 @@ public Node(Object data) { } } - - private void displayLink() {// 自己调试使用 - Node current = head; - while(current != null){ - System.out.print(current.data); - current = current.next; + + /** + * 把该链表逆置 + * 例如链表为 3->7->10 , 逆置后变为 10->7->3 + */ + public void reverse(){ + + if(head == null || head.next == null){ + return ; + } + + Node current = head; // 当前节点 我的头节点是有数据的 + + while (current.next != null){ + Node p = current.next; // 当前节点的下一个 + current.next = p.next; // 当前节点的next -> current.next.next (p.next) + p.next = head; // current.next(p) -> head.next (插入到 head 和 第一个数据之间) + head = p; } - System.out.println(""); } - + + /** + * 删除一个单链表的前半部分 + * 例如:list = 2->5->7->8 , 删除以后的值为 7->8 + * 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10 + + */ + public void removeFirstHalf(){ + + int base = size; + Node currentNode = getCurrentNode(base / 2); + currentNode = null; + size = size - base/2; + } + + /** + * 从第i个元素开始, 删除length 个元素 , 注意i从0开始 + * @param i + * @param length + */ + public void remove(int i, int length){ + + Node preNode = getCurrentNode(size - i -1); + Node nextNode = getCurrentNode(size - i - length-1); + nextNode.next = preNode; + size = size -length; + } + /** + * 假定当前链表和list均包含已升序排列的整数 + * 从当前链表中取出那些list所指定的元素 + * 例如当前链表 = 11->101->201->301->401->501->601->701 + * listB = 1->3->4->6 + * 返回的结果应该是[101,301,401,601] + * @param src + */ + public Object[] getElements(int[] src){ + Object des[] = new Object[src.length]; + + for (int i = 0; i < src.length; i++){ + des[i] = getCurrentNode(size - 1 - i).data; + } + + return des; + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 从当前链表中中删除在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; + } } \ No newline at end of file diff --git a/group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/DownloadThread.java b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/DownloadThread.java new file mode 100644 index 0000000000..97ca01e13b --- /dev/null +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/DownloadThread.java @@ -0,0 +1,59 @@ +package com.dudy.learn01.download; + +import com.dudy.learn01.download.api.Connection; + +import java.io.*; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.CyclicBarrier; + +public class DownloadThread extends Thread{ + + private Connection conn; + private int startPos; + private int endPos; + private RandomAccessFile raf; + //private CyclicBarrier cb; + private CountDownLatch downLatch; + + + public DownloadThread(Connection conn, int startPos, int endPos, + /*CyclicBarrier cb*/ + CountDownLatch downLatch){ + + this.conn = conn; + this.startPos = startPos; + this.endPos = endPos; +// this.cb = cb; + this.downLatch = downLatch; + } + public void run(){ + try { + byte[] read = conn.read(startPos, endPos); + + System.out.println("read length: -> "+read.length); + //这里要注意新创建一个RandomAccessFile对象,而不能重复使用download方法中创建的 + raf = new RandomAccessFile(new File("/Users/dudy/Desktop/1.png"), "rw"); + //将写文件的指针指向下载的起始点 + raf.seek(startPos); + raf.write(read, 0, read.length); + + downLatch.countDown(); +// cb.await(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (raf != null){ + raf.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + if (conn != null){ + conn.close(); + } + + } + } +} \ No newline at end of file diff --git a/group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/FileDownloader.java b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/FileDownloader.java new file mode 100644 index 0000000000..eee5825b84 --- /dev/null +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/FileDownloader.java @@ -0,0 +1,93 @@ +package com.dudy.learn01.download; + +import com.dudy.learn01.download.api.Connection; +import com.dudy.learn01.download.api.ConnectionManager; +import com.dudy.learn01.download.api.DownloadListener; + +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.CyclicBarrier; + +public class FileDownloader { + + private static final int THREAD_NUM = 3; + + private String url; + + private DownloadListener listener; + + private ConnectionManager cm; + + + public FileDownloader(String _url) { + this.url = _url; + + } + + 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 { + //CyclicBarrier cb = new CyclicBarrier(THREAD_NUM); + CountDownLatch downLatch = new CountDownLatch(THREAD_NUM); + + conn = cm.open(this.url); + + int length = conn.getContentLength(); + + for (int i = 0;i < THREAD_NUM; i++){ + + int start=i*length/THREAD_NUM; + int end = (i+1)*length/THREAD_NUM-1; + if(i==THREAD_NUM-1) + { + end =length; + } + + new DownloadThread(cm.open(url),start,end,downLatch).start(); + } + + //cb.await(); + downLatch.await(); + getListener().notifyFinished(); + + } catch (Exception 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; + } + +} \ No newline at end of file diff --git a/group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/api/Connection.java b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/api/Connection.java new file mode 100644 index 0000000000..513c0004e9 --- /dev/null +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/api/Connection.java @@ -0,0 +1,23 @@ +package com.dudy.learn01.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(); +} \ No newline at end of file diff --git a/group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/api/ConnectionException.java b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/api/ConnectionException.java new file mode 100644 index 0000000000..71af9bf06d --- /dev/null +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/api/ConnectionException.java @@ -0,0 +1,5 @@ +package com.dudy.learn01.download.api; + +public class ConnectionException extends Exception { + +} \ No newline at end of file diff --git a/group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/api/ConnectionManager.java b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/api/ConnectionManager.java new file mode 100644 index 0000000000..5f4777f6e0 --- /dev/null +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/api/ConnectionManager.java @@ -0,0 +1,13 @@ +package com.dudy.learn01.download.api; + +import java.io.IOException; +import java.net.MalformedURLException; + +public interface ConnectionManager { + /** + * 给定一个url , 打开一个连接 + * @param url + * @return + */ + public Connection open(String url) throws ConnectionException, IOException; +} \ No newline at end of file diff --git a/group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/api/DownloadListener.java b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/api/DownloadListener.java new file mode 100644 index 0000000000..fa3b5bead0 --- /dev/null +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/api/DownloadListener.java @@ -0,0 +1,5 @@ +package com.dudy.learn01.download.api; + +public interface DownloadListener { + public void notifyFinished(); +} \ No newline at end of file diff --git a/group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/impl/ConnectionImpl.java b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/impl/ConnectionImpl.java new file mode 100644 index 0000000000..5eb6b45d41 --- /dev/null +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/impl/ConnectionImpl.java @@ -0,0 +1,89 @@ +package com.dudy.learn01.download.impl; + +import com.dudy.learn01.download.api.Connection; + +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class ConnectionImpl implements Connection { + + + private HttpURLConnection connection; + + public ConnectionImpl(String url) { + try { + this.connection = (HttpURLConnection) new URL(url).openConnection(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public byte[] read(int startPos, int endPos) throws IOException { + + connection.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos); + + InputStream in = connection.getInputStream(); + byte buffer[] = new byte[endPos-startPos+1]; + byte result[] = new byte[endPos-startPos+1]; + int count = 0; // 记录已经读取的数据 + int length = -1 ; + + while ((length = in.read(buffer)) > 0){ + System.arraycopy(buffer,0,result,count,length); + count += length; + } + return result; + } + + @Override + public int getContentLength() { + return connection.getContentLength(); + } + + @Override + public void close() { + if (connection != null){ + connection.disconnect(); + } + } + + public static void main(String[] args) throws Exception{ + //String PATH = "http://demo2.yun.myuclass.com/upload/demo2.yun.myuclass.com/winshare/pagelogo/250617391.png"; + String PATH = "http://www.lgstatic.com/www/static/mycenter/modules/common/img/tou_42952f6.png"; + + URL url = new URL(PATH); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + //conn.setConnectTimeout(5000); + //conn.setRequestMethod("GET"); + //设置头部的参数,表示请求服务器资源的某一部分 + //conn.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos); + //设置了上面的头信息后,响应码为206代表请求资源成功,而不再是200 + int code = conn.getResponseCode(); + System.out.println(conn.getContentLength()); + if(code == 200){ + + InputStream is = conn.getInputStream(); + int hasRead = 0; + byte[] buf = new byte[conn.getContentLength()]; + System.out.println(buf.length); + //这里要注意新创建一个RandomAccessFile对象,而不能重复使用download方法中创建的 + RandomAccessFile raf = new RandomAccessFile(new File("/Users/dudy/Desktop/1.png"), "rw"); + //将写文件的指针指向下载的起始点 + raf.seek(0); + + while((hasRead = is.read(buf,0,conn.getContentLength())) > 0) { + System.out.println("hasRead = " + hasRead); + raf.write(buf, 0, hasRead); + } + is.close(); + raf.close(); + conn.disconnect(); + } + } + +} \ No newline at end of file diff --git a/group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/impl/ConnectionManagerImpl.java b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/impl/ConnectionManagerImpl.java new file mode 100644 index 0000000000..809f98d91b --- /dev/null +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/download/impl/ConnectionManagerImpl.java @@ -0,0 +1,25 @@ +package com.dudy.learn01.download.impl; + +import com.dudy.learn01.download.api.Connection; +import com.dudy.learn01.download.api.ConnectionException; +import com.dudy.learn01.download.api.ConnectionManager; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; + +public class ConnectionManagerImpl implements ConnectionManager { + + + private Connection connection = null; + + @Override + public Connection open(String url) throws ConnectionException, IOException { + + connection = new ConnectionImpl(url); + + return connection; + } + +} \ No newline at end of file diff --git a/group04/1796244932/learn01/src/main/java/com/dudy/learn01/juc/ThreadLocalTest.java b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/juc/ThreadLocalTest.java new file mode 100644 index 0000000000..e4239ae521 --- /dev/null +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/juc/ThreadLocalTest.java @@ -0,0 +1,64 @@ +package com.dudy.learn01.juc; + +/** + * Created by dudy on 2017/3/9. + * + * 4. ThreadLocal 这个类实现原理和用途,在哪里用到了 + * 每个ThreadLocal可以放一个线程级别的变量,但是它本身可以被多个线程共享变量,而且又可以达到线程安全的目的,且绝对线程安全 + * spring的事物管理Session, 连接池管理 Connection + * https://my.oschina.net/huangyong/blog/159725 + * 数据库事物的前提是: 必须是同一个连接 + */ +public class ThreadLocalTest { + + static class Resource{ + public static final ThreadLocal RESOURCE1 = new ThreadLocal(); + public static final ThreadLocal RESOURCE2 = new ThreadLocal(); + } + + static class A { + public void setOne(String str){ + Resource.RESOURCE1.set(str); + } + + public void setTwo(String str){ + Resource.RESOURCE2.set(str); + } + } + + static class B { + public void display(){ + System.out.println(Resource.RESOURCE1.get() + +":" + Resource.RESOURCE2.get()); + } + } + + public static void main(String[] args) { + + final A a = new A(); + final B b = new B(); + + for (int i = 0; i< 5 ;i++){ + + final String resource1 = "Thread_" + i; + final String resource2 = "value " + i; + + new Thread(new Runnable() { + @Override + public void run() { + try { + a.setOne(resource1); + a.setTwo(resource2); + b.display(); + }finally { + Resource.RESOURCE2.remove(); + Resource.RESOURCE1.remove(); + } + } + }).start(); + } + + } + + +} diff --git a/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/Struts.java b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/Struts.java index bbe8c108ca..c08ae7ae49 100644 --- a/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/Struts.java +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/Struts.java @@ -46,6 +46,7 @@ public static View runAction(String actionName, Map parameters) { for (Map.Entry entry : parameters.entrySet()) { System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue()); // 这里 只能传递object吧 + //actionClass.gett Method method = actionClass.getDeclaredMethod(methodNameconversion(entry.getKey()), String.class); method.setAccessible(true); method.invoke(base,entry.getValue()); diff --git a/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/Configuration.java b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/Configuration.java new file mode 100755 index 0000000000..987696acde --- /dev/null +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/Configuration.java @@ -0,0 +1,113 @@ +package com.dudy.learn01.litestruts.format; + +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) { + + 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 (JDOMException e) { + throw new ConfigurationException(e); + + } catch (IOException 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 action, String resultName) { + ActionConfig ac = this.actions.get(action); + 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/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/ConfigurationException.java b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/ConfigurationException.java new file mode 100755 index 0000000000..a584a7077d --- /dev/null +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/ConfigurationException.java @@ -0,0 +1,21 @@ +package com.dudy.learn01.litestruts.format; + +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/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/ConfigurationTest.java b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/ConfigurationTest.java new file mode 100755 index 0000000000..0f3c74e69a --- /dev/null +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/ConfigurationTest.java @@ -0,0 +1,50 @@ +package com.dudy.learn01.litestruts.format; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + + +public class ConfigurationTest { + + + Configuration cfg = new Configuration("struts.xml"); + + @Before + public void setUp() throws Exception { + } + + @After + 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"); + 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/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/LoginAction.java b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/LoginAction.java new file mode 100755 index 0000000000..3672d5a990 --- /dev/null +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/LoginAction.java @@ -0,0 +1,39 @@ +package com.dudy.learn01.litestruts.format; + +/** + * 这是一个用来展示登录的业务类, 其中的用户名和密码都是硬编码的。 + * @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/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/ReflectionUtil.java b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/ReflectionUtil.java new file mode 100755 index 0000000000..6ab3715730 --- /dev/null +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/ReflectionUtil.java @@ -0,0 +1,123 @@ +package com.dudy.learn01.litestruts.format; + +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) { + + return getMethods(clz,"set"); + + } + + 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 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 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; + } + + ////////////////////////Backup /////////////////////////////////// + + public static List getGetterMethods_V1(Class clz) { + + List methods = new ArrayList<>(); + + for(Method m : clz.getDeclaredMethods()){ + + if(m.getName().startsWith("get")){ + + methods.add(m); + + } + + } + + return methods; + } + + public static List getSetterMethods_V1(Class clz) { + + List methods = new ArrayList<>(); + + for(Method m : clz.getDeclaredMethods()){ + + if(m.getName().startsWith("set")){ + + methods.add(m); + + } + + } + + return methods; + + } + + + + +} diff --git a/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/ReflectionUtilTest.java b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/ReflectionUtilTest.java new file mode 100755 index 0000000000..174808fe62 --- /dev/null +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/ReflectionUtilTest.java @@ -0,0 +1,113 @@ +package com.dudy.learn01.litestruts.format; + +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.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + + +public class ReflectionUtilTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testGetSetterMethod() throws Exception { + + String name = "com.coderising.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 testSetParameters() throws Exception{ + + String name = "com.coderising.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 testGetGetterMethod() throws Exception{ + String name = "com.coderising.litestruts.LoginAction"; + Class clz = Class.forName(name); + List methods = ReflectionUtil.getGetterMethods(clz); + + Assert.assertEquals(3, methods.size()); + + List expectedNames = new ArrayList<>(); + expectedNames.add("getMessage"); + expectedNames.add("getName"); + expectedNames.add("getPassword"); + + Set acctualNames = new HashSet<>(); + for(Method m : methods){ + acctualNames.add(m.getName()); + } + + Assert.assertTrue(acctualNames.containsAll(expectedNames)); + } + + @Test + public void testGetParamters() throws Exception{ + String name = "com.coderising.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("messaage") ); + Assert.assertEquals("test", params.get("name") ); + Assert.assertEquals("123456", params.get("password") ); + } +} diff --git a/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/Struts.java b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/Struts.java new file mode 100755 index 0000000000..661fd96ebe --- /dev/null +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/Struts.java @@ -0,0 +1,68 @@ +package com.dudy.learn01.litestruts.format; + +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.getParamterMap(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/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/StrutsTest.java b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/StrutsTest.java new file mode 100755 index 0000000000..f3b177e54c --- /dev/null +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/StrutsTest.java @@ -0,0 +1,43 @@ +package com.dudy.learn01.litestruts.format; + +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/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/View.java b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/View.java new file mode 100755 index 0000000000..93c73bd359 --- /dev/null +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/View.java @@ -0,0 +1,23 @@ +package com.dudy.learn01.litestruts.format; + +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/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/struts.xml b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/struts.xml new file mode 100755 index 0000000000..4c6eeabbd4 --- /dev/null +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/litestruts/format/struts.xml @@ -0,0 +1,11 @@ + + + + /jsp/homepage.jsp + /jsp/showLogin.jsp + + + /jsp/welcome.jsp + /jsp/error.jsp + + \ No newline at end of file diff --git a/group04/1796244932/learn01/src/main/java/com/dudy/learn01/utils/ArraySortDemo.java b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/utils/ArraySortDemo.java index a26790375a..2763af6d55 100644 --- a/group04/1796244932/learn01/src/main/java/com/dudy/learn01/utils/ArraySortDemo.java +++ b/group04/1796244932/learn01/src/main/java/com/dudy/learn01/utils/ArraySortDemo.java @@ -28,9 +28,6 @@ public class ArraySortDemo { * 二分法查找 插入 * 和 直接插入排序不同的是: 查找 要插入的位置的方式不同 * 二分法前提是有序的** - * - * - * */ public static void dichotomySort(int src[]){ diff --git a/group04/1796244932/learn01/src/test/java/com/dudy/learn01/base/MyLinkedListTest.java b/group04/1796244932/learn01/src/test/java/com/dudy/learn01/base/MyLinkedListTest.java index c6ebb096ec..cce7a1c163 100644 --- a/group04/1796244932/learn01/src/test/java/com/dudy/learn01/base/MyLinkedListTest.java +++ b/group04/1796244932/learn01/src/test/java/com/dudy/learn01/base/MyLinkedListTest.java @@ -2,10 +2,69 @@ import java.util.LinkedList; +import org.junit.After; +import org.junit.Before; import org.junit.Test; public class MyLinkedListTest { + MyLinkedList list = new MyLinkedList(); + + @Before + public void init(){ + list.add(1); + list.add(2); + list.add(3); + list.add(4); + list.add(5); + } + + @After + public void after(){ + for(MyIterator it = list.iterator(); it.hasNext();){ + System.out.print(it.next() + " "); + } + } + + @Test + public void reverse() throws Exception { + list.reverse(); + } + + @Test + public void removeFirstHalf() throws Exception { + list.removeFirstHalf(); + } + + @Test + public void remove() throws Exception { + list.remove(0,2); + } + + @Test + public void getElements() throws Exception { + + } + + @Test + public void subtract() throws Exception { + + } + + @Test + public void removeDuplicateValues() throws Exception { + + } + + @Test + public void removeRange() throws Exception { + + } + + @Test + public void intersection() throws Exception { + + } @Test diff --git a/group04/1796244932/learn01/src/test/java/com/dudy/learn01/download/FileDownloaderTest.java b/group04/1796244932/learn01/src/test/java/com/dudy/learn01/download/FileDownloaderTest.java new file mode 100644 index 0000000000..fc427e2171 --- /dev/null +++ b/group04/1796244932/learn01/src/test/java/com/dudy/learn01/download/FileDownloaderTest.java @@ -0,0 +1,53 @@ +package com.dudy.learn01.download; + +import com.dudy.learn01.download.api.ConnectionManager; +import com.dudy.learn01.download.api.DownloadListener; +import com.dudy.learn01.download.impl.ConnectionManagerImpl; +import org.junit.Test; + + +import java.io.IOException; + + +public class FileDownloaderTest { + boolean downloadFinished = false; + + + + @Test + public void testDownload() throws IOException { + + //String url = "http://www.lgstatic.com/www/static/mycenter/modules/common/img/tou_42952f6.png"; + String url = "http://img.lanrentuku.com/img/allimg/1606/14665573271238.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("下载完成!"); + + + + } + +} \ No newline at end of file From 4cd003657ced885f137abd1479bbe4e79982203b Mon Sep 17 00:00:00 2001 From: gongxun Date: Mon, 13 Mar 2017 18:57:44 +0800 Subject: [PATCH 012/287] =?UTF-8?q?=E4=B8=AD=E9=80=94=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=E4=BF=9D=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group17/785396327/3.12/link/LinkedList.java | 202 ++++++++++++++++++ .../785396327/3.12/link/LinkedListTest.java | 35 +++ 2 files changed, 237 insertions(+) create mode 100644 group17/785396327/3.12/link/LinkedList.java create mode 100644 group17/785396327/3.12/link/LinkedListTest.java diff --git a/group17/785396327/3.12/link/LinkedList.java b/group17/785396327/3.12/link/LinkedList.java new file mode 100644 index 0000000000..1a47b812da --- /dev/null +++ b/group17/785396327/3.12/link/LinkedList.java @@ -0,0 +1,202 @@ +package link; + +import java.util.Iterator; + +/** + * Created by gongxun on 2017/3/13. + */ +public class LinkedList { + private Node head; + private int size = 0; + + public void add(T o) { + if (head == null) + head = new Node(null, o); + else + addLast(o); + } + + private Node getLast() { + Node last = null; + while (head.next != null) { + last = head; + head = head.next; + } + return last; + } + + private Node getNodeIndex(int index) { + if (index > size - 1) + throw new IndexOutOfBoundsException("size : " + size + ", index : " + index); + Node target = head; + for (int i = 0; i < size; i++) { + if (i == index) + return target; + target = target.next; + } + return null; + } + + public void add(int index, T o) { + Node node = getNodeIndex(index - 1); + Node nextNode = node.next; + Node newNode = new Node(node, o); + newNode.next = nextNode; + size++; + } + + public T get(int index) { + Node node = getNodeIndex(index); + return node.data; + } + + public T remove(int index) { + Node prev = getNodeIndex(index - 1); + Node now = getNodeIndex(index); + prev.next = now.next; + size--; + return now.data; + } + + public int size() { + return size; + } + + public void addFirst(T o) { + if (head != null) + head = new Node(null, o); + else { + Node newNode = new Node(head, o); + head = newNode; + } + size++; + } + + public void addLast(T o) { + Node last = getNodeIndex(size - 1); + last.next = new Node(null, o); + size++; + } + + public T removeFirst() { + Node removeNode = head; + if (head != null) + head = head.next; + size--; + return removeNode == null ? null : removeNode.data; + } + + public T removeLast() { + Node last = getNodeIndex(size - 1); + Node prev = getNodeIndex(size - 2); + prev.next = null; + size--; + return last.data; + } + + public Iterator iterator() { + return null; + } + + + private static class Node { + T data; + Node next; + + Node(Node next, T data) { + this.next = next; + this.data = data; + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + Node temp = head; + while (temp != null) { + sb.append(temp.data).append("-->"); + temp = temp.next; + } + return sb.toString(); + } + + /** + * 把该链表逆置 + * 例如链表为 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/group17/785396327/3.12/link/LinkedListTest.java b/group17/785396327/3.12/link/LinkedListTest.java new file mode 100644 index 0000000000..58a060b2c8 --- /dev/null +++ b/group17/785396327/3.12/link/LinkedListTest.java @@ -0,0 +1,35 @@ +package link; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Created by gongxun on 2017/3/13. + */ +public class LinkedListTest { + private LinkedList linkedList; + + @Before + public void startUp() { + linkedList = new LinkedList(); + } + + @After + public void tearDown() { + + } + + @Test + public void addFirst() { + linkedList.addFirst("1"); + System.out.println(linkedList); + } + + @Test + public void add() { + linkedList.add("1"); + linkedList.add("2"); + System.out.println(linkedList); + } +} From 23875d022746f311b385182896a0bf6c8642c8e0 Mon Sep 17 00:00:00 2001 From: xiaobo Date: Mon, 13 Mar 2017 21:31:21 +0800 Subject: [PATCH 013/287] =?UTF-8?q?=E7=AC=AC=E4=B8=89=E6=AC=A1=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit .. --- .../coderising/download/DownloadThread.java | 49 +++ .../coderising/download/FileDownloader.java | 112 +++++ .../download/FileDownloaderTest.java | 58 +++ .../coderising/download/api/Connection.java | 23 ++ .../download/api/ConnectionException.java | 10 + .../download/api/ConnectionManager.java | 10 + .../download/api/DownloadListener.java | 5 + .../download/impl/ConnectionImpl.java | 52 +++ .../download/impl/ConnectionManagerImpl.java | 37 ++ .../Study/src/com/linked/Iterator.java | 7 + .../Study/src/com/linked/LinkedList.java | 388 ++++++++++++++++++ .../349184132/Study/src/com/linked/List.java | 32 ++ 12 files changed, 783 insertions(+) create mode 100644 group04/349184132/Study/src/com/coderising/download/DownloadThread.java create mode 100644 group04/349184132/Study/src/com/coderising/download/FileDownloader.java create mode 100644 group04/349184132/Study/src/com/coderising/download/FileDownloaderTest.java create mode 100644 group04/349184132/Study/src/com/coderising/download/api/Connection.java create mode 100644 group04/349184132/Study/src/com/coderising/download/api/ConnectionException.java create mode 100644 group04/349184132/Study/src/com/coderising/download/api/ConnectionManager.java create mode 100644 group04/349184132/Study/src/com/coderising/download/api/DownloadListener.java create mode 100644 group04/349184132/Study/src/com/coderising/download/impl/ConnectionImpl.java create mode 100644 group04/349184132/Study/src/com/coderising/download/impl/ConnectionManagerImpl.java create mode 100644 group04/349184132/Study/src/com/linked/Iterator.java create mode 100644 group04/349184132/Study/src/com/linked/LinkedList.java create mode 100644 group04/349184132/Study/src/com/linked/List.java diff --git a/group04/349184132/Study/src/com/coderising/download/DownloadThread.java b/group04/349184132/Study/src/com/coderising/download/DownloadThread.java new file mode 100644 index 0000000000..2b806a7f44 --- /dev/null +++ b/group04/349184132/Study/src/com/coderising/download/DownloadThread.java @@ -0,0 +1,49 @@ +package com.coderising.download; + +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; + +import com.coderising.download.api.Connection; + +public class DownloadThread extends Thread { + Connection conn; + int startPos; + int endPos; + int threadId = 0; + CyclicBarrier barrier; + + public DownloadThread(CyclicBarrier barrier, Connection conn, int threadId, + int startPos, int endPos) { + this.barrier = barrier; + this.conn = conn; + this.threadId = threadId; + this.startPos = startPos; + this.endPos = endPos; + } + + public void run() { + RandomAccessFile raf = null; + try { + raf = new RandomAccessFile("yunpan.exe", "rwd"); + + raf.seek(startPos); + + byte[] buffer = conn.read(startPos, endPos); + + raf.write(buffer, 0, buffer.length); + raf.close(); + barrier.await(); + System.out.println("threadId" + threadId +"download success !"); + + } catch (IOException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (BrokenBarrierException e) { + e.printStackTrace(); + } + + } +} diff --git a/group04/349184132/Study/src/com/coderising/download/FileDownloader.java b/group04/349184132/Study/src/com/coderising/download/FileDownloader.java new file mode 100644 index 0000000000..281dafde96 --- /dev/null +++ b/group04/349184132/Study/src/com/coderising/download/FileDownloader.java @@ -0,0 +1,112 @@ +package com.coderising.download; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.net.URL; +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; + +public class FileDownloader { + + boolean isFinished = false; + + String url; + + DownloadListener listener; + + ConnectionManager cm; + + private static final int THREAD_NUM = 3; + + 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方法 + + // 下面的代码是示例代码, 也就是说只有一个线程, 你需要改造成多线程的。 + + CyclicBarrier barrier = new CyclicBarrier(THREAD_NUM,new Runnable(){ + + @Override + public void run() { + listener.notifyFinished(); + } + + }); + + Connection conn = null; + try { + conn = cm.open(url); + + int length = conn.getContentLength(); + System.out.println("----文件总长度---- :" + length); + RandomAccessFile raf = new RandomAccessFile("yunpan.exe","rwd"); + + raf.setLength(length); + + int block = length / THREAD_NUM; + + for(int threadId = 0; threadId < THREAD_NUM; threadId++){ + int startPos = (threadId) * block; + int endPos = (threadId + 1 ) * block -1; + if(threadId-1 == THREAD_NUM){ + endPos = length; + } + System.out.println("---threadId--- :" + threadId + + "---startIndex---" + startPos + + "---endIndex---" + endPos); + //开启 线程 + URL u = new URL(url); + new DownloadThread(barrier,cm.open(url),threadId,startPos,endPos).start(); + } + + + } catch (ConnectionException e) { + + e.printStackTrace(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException 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/group04/349184132/Study/src/com/coderising/download/FileDownloaderTest.java b/group04/349184132/Study/src/com/coderising/download/FileDownloaderTest.java new file mode 100644 index 0000000000..604712d2a9 --- /dev/null +++ b/group04/349184132/Study/src/com/coderising/download/FileDownloaderTest.java @@ -0,0 +1,58 @@ +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://down.360safe.com/yunpan/360wangpan_setup.exe"; + 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/group04/349184132/Study/src/com/coderising/download/api/Connection.java b/group04/349184132/Study/src/com/coderising/download/api/Connection.java new file mode 100644 index 0000000000..0957eaf7f4 --- /dev/null +++ b/group04/349184132/Study/src/com/coderising/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/group04/349184132/Study/src/com/coderising/download/api/ConnectionException.java b/group04/349184132/Study/src/com/coderising/download/api/ConnectionException.java new file mode 100644 index 0000000000..1599be1296 --- /dev/null +++ b/group04/349184132/Study/src/com/coderising/download/api/ConnectionException.java @@ -0,0 +1,10 @@ +package com.coderising.download.api; + +public class ConnectionException extends Exception { + + public ConnectionException(String string) { + // TODO 自动生成的构造函数存根 + } + + +} diff --git a/group04/349184132/Study/src/com/coderising/download/api/ConnectionManager.java b/group04/349184132/Study/src/com/coderising/download/api/ConnectionManager.java new file mode 100644 index 0000000000..ce045393b1 --- /dev/null +++ b/group04/349184132/Study/src/com/coderising/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/group04/349184132/Study/src/com/coderising/download/api/DownloadListener.java b/group04/349184132/Study/src/com/coderising/download/api/DownloadListener.java new file mode 100644 index 0000000000..bf9807b307 --- /dev/null +++ b/group04/349184132/Study/src/com/coderising/download/api/DownloadListener.java @@ -0,0 +1,5 @@ +package com.coderising.download.api; + +public interface DownloadListener { + public void notifyFinished(); +} diff --git a/group04/349184132/Study/src/com/coderising/download/impl/ConnectionImpl.java b/group04/349184132/Study/src/com/coderising/download/impl/ConnectionImpl.java new file mode 100644 index 0000000000..3ad903146b --- /dev/null +++ b/group04/349184132/Study/src/com/coderising/download/impl/ConnectionImpl.java @@ -0,0 +1,52 @@ +package com.coderising.download.impl; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; + +import com.coderising.download.api.Connection; + +public class ConnectionImpl implements Connection{ + private HttpURLConnection conn ; + public ConnectionImpl(HttpURLConnection conn) { + this.conn = conn; + } + @Override + public byte[] read(int startPos, int endPos) throws IOException { + conn.setRequestMethod("GET"); + conn.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos); + conn.setConnectTimeout(5000); + + InputStream is = conn.getInputStream(); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + int length = 0; + byte[] buffer = new byte[1024]; + while(-1 != ( length = is.read(buffer))){ + bos.write(buffer,0,length); + } + bos.flush(); + is.close(); + bos.close(); + + + return bos.toByteArray(); + } + + @Override + public int getContentLength() { + + return conn.getContentLength(); + } + + @Override + public void close() { + if(conn!=null){ + conn = null; + } + } + +} diff --git a/group04/349184132/Study/src/com/coderising/download/impl/ConnectionManagerImpl.java b/group04/349184132/Study/src/com/coderising/download/impl/ConnectionManagerImpl.java new file mode 100644 index 0000000000..9132787cf8 --- /dev/null +++ b/group04/349184132/Study/src/com/coderising/download/impl/ConnectionManagerImpl.java @@ -0,0 +1,37 @@ +package com.coderising.download.impl; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +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 { + + URL u; + HttpURLConnection hc ; + try { + u = new URL(url); + hc = (HttpURLConnection) u.openConnection(); + Connection conn = new ConnectionImpl(hc);; + return conn; + } catch (MalformedURLException e) { + e.printStackTrace(); + + } catch (IOException e) { + e.printStackTrace(); + } + return null; + + + + + + } + +} diff --git a/group04/349184132/Study/src/com/linked/Iterator.java b/group04/349184132/Study/src/com/linked/Iterator.java new file mode 100644 index 0000000000..b2397b9aa7 --- /dev/null +++ b/group04/349184132/Study/src/com/linked/Iterator.java @@ -0,0 +1,7 @@ +package com.linked; + +public interface Iterator { + public boolean hasNext(); + public Object next(); + +} diff --git a/group04/349184132/Study/src/com/linked/LinkedList.java b/group04/349184132/Study/src/com/linked/LinkedList.java new file mode 100644 index 0000000000..44aba236b4 --- /dev/null +++ b/group04/349184132/Study/src/com/linked/LinkedList.java @@ -0,0 +1,388 @@ +package com.linked; + +import java.util.Objects; + + + +public class LinkedList implements List { + + private Node head; + + private int size = 0; + + public LinkedList(){ + this.head = new Node(null,null); + } + + public boolean add(T o){ + + if(head.next == null){ + Node element = new Node(o,null); + head.next = element; + size++; + return true; + } + + Node current = head.next; + while(current != null){ + if(current.next==null){ + Node element = new Node(o,null); + current.next = element; + size++; + return true; + } + current = current.next; + } + + return false; + } + + + private void rangeCheck(int index) { + if (index < -1 || index > size - 1) + throw new IndexOutOfBoundsException(" index "); + } + public boolean add(int index , T o){ + rangeCheck(index); + + Node node = getNode(index); + Node pre = getNode(index-1); + Node newNode = new Node(o,node); + pre.next = newNode; + size++; + return true; + } + + + private Node getNode(int index){ + rangeCheck(index); + Node current = head.next; + int count = 0; + while(current!=null){ + if(count==index){ + return current; + } + count++; + current = current.next; + } + return null; + } + + public T get(int index){ + Node node = getNode(index); + return (T)node.data; + } + public T remove(int index){ + rangeCheck(index); + + Node pre = getNode(index-1); + Node cur = getNode(index); + Node next = cur.next; + pre.next = next; + cur.next = null; + size--; + return (T)cur.data; + } + + + public T remove(T o) { + int index = 0; + for (Node x = head.next; x != null; x = x.next) { + if (Objects.deepEquals(x.data, o)) { + return remove(index); + } + index++; + } + size--; + + return null; + } + + @Override + public T set(int index, T element) { + Node node = getNode(index); + node.data = element; + + return (T)node.data; + } + + @Override + public boolean contains(Object o) { + + return indexOf(o)!=-1; + } + + @Override + public int indexOf(Object o) { + int index = 0; + + for (Node x = head.next; x != null; x = x.next) { + if (Objects.deepEquals(x.data, o)) + return index; + index++; + } + return -1; + } + + @Override + public Object[] toArray() { + Object[] result = new Object[size]; + int i = 0; + for(Node x = head.next; x != null; x = x.next){ + result[i++] = x.data; + } + return null; + } + + @Override + public void clear() { + for(Node cur = head.next;cur!=null;cur = cur.next){ + Node x = cur; + x.data = null; + x.next = null; + } + head = null; + size = 0; + } + + + public int size(){ + return size; + } + public boolean isEmpty() { + return size == 0; + } + public void addFirst(Object o){ + Node newFirst = new Node(o,null); + Node oldFirst = head.next; + head.next = newFirst; + newFirst.next = oldFirst; + size++; + } + public void addLast(Object o){ + Node last = getNode(size-1); + Node newLast = new Node(o,null); + last.next = newLast; + size++; + } + public T removeFirst(){ + Node oldFirst = head.next; + Node nextNode = oldFirst.next; + head.next = nextNode; + size--; + return (T)oldFirst; + } + public T removeLast(){ + Node x = getNode(size-2);//倒数第二个结点 + Node last = x.next; + x.next = null; + size--; + return (T)last; + } + public Iterator iterator(){ + return new LinkedListIterator(); + } + + private class LinkedListIterator implements Iterator { + int pos = 0; + + @Override + public boolean hasNext() { + return pos < size; + } + + @Override + public Object next() { + if (pos > size) + throw new IllegalArgumentException(); + return get(pos++); + } + } + + + + private static class Node{ + Object data; + Node next; + private Node(Object data, Node next) { + this.data = data; + this.next = next; + + } + } + + /** + * 把该链表逆置 + * 例如链表为 3->7->10 , 逆置后变为 10->7->3 + */ + public Node reverseFor(Node head){ + if(head==null){ + return null; + } + Node pre = null; + Node curr = head; + Node next = head.next; + while(curr.next!=null){ + + head.next = pre; + pre = curr; + curr = curr.next; + next = next.next; + head = curr; + } + pre = null; + curr = null; + return head; + } + /** + * 递归写法 + * @param node + * @return + */ + public Node reverseRecursion(Node current){ + if(current == null || current.next == null){ + return current; + } + Node nextNode = current.next; + current = null; + Node reverseNode = reverseRecursion(current.next); + nextNode.next = current; + + + return reverseNode; + + } + + /** + * 删除一个单链表的前半部分 + * 例如:list = 2->5->7->8 , 删除以后的值为 7->8 + * 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10 + + */ + public void removeFirstHalf(){ + int delectLength = size/2; + for(int i=0;isize-length){ + throw new IllegalArgumentException(i +" or "+length +" error"); + } + for(int j=i;j101->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){ + throw new NullPointerException("List is null"); + } + int[] result = new int[list.size()]; + int index = 0; + for(Iterator iter = list.iterator();iter.hasNext();){ + int LinkIndex = (int)iter.next(); + result[index] = (int)get(LinkIndex); + } + return result; + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 从当前链表中中删除在list中出现的元素 + + * @param list + */ + + public void subtract(LinkedList list){ + if(list == null){ + throw new NullPointerException("List is null"); + } + int index = 0; + for(Node cur = head.next ; cur !=null ; cur = cur.next){ + for(Node newList = list.head.next ; newList != null; newList = newList.next ){ + if(Objects.deepEquals(cur.data, newList.data)){ + remove(index); + } + } + index++; + } + } + + /** + * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) + */ + public void removeDuplicateValues(){ + for(Node current=head.next;current!=null;current=current.next){ + Node nextNode = current.next; + + if(current.data.equals(nextNode.data)){ + Node nextNodeNext = nextNode.next; + if(nextNodeNext==null){ + current.next = null; + }else{ + current.next = nextNodeNext; + nextNode.next = null; + } + } + } + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 试写一高效的算法,删除表中所有值大于min且小于max的元素(若表中存在这样的元素) + * @param min + * @param max + */ + public void removeRange(int min, int max) { + if (min + max > size && min == max) { + throw new IndexOutOfBoundsException("Arguement is Illegal"); + } + int index = 0; + for (Node curr = head.next; curr != null; curr = curr.next) { + if(((int)curr.data>min) && ((int)curr.data { + public boolean add(T o); + + public boolean add(int index, T o); + + public T get(int index); + + T set(int index, T element); + + public T remove(int index); + + public T remove(T o); + + public int size(); + + public boolean isEmpty(); + + public Iterator iterator(); + + public boolean contains(Object o); + + int indexOf(Object o); + + + Object[] toArray(); + + void clear(); + +} From 4849ef4ebe57a037dab01cfc249a047b4211ae09 Mon Sep 17 00:00:00 2001 From: gongxun Date: Mon, 13 Mar 2017 23:26:05 +0800 Subject: [PATCH 014/287] =?UTF-8?q?=E4=BA=8C=E5=88=86=E4=B9=8B=E4=B8=80?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E7=BB=93=E6=9E=84=E5=92=8C=E7=AE=97=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group17/785396327/3.12/link/LinkedList.java | 46 +++++++++---- .../785396327/3.12/link/LinkedListTest.java | 66 +++++++++++++++++++ 2 files changed, 99 insertions(+), 13 deletions(-) diff --git a/group17/785396327/3.12/link/LinkedList.java b/group17/785396327/3.12/link/LinkedList.java index 1a47b812da..43083aea32 100644 --- a/group17/785396327/3.12/link/LinkedList.java +++ b/group17/785396327/3.12/link/LinkedList.java @@ -10,9 +10,10 @@ public class LinkedList { private int size = 0; public void add(T o) { - if (head == null) + if (head == null) { head = new Node(null, o); - else + size++; + } else addLast(o); } @@ -40,8 +41,7 @@ private Node getNodeIndex(int index) { public void add(int index, T o) { Node node = getNodeIndex(index - 1); Node nextNode = node.next; - Node newNode = new Node(node, o); - newNode.next = nextNode; + node.next = new Node(nextNode, o); size++; } @@ -73,9 +73,7 @@ public void addFirst(T o) { } public void addLast(T o) { - Node last = getNodeIndex(size - 1); - last.next = new Node(null, o); - size++; + add(size, o); } public T removeFirst() { @@ -117,7 +115,7 @@ public String toString() { sb.append(temp.data).append("-->"); temp = temp.next; } - return sb.toString(); + return sb.toString().substring(0, sb.lastIndexOf("-->")); } /** @@ -125,7 +123,15 @@ public String toString() { * 例如链表为 3->7->10 , 逆置后变为 10->7->3 */ public void reverse() { - + Node cur = null; + Node prev = null; + while (head != null) { + cur = head; + head = head.next; + cur.next = prev; + prev = cur; + } + head = cur; } /** @@ -134,7 +140,7 @@ public void reverse() { * 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10 */ public void removeFirstHalf() { - + head = getNodeIndex(size / 2); } /** @@ -144,7 +150,15 @@ public void removeFirstHalf() { * @param length */ public void remove(int i, int length) { - + if (size <= (i + length) || i < 0) + throw new IndexOutOfBoundsException("size : " + size + ", i + length : " + (i + length)); + Node rightNode = getNodeIndex(i + length); + if (i == 0) + head = rightNode; + else { + Node leftNode = getNodeIndex(i - 1); + leftNode.next = rightNode; + } } /** @@ -156,8 +170,14 @@ public void remove(int i, int length) { * * @param list */ - public static int[] getElements(LinkedList list) { - return null; + public Object[] getElements(LinkedList list) { + Object[] result = new Object[list.size]; + if (list != null) { + for (int i = 0; i < list.size; i++) { + result[i] = get(list.get(i)); + } + } + return result; } /** diff --git a/group17/785396327/3.12/link/LinkedListTest.java b/group17/785396327/3.12/link/LinkedListTest.java index 58a060b2c8..6699c5531a 100644 --- a/group17/785396327/3.12/link/LinkedListTest.java +++ b/group17/785396327/3.12/link/LinkedListTest.java @@ -4,6 +4,8 @@ import org.junit.Before; import org.junit.Test; +import java.util.Arrays; + /** * Created by gongxun on 2017/3/13. */ @@ -13,6 +15,10 @@ public class LinkedListTest { @Before public void startUp() { linkedList = new LinkedList(); + linkedList.add("1"); + linkedList.add("2"); + linkedList.add("3"); + linkedList.add(1, "0"); } @After @@ -32,4 +38,64 @@ public void add() { linkedList.add("2"); System.out.println(linkedList); } + + @Test + public void add2() { + linkedList.add("1"); + linkedList.add("2"); + linkedList.add("3"); + linkedList.add(1, "0"); + System.out.println(linkedList); + } + + @Test + public void addLast() { + linkedList.add("1"); + linkedList.addLast("2"); + System.out.println(linkedList); + } + + @Test + public void get() { + String value = linkedList.get(2); + System.out.println(value); + } + + @Test + public void remove() { + String removeValue = linkedList.remove(3); + System.out.println(removeValue); + } + + @Test + public void reverse() { + System.out.println(linkedList); + linkedList.reverse(); + System.out.println(linkedList); + } + + @Test + public void removeFirstHalf() { + System.out.println(linkedList); + linkedList.removeFirstHalf(); + System.out.println(linkedList); + } + + @Test + public void removeByRange() { + System.out.println(linkedList); + linkedList.remove(0, 2); + System.out.println(linkedList); + } + + @Test + public void getElements() { + System.out.println(linkedList); + LinkedList indexList = new LinkedList(); + indexList.add(0); + indexList.add(2); + indexList.add(3); + Object[] elements = linkedList.getElements(indexList); + System.out.println(Arrays.toString(elements)); + } } From f43e9c1147ccd1fc658c19a237d0443417f8f555 Mon Sep 17 00:00:00 2001 From: qilei Date: Tue, 14 Mar 2017 11:15:07 +0800 Subject: [PATCH 015/287] refactor ArrayList --- .../main/java/com/coding/basic/ArrayList.java | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/group04/916758663/learn01/src/main/java/com/coding/basic/ArrayList.java b/group04/916758663/learn01/src/main/java/com/coding/basic/ArrayList.java index 0c9e702951..b4ac9cf2b9 100644 --- a/group04/916758663/learn01/src/main/java/com/coding/basic/ArrayList.java +++ b/group04/916758663/learn01/src/main/java/com/coding/basic/ArrayList.java @@ -9,23 +9,30 @@ public class ArrayList implements List { private Object[] elementData = new Object[3]; public void add(Object o){ - add(size,o); + ensureCapacity(size + 1); + elementData[size] = o; + size++; } + public void add(int index, Object o){ if (index > size){ throw new IndexOutOfBoundsException(); } + // 扩容 - if (size == elementData.length || index + 1 > elementData.length) { - int newLength = index + 1 > size * 2 ? index + 1 :size * 2; - elementData = Arrays.copyOf(elementData, newLength); - } + ensureCapacity(size + 1); + // 移动元素 System.arraycopy(elementData,index,elementData,index + 1 ,size-index); elementData[index] = o; size ++ ; } - + + private void ensureCapacity(int minCapacity) { + int newLength = Math.max(minCapacity, size * 2); + elementData = Arrays.copyOf(elementData, newLength); + } + public Object get(int index){ checkIndex(index); return elementData[index]; @@ -55,17 +62,17 @@ public Iterator iterator(){ private class ArrayListIterator implements Iterator { - private int currentIndex = 0; + private int position = 0; @Override public boolean hasNext() { - return currentIndex < size(); + return position < size(); } @Override public Object next() { - Object o = get(currentIndex); - currentIndex ++ ; + Object o = get(position); + position++ ; return o; } } From 3c81c87340530106e33c709ddac59c097b83b0c6 Mon Sep 17 00:00:00 2001 From: gongxun Date: Tue, 14 Mar 2017 18:55:41 +0800 Subject: [PATCH 016/287] =?UTF-8?q?=E4=B8=AD=E9=80=94=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=E4=BF=9D=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group17/785396327/3.12/link/LinkedList.java | 39 +++++++++++++++++-- .../785396327/3.12/link/LinkedListTest.java | 16 +++++--- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/group17/785396327/3.12/link/LinkedList.java b/group17/785396327/3.12/link/LinkedList.java index 43083aea32..7947519f80 100644 --- a/group17/785396327/3.12/link/LinkedList.java +++ b/group17/785396327/3.12/link/LinkedList.java @@ -1,5 +1,6 @@ package link; +import java.util.Arrays; import java.util.Iterator; /** @@ -96,6 +97,29 @@ public Iterator iterator() { return null; } + private int getIndex(Node node) { + Node temp = head; + int index = 0; + while (temp != null) { + if (temp == node) { + return index; + } + } + return -1; + } + + private int getIndexByData(T data) { + Node temp = head; + int index = 0; + while (temp != null) { + if ((data == null && temp.data == null) || temp.data.equals(data)) + return index; + index++; + temp = temp.next; + } + return -1; + } + private static class Node { T data; @@ -105,6 +129,7 @@ private static class Node { this.next = next; this.data = data; } + } @Override @@ -171,7 +196,7 @@ public void remove(int i, int length) { * @param list */ public Object[] getElements(LinkedList list) { - Object[] result = new Object[list.size]; + Object[] result = new Object[list.size]; if (list != null) { for (int i = 0; i < list.size; i++) { result[i] = get(list.get(i)); @@ -187,8 +212,16 @@ public Object[] getElements(LinkedList list) { * @param list */ - public void subtract(LinkedList list) { - + public void subtract(LinkedList list) { + if (list != null && list.size > 0) { + for (int i = 0; i < list.size; i++) { + int index = getIndexByData(list.get(i)); + if (index != -1) + remove(index); + else + throw new RuntimeException("wrong element of removed list"); + } + } } /** diff --git a/group17/785396327/3.12/link/LinkedListTest.java b/group17/785396327/3.12/link/LinkedListTest.java index 6699c5531a..923623f458 100644 --- a/group17/785396327/3.12/link/LinkedListTest.java +++ b/group17/785396327/3.12/link/LinkedListTest.java @@ -18,7 +18,7 @@ public void startUp() { linkedList.add("1"); linkedList.add("2"); linkedList.add("3"); - linkedList.add(1, "0"); + System.out.println(linkedList); } @After @@ -69,28 +69,24 @@ public void remove() { @Test public void reverse() { - System.out.println(linkedList); linkedList.reverse(); System.out.println(linkedList); } @Test public void removeFirstHalf() { - System.out.println(linkedList); linkedList.removeFirstHalf(); System.out.println(linkedList); } @Test public void removeByRange() { - System.out.println(linkedList); linkedList.remove(0, 2); System.out.println(linkedList); } @Test public void getElements() { - System.out.println(linkedList); LinkedList indexList = new LinkedList(); indexList.add(0); indexList.add(2); @@ -98,4 +94,14 @@ public void getElements() { Object[] elements = linkedList.getElements(indexList); System.out.println(Arrays.toString(elements)); } + + @Test + public void subtract() { + LinkedList indexList = new LinkedList(); + indexList.add("2"); + indexList.add("0"); + linkedList.subtract(indexList); + System.out.println(linkedList); + } + } From 8ca1d722d2630743cf20ad6d5322a043366ab1f2 Mon Sep 17 00:00:00 2001 From: gongxun Date: Tue, 14 Mar 2017 23:30:20 +0800 Subject: [PATCH 017/287] =?UTF-8?q?=E4=B8=AD=E9=80=94=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group17/785396327/3.12/link/LinkedList.java | 18 +++++++++++++++--- .../785396327/3.12/link/LinkedListTest.java | 11 +++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/group17/785396327/3.12/link/LinkedList.java b/group17/785396327/3.12/link/LinkedList.java index 7947519f80..e9925e8ae8 100644 --- a/group17/785396327/3.12/link/LinkedList.java +++ b/group17/785396327/3.12/link/LinkedList.java @@ -1,7 +1,9 @@ package link; -import java.util.Arrays; -import java.util.Iterator; +import list.ArrayList; +import list.List; + +import java.util.*; /** * Created by gongxun on 2017/3/13. @@ -229,7 +231,17 @@ public void subtract(LinkedList list) { * 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) */ public void removeDuplicateValues() { - + Node temp = head; + List list = new ArrayList(); + int index = 0; + while (temp != null) { + if (list.contains(temp.data)) + remove(index--); + else + list.add(temp.data); + temp = temp.next; + index++; + } } /** diff --git a/group17/785396327/3.12/link/LinkedListTest.java b/group17/785396327/3.12/link/LinkedListTest.java index 923623f458..83df19d4fa 100644 --- a/group17/785396327/3.12/link/LinkedListTest.java +++ b/group17/785396327/3.12/link/LinkedListTest.java @@ -104,4 +104,15 @@ public void subtract() { System.out.println(linkedList); } + @Test + public void removeDuplicateValues() { + linkedList.add("3"); + linkedList.add("7"); + linkedList.add("0"); + linkedList.add("1"); + System.out.println(linkedList); + linkedList.removeDuplicateValues(); + System.out.println(linkedList); + } + } From 4f4777944256a51396bafbb0ea3c1b021144d8e6 Mon Sep 17 00:00:00 2001 From: Administrator Date: Wed, 15 Mar 2017 00:24:35 +0800 Subject: [PATCH 018/287] =?UTF-8?q?add=20=E5=A4=9A=E7=BA=BF=E7=A8=8B?= =?UTF-8?q?=E4=B8=8B=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coding/three/download/DownloadThread.java | 60 ++++++++++++++ .../coding/three/download/FileDownloader.java | 81 +++++++++++++++++++ .../coding/three/download/api/Connection.java | 23 ++++++ .../download/api/ConnectionException.java | 12 +++ .../three/download/api/ConnectionManager.java | 10 +++ .../three/download/api/DownloadListener.java | 5 ++ .../three/download/impl/ConnectionImpl.java | 67 +++++++++++++++ .../download/impl/ConnectionManagerImpl.java | 18 +++++ .../three/download/FileDownloaderTest.java | 60 ++++++++++++++ 9 files changed, 336 insertions(+) create mode 100644 group04/498654356/one/src/org/coding/three/download/DownloadThread.java create mode 100644 group04/498654356/one/src/org/coding/three/download/FileDownloader.java create mode 100644 group04/498654356/one/src/org/coding/three/download/api/Connection.java create mode 100644 group04/498654356/one/src/org/coding/three/download/api/ConnectionException.java create mode 100644 group04/498654356/one/src/org/coding/three/download/api/ConnectionManager.java create mode 100644 group04/498654356/one/src/org/coding/three/download/api/DownloadListener.java create mode 100644 group04/498654356/one/src/org/coding/three/download/impl/ConnectionImpl.java create mode 100644 group04/498654356/one/src/org/coding/three/download/impl/ConnectionManagerImpl.java create mode 100644 group04/498654356/one/test/org/coding/three/download/FileDownloaderTest.java diff --git a/group04/498654356/one/src/org/coding/three/download/DownloadThread.java b/group04/498654356/one/src/org/coding/three/download/DownloadThread.java new file mode 100644 index 0000000000..2675e31851 --- /dev/null +++ b/group04/498654356/one/src/org/coding/three/download/DownloadThread.java @@ -0,0 +1,60 @@ +package org.coding.three.download; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.Arrays; + +import org.coding.three.download.api.Connection; + +public class DownloadThread extends Thread{ + + String filePath = "D:\\a.jpg"; + + FileDownloader fileDownloader; + Connection conn; + int startPos; + int endPos; + + public DownloadThread(FileDownloader fileDownloader, Connection conn, int startPos, int endPos){ + this.fileDownloader = fileDownloader; + this.conn = conn; + this.startPos = startPos; + this.endPos = endPos; + } + public void run(){ + RandomAccessFile accessFile = null; + try { + synchronized (DownloadThread.class) { + File file = new File(filePath); + if(!file.exists()) { + file.createNewFile(); + accessFile = new RandomAccessFile(file, "rw"); + accessFile.setLength(conn.getContentLength()); + } + byte[] b = conn.read(startPos, endPos); + accessFile = new RandomAccessFile(new File(filePath), "rw"); + System.out.println(Thread.currentThread().getName() + " --> 读取数据 " + b.length ); + accessFile.seek(startPos); + accessFile.write(b); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + fileDownloader.addFinshCount(); + if(fileDownloader.isFinsh()) { + fileDownloader.listener.notifyFinished(); + } + if(accessFile != null) { + try { + accessFile.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if(conn != null) { + conn.close(); + } + } + } +} diff --git a/group04/498654356/one/src/org/coding/three/download/FileDownloader.java b/group04/498654356/one/src/org/coding/three/download/FileDownloader.java new file mode 100644 index 0000000000..4cfd75f1da --- /dev/null +++ b/group04/498654356/one/src/org/coding/three/download/FileDownloader.java @@ -0,0 +1,81 @@ +package org.coding.three.download; + +import org.coding.three.download.api.Connection; +import org.coding.three.download.api.ConnectionException; +import org.coding.three.download.api.ConnectionManager; +import org.coding.three.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(); + // TODO + int size = length / THREAD_COUNT; + for(int i = 0; i < THREAD_COUNT; i++) { + int start = i * size; + int end = start + size - 1; + if(i == THREAD_COUNT - 1) { + end += length % THREAD_COUNT; + } + new DownloadThread(this, conn, start, end).start(); + } + } catch (ConnectionException e) { + e.printStackTrace(); + } + + } + + public void setListener(DownloadListener listener) { + this.listener = listener; + } + public void setConnectionManager(ConnectionManager ucm){ + this.cm = ucm; + } + + public DownloadListener getListener(){ + return this.listener; + } + + + private static final int THREAD_COUNT = 3; + private int finshCount; + + public synchronized void addFinshCount(){ + finshCount++; + } + + public synchronized boolean isFinsh() { + return THREAD_COUNT == finshCount; + } + + +} + \ No newline at end of file diff --git a/group04/498654356/one/src/org/coding/three/download/api/Connection.java b/group04/498654356/one/src/org/coding/three/download/api/Connection.java new file mode 100644 index 0000000000..6c3a0e66d6 --- /dev/null +++ b/group04/498654356/one/src/org/coding/three/download/api/Connection.java @@ -0,0 +1,23 @@ +package org.coding.three.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/group04/498654356/one/src/org/coding/three/download/api/ConnectionException.java b/group04/498654356/one/src/org/coding/three/download/api/ConnectionException.java new file mode 100644 index 0000000000..7393d8824b --- /dev/null +++ b/group04/498654356/one/src/org/coding/three/download/api/ConnectionException.java @@ -0,0 +1,12 @@ +package org.coding.three.download.api; + +@SuppressWarnings("serial") +public class ConnectionException extends Exception { + + public ConnectionException() {} + + public ConnectionException(String msg) { + super(msg); + } + +} diff --git a/group04/498654356/one/src/org/coding/three/download/api/ConnectionManager.java b/group04/498654356/one/src/org/coding/three/download/api/ConnectionManager.java new file mode 100644 index 0000000000..c4bc02e65b --- /dev/null +++ b/group04/498654356/one/src/org/coding/three/download/api/ConnectionManager.java @@ -0,0 +1,10 @@ +package org.coding.three.download.api; + +public interface ConnectionManager { + /** + * 给定一个url , 打开一个连接 + * @param url + * @return + */ + public Connection open(String url) throws ConnectionException; +} diff --git a/group04/498654356/one/src/org/coding/three/download/api/DownloadListener.java b/group04/498654356/one/src/org/coding/three/download/api/DownloadListener.java new file mode 100644 index 0000000000..0d9dc0974d --- /dev/null +++ b/group04/498654356/one/src/org/coding/three/download/api/DownloadListener.java @@ -0,0 +1,5 @@ +package org.coding.three.download.api; + +public interface DownloadListener { + public void notifyFinished(); +} diff --git a/group04/498654356/one/src/org/coding/three/download/impl/ConnectionImpl.java b/group04/498654356/one/src/org/coding/three/download/impl/ConnectionImpl.java new file mode 100644 index 0000000000..afd71c78ee --- /dev/null +++ b/group04/498654356/one/src/org/coding/three/download/impl/ConnectionImpl.java @@ -0,0 +1,67 @@ +package org.coding.three.download.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Arrays; + +import org.coding.three.download.api.Connection; + + +public class ConnectionImpl implements Connection{ + private String url; + private int length; + private InputStream inputStream; + public ConnectionImpl (String url) throws Exception{ + super(); + this.url = url; + URL u = new URL(url); + int length = u.openConnection().getContentLength(); + this.length = length; + } + + @Override + public byte[] read(int startPos, int endPos) throws IOException { + URL u = new URL(this.url); + HttpURLConnection urlConnection = (HttpURLConnection) u.openConnection(); + urlConnection.setRequestMethod("GET"); + urlConnection.setConnectTimeout(5000); + // *** + urlConnection.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos); + System.out.println(Thread.currentThread() + "---> startPos = " + startPos + ", endPos = " + endPos ); + int size = endPos - startPos + 1; + byte[] data = new byte[size * 2]; + InputStream inputStream = urlConnection.getInputStream(); + this.inputStream = inputStream; + // *** 从 0 开始 + byte[] b = new byte[1024]; + int length = 0; + int count = 0; + int dataLength = 0; + while((length = inputStream.read(b)) != -1) { + int destPos = count * 1024; + for(int i = 0; i < length; i++) { + data[destPos + i] = b[i]; + dataLength++; + } + count++; + } + return Arrays.copyOf(data, dataLength); + } + + @Override + public int getContentLength() { + return this.length; + } + + @Override + public void close() { + try { + this.inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + +} diff --git a/group04/498654356/one/src/org/coding/three/download/impl/ConnectionManagerImpl.java b/group04/498654356/one/src/org/coding/three/download/impl/ConnectionManagerImpl.java new file mode 100644 index 0000000000..d8f19033d3 --- /dev/null +++ b/group04/498654356/one/src/org/coding/three/download/impl/ConnectionManagerImpl.java @@ -0,0 +1,18 @@ +package org.coding.three.download.impl; + +import org.coding.three.download.api.Connection; +import org.coding.three.download.api.ConnectionException; +import org.coding.three.download.api.ConnectionManager; + +public class ConnectionManagerImpl implements ConnectionManager { + + @Override + public Connection open(String url) throws ConnectionException { + try { + return new ConnectionImpl(url); + } catch (Exception e) { + throw new ConnectionException(e.getMessage()); + } + } + +} diff --git a/group04/498654356/one/test/org/coding/three/download/FileDownloaderTest.java b/group04/498654356/one/test/org/coding/three/download/FileDownloaderTest.java new file mode 100644 index 0000000000..e384154293 --- /dev/null +++ b/group04/498654356/one/test/org/coding/three/download/FileDownloaderTest.java @@ -0,0 +1,60 @@ +package org.coding.three.download; + +import org.coding.three.download.api.ConnectionManager; +import org.coding.three.download.api.DownloadListener; +import org.coding.three.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://7xq43s.com1.z0.glb.clouddn.com/yunanding-6.jpg"; + String url = "http://orig04.deviantart.net/93d4/f/2007/314/9/5/audrey_tautou_by_shimoda7.jpg"; +// String url = "http://www.yinwang.org/blog-cn/2016/11/17/all-about-hillary"; + + 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("下载完成!"); + + + + } + +} From 052489667cd62c8cc1505d519a8b5c267b19b344 Mon Sep 17 00:00:00 2001 From: sulei Date: Wed, 15 Mar 2017 19:28:29 +0800 Subject: [PATCH 019/287] thirdhomework --- .../1020483199/1020483199Learning/.classpath | 2 +- liuxin/.project | 2 +- .../org.eclipse.core.resources.prefs | 2 + .../coderising/download/DownloadThread.java | 33 ++++++--- .../coderising/download/FileDownloader.java | 69 +++++++++++++++++-- .../download/FileDownloaderTest.java | 2 +- .../download/api/ConnectionException.java | 8 +++ .../download/api/DownloadListener.java | 1 + .../download/impl/ConnectionImpl.java | 45 ++++++++++-- .../download/impl/ConnectionManagerImpl.java | 13 +++- liuxin/src/com/coding/basic/LinkedList.java | 34 ++++++--- 11 files changed, 179 insertions(+), 32 deletions(-) create mode 100644 liuxin/.settings/org.eclipse.core.resources.prefs diff --git a/group04/1020483199/1020483199Learning/.classpath b/group04/1020483199/1020483199Learning/.classpath index 3e0fb272a8..04cc82dc42 100644 --- a/group04/1020483199/1020483199Learning/.classpath +++ b/group04/1020483199/1020483199Learning/.classpath @@ -1,7 +1,7 @@ - + diff --git a/liuxin/.project b/liuxin/.project index b6d8ce6204..8a1c96cafa 100644 --- a/liuxin/.project +++ b/liuxin/.project @@ -1,6 +1,6 @@ - coding2017 + ThirdHomework diff --git a/liuxin/.settings/org.eclipse.core.resources.prefs b/liuxin/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000000..99f26c0203 --- /dev/null +++ b/liuxin/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/liuxin/src/com/coderising/download/DownloadThread.java b/liuxin/src/com/coderising/download/DownloadThread.java index 1456314140..21b42db267 100644 --- a/liuxin/src/com/coderising/download/DownloadThread.java +++ b/liuxin/src/com/coderising/download/DownloadThread.java @@ -1,20 +1,37 @@ package com.coderising.download; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; + import com.coderising.download.api.Connection; public class DownloadThread extends Thread{ + + + private Connection conn; + private int startPos; + private int endPos; + private String filePath; - Connection conn; - int startPos; - int endPos; - - public DownloadThread( Connection conn, int startPos, int endPos){ - - this.conn = conn; + public DownloadThread(Connection conn, int startPos, int endPos,String filePath){ + this.conn = conn; this.startPos = startPos; this.endPos = endPos; + this.filePath = filePath; } public void run(){ - + try { + System.out.println("线程" + this.getName() + "开始下载. startPos:" + startPos + "; endPos:" + endPos); + byte[] buffer = conn.read(startPos, endPos); + RandomAccessFile ra = new RandomAccessFile(filePath, "rw"); + ra.seek(startPos); + ra.write(buffer, 0, buffer.length); + ra.close(); + System.out.println("线程" + this.getName() + "下载完成."); + }catch (IOException e) { + e.printStackTrace(); + } } } diff --git a/liuxin/src/com/coderising/download/FileDownloader.java b/liuxin/src/com/coderising/download/FileDownloader.java index f5d7999eb4..77fc19a041 100644 --- a/liuxin/src/com/coderising/download/FileDownloader.java +++ b/liuxin/src/com/coderising/download/FileDownloader.java @@ -1,5 +1,8 @@ package com.coderising.download; +import java.util.ArrayList; +import java.util.List; + import com.coderising.download.api.Connection; import com.coderising.download.api.ConnectionException; import com.coderising.download.api.ConnectionManager; @@ -14,7 +17,10 @@ public class FileDownloader { ConnectionManager cm; - + private final static int thread_count = 3; + + private final static String BASE_PATH = "E:\\"; + public FileDownloader(String _url) { this.url = _url; @@ -23,13 +29,18 @@ public FileDownloader(String _url) { public void execute(){ // 在这里实现你的代码, 注意: 需要用多线程实现下载 // 这个类依赖于其他几个接口, 你需要写这几个接口的实现代码 - // (1) ConnectionManager , 可以打开一个连接,通过Connection可以读取其中的一段(用startPos, endPos来指定) - // (2) DownloadListener, 由于是多线程下载, 调用这个类的客户端不知道什么时候结束,所以你需要实现当所有 - // 线程都执行完以后, 调用listener的notifiedFinished方法, 这样客户端就能收到通知。 + // (1) ConnectionManager , 可以打开一个连接, + //通过Connection可以读取其中的一段(用startPos, endPos来指定) + // (2) DownloadListener, 由于是多线程下载, + //调用这个类的客户端不知道什么时候结束,所以你需要实现当所有 + // 线程都执行完以后, 调用listener的notifiedFinished方法, + //这样客户端就能收到通知。 // 具体的实现思路: - // 1. 需要调用ConnectionManager的open方法打开连接, 然后通过Connection.getContentLength方法获得文件的长度 + // 1. 需要调用ConnectionManager的open方法打开连接, + //然后通过Connection.getContentLength方法获得文件的长度 // 2. 至少启动3个线程下载, 注意每个线程需要先调用ConnectionManager的open方法 - // 然后调用read方法, read方法中有读取文件的开始位置和结束位置的参数, 返回值是byte[]数组 + // 然后调用read方法, read方法中有读取文件的开始位置和结束位置的参数, + //返回值是byte[]数组 // 3. 把byte数组写入到文件中 // 4. 所有的线程都下载完成以后, 需要调用listener的notifiedFinished方法 @@ -41,10 +52,54 @@ public void execute(){ int length = conn.getContentLength(); - new DownloadThread(conn,0,length-1).start(); + String targetPath = BASE_PATH + "targetfile." + url.substring(url.lastIndexOf(".") + 1); + + int startPos = 0; + + int endPos = 0; + + List list = new ArrayList(); + + for(int i = 0; i < thread_count; i++){ + + conn = cm.open(url); + + startPos = i * (length / thread_count); + + endPos = (i == thread_count - 1) ? length - 1 : (i + 1) * (length / thread_count) - 1; + + DownloadThread thread = new DownloadThread(conn, startPos, endPos, targetPath); + + list.add(thread); + + thread.start(); + } + + // 调用线程的join方法,保证所有的线程都结束后再发出结束通知 + + for (int i = 0; i < list.size(); i++) { + + try { + + list.get(i).join(); + + } catch (InterruptedException e) { + + // TODO Auto-generated catch block + + e.printStackTrace(); + + } + + } + + + + listener.notifyFinished(); } catch (ConnectionException e) { e.printStackTrace(); + }finally{ if(conn != null){ conn.close(); diff --git a/liuxin/src/com/coderising/download/FileDownloaderTest.java b/liuxin/src/com/coderising/download/FileDownloaderTest.java index 8171ee5763..b8fb26cc2d 100644 --- a/liuxin/src/com/coderising/download/FileDownloaderTest.java +++ b/liuxin/src/com/coderising/download/FileDownloaderTest.java @@ -21,7 +21,7 @@ public void tearDown() throws Exception { @Test public void testDownload() { - String url = "http://localhost:8080/test.jpg"; + String url = "C:/Users/苏磊/Desktop/R%T[DQRU~@$6TKZ7)TD81JW.png"; FileDownloader downloader = new FileDownloader(url); diff --git a/liuxin/src/com/coderising/download/api/ConnectionException.java b/liuxin/src/com/coderising/download/api/ConnectionException.java index 8dbfe95dda..0b256f8f4a 100644 --- a/liuxin/src/com/coderising/download/api/ConnectionException.java +++ b/liuxin/src/com/coderising/download/api/ConnectionException.java @@ -2,4 +2,12 @@ public class ConnectionException extends Exception { + /** + * 自定义异常错误 + * @param string + */ + public ConnectionException(String string) { + + } + } diff --git a/liuxin/src/com/coderising/download/api/DownloadListener.java b/liuxin/src/com/coderising/download/api/DownloadListener.java index 4cd0b3eab1..ee55a8cec0 100644 --- a/liuxin/src/com/coderising/download/api/DownloadListener.java +++ b/liuxin/src/com/coderising/download/api/DownloadListener.java @@ -1,5 +1,6 @@ package com.coderising.download.api; public interface DownloadListener { + public void notifyFinished(); } diff --git a/liuxin/src/com/coderising/download/impl/ConnectionImpl.java b/liuxin/src/com/coderising/download/impl/ConnectionImpl.java index 32f03efdc7..99654289cb 100644 --- a/liuxin/src/com/coderising/download/impl/ConnectionImpl.java +++ b/liuxin/src/com/coderising/download/impl/ConnectionImpl.java @@ -1,26 +1,63 @@ package com.coderising.download.impl; +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; import com.coderising.download.api.Connection; public class ConnectionImpl implements Connection{ + private URL url; + + private final int byte_Size = 1024; + + public ConnectionImpl(URL url) { + this.url = url; + } + @Override public byte[] read(int startPos, int endPos) throws IOException { + URLConnection opCon = url.openConnection(); + opCon.setAllowUserInteraction(true); + opCon.setRequestProperty("Range", "bytes="+startPos+"-"+endPos); + //读入流 + InputStream in = opCon.getInputStream(); + //写出流 + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + byte[] bt = new byte[byte_Size]; + int length = 0; + while(-1!=(length=in.read(bt))){ + out.write(bt, startPos, endPos); + } - return null; + in.close(); + out.close(); + return out.toByteArray(); } @Override public int getContentLength() { - - return 0; + int contentLength = 0; + try { + contentLength = url.openConnection().getContentLength(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return contentLength; } @Override public void close() { - + if(url!=null){ + url = null; + } } diff --git a/liuxin/src/com/coderising/download/impl/ConnectionManagerImpl.java b/liuxin/src/com/coderising/download/impl/ConnectionManagerImpl.java index 046f7c49a4..c09716d298 100644 --- a/liuxin/src/com/coderising/download/impl/ConnectionManagerImpl.java +++ b/liuxin/src/com/coderising/download/impl/ConnectionManagerImpl.java @@ -1,5 +1,8 @@ package com.coderising.download.impl; +import java.net.MalformedURLException; +import java.net.URL; + import com.coderising.download.api.Connection; import com.coderising.download.api.ConnectionException; import com.coderising.download.api.ConnectionManager; @@ -8,8 +11,14 @@ public class ConnectionManagerImpl implements ConnectionManager { @Override public Connection open(String url) throws ConnectionException { - - return null; + Connection con; + try { + URL newUrl = new URL(url); + con = new ConnectionImpl(newUrl); + } catch (MalformedURLException e) { + throw new ConnectionException("URL格式出现错误"+e.getMessage()); + } + return con; } } diff --git a/liuxin/src/com/coding/basic/LinkedList.java b/liuxin/src/com/coding/basic/LinkedList.java index d162a3687c..96cffdabf0 100644 --- a/liuxin/src/com/coding/basic/LinkedList.java +++ b/liuxin/src/com/coding/basic/LinkedList.java @@ -1,6 +1,7 @@ package com.coding.basic; public class LinkedList implements List { + private int size; private Node head; @@ -18,7 +19,8 @@ public Object remove(int index){ } public int size(){ - return -1; + + return size; } public void addFirst(Object o){ @@ -41,29 +43,44 @@ public Iterator iterator(){ private static class Node{ Object data; Node next; - } /** * 把该链表逆置 + * head head * 例如链表为 3->7->10 , 逆置后变为 10->7->3 */ - public void reverse(){ - + public void reverse(){ + /** + * 长度超过1的单链表需要逆转 + */ + if(size>1){ + Node pre = head; + Node cur = head.next; + Node next = null; + while(cur!=null){ + next = cur.next; + cur.next = pre; + pre = cur; + cur = next; + } + + } } + /** * 删除一个单链表的前半部分 * 例如:list = 2->5->7->8 , 删除以后的值为 7->8 * 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10 */ - public void removeFirstHalf(){ + public void removeFirstHalf(){ } /** - * 从第i个元素开始, 删除length 个元素 , 注意i从0开始 + * 从第i个元素开始,删除length个元素 ,注意i从0开始 * @param i * @param length */ @@ -107,7 +124,7 @@ public void removeDuplicateValues(){ * @param min * @param max */ - public void removeRange(int min, int max){ + public void removeRange(int min, int max){ } @@ -116,7 +133,8 @@ public void removeRange(int min, int max){ * 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列 * @param list */ - public LinkedList intersection( LinkedList list){ + public LinkedList intersection(LinkedList list){ + return null; } } From f4e3a16794ed54e19f958244b8af09ac04bbd718 Mon Sep 17 00:00:00 2001 From: wiertty Date: Wed, 15 Mar 2017 19:46:14 +0800 Subject: [PATCH 020/287] =?UTF-8?q?=E5=A4=9A=E7=BA=BF=E7=A8=8B=E4=B8=8B?= =?UTF-8?q?=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coderising/download/DownloadThread.java | 35 ++++++ .../coderising/download/FileDownloader.java | 104 ++++++++++++++++++ .../download/FileDownloaderTest.java | 56 ++++++++++ .../coderising/download/api/Connection.java | 23 ++++ .../download/api/ConnectionException.java | 5 + .../download/api/ConnectionManager.java | 10 ++ .../download/api/DownloadListener.java | 5 + .../download/impl/ConnectionImpl.java | 46 ++++++++ .../download/impl/ConnectionManagerImpl.java | 29 +++++ .../src/com/coderising/litestruts/Struts.java | 19 +--- 10 files changed, 318 insertions(+), 14 deletions(-) create mode 100644 group05/289326186/src/com/coderising/download/DownloadThread.java create mode 100644 group05/289326186/src/com/coderising/download/FileDownloader.java create mode 100644 group05/289326186/src/com/coderising/download/FileDownloaderTest.java create mode 100644 group05/289326186/src/com/coderising/download/api/Connection.java create mode 100644 group05/289326186/src/com/coderising/download/api/ConnectionException.java create mode 100644 group05/289326186/src/com/coderising/download/api/ConnectionManager.java create mode 100644 group05/289326186/src/com/coderising/download/api/DownloadListener.java create mode 100644 group05/289326186/src/com/coderising/download/impl/ConnectionImpl.java create mode 100644 group05/289326186/src/com/coderising/download/impl/ConnectionManagerImpl.java diff --git a/group05/289326186/src/com/coderising/download/DownloadThread.java b/group05/289326186/src/com/coderising/download/DownloadThread.java new file mode 100644 index 0000000000..9690e741a2 --- /dev/null +++ b/group05/289326186/src/com/coderising/download/DownloadThread.java @@ -0,0 +1,35 @@ +package com.coderising.download; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; + +import com.coderising.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(){ + try { + byte[] b = conn.read(startPos, endPos); + String path = "D:" + File.separator + "test"+File.separator+"123.jpg"; + RandomAccessFile f = new RandomAccessFile(path, "rw"); + f.seek(startPos); + f.write(b); + f.close(); + System.out.println(Thread.currentThread().getName()+"线程下载完毕"); + } catch (IOException e) { + e.printStackTrace(); + } + + } +} \ No newline at end of file diff --git a/group05/289326186/src/com/coderising/download/FileDownloader.java b/group05/289326186/src/com/coderising/download/FileDownloader.java new file mode 100644 index 0000000000..d8a37c3abe --- /dev/null +++ b/group05/289326186/src/com/coderising/download/FileDownloader.java @@ -0,0 +1,104 @@ +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; + + +public class FileDownloader { + + String url; + + DownloadListener listener; + + ConnectionManager cm; + + int threadCount = 3; + + private DownloadThread[] threads = new DownloadThread[threadCount]; + + int length = 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 { + + conn = cm.open(this.url); + + length = conn.getContentLength(); + System.out.println("length:"+length); + + //计算每个线程需要下载的文件大小 + int perLen = 0; + int lastLen = 0; + int tail = length % threadCount; + perLen = length/threadCount; + if(tail == 0){ + lastLen = perLen; + }else{ + lastLen = perLen + tail; + } + for(int i=0; i parameters) String key = entry.getKey(); if(pd.getName().equals(key)){ Method setMethod = pd.getWriteMethod();//获得set方法 - setMethod .invoke(obj, entry.getValue());//调用 + setMethod.invoke(obj, entry.getValue());//调用 break; } } @@ -65,23 +65,14 @@ public static View runAction(String actionName, Map parameters) Method method = clazz.getMethod("execute", null); Object result = method.invoke(obj); Map map = new HashMap(); - if("success".equals(result)){ - map.put("message", "login successful"); - }else{ - map.put("message", "login failed,please check your user/pwd"); - } // 3. 通过反射找到对象的所有getter方法(例如 getMessage), // 通过反射来调用, 把值和属性形成一个HashMap , 例如 {"message": "登录成功"} , // 放到View对象的parameters for(PropertyDescriptor pd : pds){ - for (Entry entry : parameters.entrySet()) { - String key = entry.getKey(); - if(pd.getName().equals(key)){ - Method getMethod = pd.getReadMethod();//获得get方法 - Object getresult = getMethod .invoke(obj);//调用 - map.put(pd.getName(), getresult.toString()); - break; - } + Method getMethod = pd.getReadMethod();//获得get方法 + Object getresult = getMethod.invoke(obj);//调用 + if(!"class".equals(pd.getName())){ + map.put(pd.getName(), getresult.toString()); } } view.setParameters(map); From da29e3e0bd555542456736a2b896701df9f953ed Mon Sep 17 00:00:00 2001 From: wugu Date: Wed, 15 Mar 2017 22:17:04 +0800 Subject: [PATCH 021/287] ok --- .../com/coding/download/DownloadThread.java | 34 +++++++++ .../com/coding/download/FileDownloader.java | 76 +++++++++++++++++++ .../coding/download/FileDownloaderTest.java | 59 ++++++++++++++ .../com/coding/download/api/Connection.java | 23 ++++++ .../download/api/ConnectionException.java | 10 +++ .../download/api/ConnectionManager.java | 10 +++ .../coding/download/api/DownloadListener.java | 5 ++ .../coding/download/impl/ConnectionImpl.java | 50 ++++++++++++ .../download/impl/ConnectionManagerImpl.java | 23 ++++++ 9 files changed, 290 insertions(+) create mode 100644 group04/351121278/src/com/coding/download/DownloadThread.java create mode 100644 group04/351121278/src/com/coding/download/FileDownloader.java create mode 100644 group04/351121278/src/com/coding/download/FileDownloaderTest.java create mode 100644 group04/351121278/src/com/coding/download/api/Connection.java create mode 100644 group04/351121278/src/com/coding/download/api/ConnectionException.java create mode 100644 group04/351121278/src/com/coding/download/api/ConnectionManager.java create mode 100644 group04/351121278/src/com/coding/download/api/DownloadListener.java create mode 100644 group04/351121278/src/com/coding/download/impl/ConnectionImpl.java create mode 100644 group04/351121278/src/com/coding/download/impl/ConnectionManagerImpl.java diff --git a/group04/351121278/src/com/coding/download/DownloadThread.java b/group04/351121278/src/com/coding/download/DownloadThread.java new file mode 100644 index 0000000000..e0b396a5e6 --- /dev/null +++ b/group04/351121278/src/com/coding/download/DownloadThread.java @@ -0,0 +1,34 @@ +package com.coding.download; + +import com.coding.download.api.Connection; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; + +public class DownloadThread extends Thread{ + + Connection conn; + int startPos; + int endPos; + File file; + + public DownloadThread(File file, Connection conn, int startPos, int endPos){ + this.file = file; + this.conn = conn; + this.startPos = startPos; + this.endPos = endPos; + } + public void run(){ + try { + System.out.println("DownloadThread.run"); + byte[] buffer = conn.read(startPos, endPos); + RandomAccessFile raf = new RandomAccessFile(file, "rw"); + raf.seek(startPos); + raf.write(buffer, 0, buffer.length); + raf.close(); + } catch (IOException e) { + System.out.println("e = " + e.getMessage()); + } + } +} diff --git a/group04/351121278/src/com/coding/download/FileDownloader.java b/group04/351121278/src/com/coding/download/FileDownloader.java new file mode 100644 index 0000000000..13d24f5b2b --- /dev/null +++ b/group04/351121278/src/com/coding/download/FileDownloader.java @@ -0,0 +1,76 @@ +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; + +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); + File file = new File("D:/test"); + int length = conn.getContentLength(); + for (int i=0; i<3; i++) { + new DownloadThread(file, 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/group04/351121278/src/com/coding/download/FileDownloaderTest.java b/group04/351121278/src/com/coding/download/FileDownloaderTest.java new file mode 100644 index 0000000000..84fbc8afa2 --- /dev/null +++ b/group04/351121278/src/com/coding/download/FileDownloaderTest.java @@ -0,0 +1,59 @@ +package com.coding.download; + +import com.coding.download.api.ConnectionManager; +import com.coding.download.api.DownloadListener; +import com.coding.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/group04/351121278/src/com/coding/download/api/Connection.java b/group04/351121278/src/com/coding/download/api/Connection.java new file mode 100644 index 0000000000..bd75d6cad0 --- /dev/null +++ b/group04/351121278/src/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/group04/351121278/src/com/coding/download/api/ConnectionException.java b/group04/351121278/src/com/coding/download/api/ConnectionException.java new file mode 100644 index 0000000000..1f57f86606 --- /dev/null +++ b/group04/351121278/src/com/coding/download/api/ConnectionException.java @@ -0,0 +1,10 @@ +package com.coding.download.api; + +public class ConnectionException extends Exception { + + public ConnectionException(String exceptionMessage) { + + } + public ConnectionException() { + } +} diff --git a/group04/351121278/src/com/coding/download/api/ConnectionManager.java b/group04/351121278/src/com/coding/download/api/ConnectionManager.java new file mode 100644 index 0000000000..1d1a83caf2 --- /dev/null +++ b/group04/351121278/src/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/group04/351121278/src/com/coding/download/api/DownloadListener.java b/group04/351121278/src/com/coding/download/api/DownloadListener.java new file mode 100644 index 0000000000..c41045b0e8 --- /dev/null +++ b/group04/351121278/src/com/coding/download/api/DownloadListener.java @@ -0,0 +1,5 @@ +package com.coding.download.api; + +public interface DownloadListener { + public void notifyFinished(); +} diff --git a/group04/351121278/src/com/coding/download/impl/ConnectionImpl.java b/group04/351121278/src/com/coding/download/impl/ConnectionImpl.java new file mode 100644 index 0000000000..7d524ec4a0 --- /dev/null +++ b/group04/351121278/src/com/coding/download/impl/ConnectionImpl.java @@ -0,0 +1,50 @@ +package com.coding.download.impl; + +import com.coding.download.api.Connection; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.RandomAccessFile; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; + + +public class ConnectionImpl implements Connection { + + private static final int THEAD_COUNT = 3; + private URL url; + private HttpURLConnection httpURLConnection; + private final int BUFFER_SIZE = 1024; + + public ConnectionImpl(URL url) { + this.url = url; + } + + @Override + public byte[] read(int startPos, int endPos) throws IOException { + URLConnection urlConnection = url.openConnection(); + httpURLConnection = (HttpURLConnection)urlConnection; + httpURLConnection.setRequestMethod("GET"); + InputStream in = httpURLConnection.getInputStream(); + ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream(); + int len; + byte[] buffer = new byte[BUFFER_SIZE]; + while ((len = in.read(buffer)) != -1) { + byteOutputStream.write(buffer, startPos, len); + } + return byteOutputStream.toByteArray(); + } + + @Override + public int getContentLength() { + return httpURLConnection.getContentLength(); + } + + @Override + public void close() { + httpURLConnection.disconnect(); + } + +} diff --git a/group04/351121278/src/com/coding/download/impl/ConnectionManagerImpl.java b/group04/351121278/src/com/coding/download/impl/ConnectionManagerImpl.java new file mode 100644 index 0000000000..c07a0b545a --- /dev/null +++ b/group04/351121278/src/com/coding/download/impl/ConnectionManagerImpl.java @@ -0,0 +1,23 @@ +package com.coding.download.impl; + +import com.coding.download.api.Connection; +import com.coding.download.api.ConnectionException; +import com.coding.download.api.ConnectionManager; + +import java.net.MalformedURLException; +import java.net.URL; + +public class ConnectionManagerImpl implements ConnectionManager { + + @Override + public Connection open(String url) throws ConnectionException { + URL urlObj; + try { + urlObj = new URL(url); + } catch (MalformedURLException e) { + throw new ConnectionException("URL无法访问" + e.getMessage()); + } + return new ConnectionImpl(urlObj); + } + +} From 1ad30ca6883d1053cfa434c064accda2dea496d0 Mon Sep 17 00:00:00 2001 From: Administrator Date: Wed, 15 Mar 2017 23:30:38 +0800 Subject: [PATCH 022/287] =?UTF-8?q?edit=20=E5=A4=9A=E7=BA=BF=E7=A8=8B?= =?UTF-8?q?=E4=B8=8B=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coding/three/download/DownloadThread.java | 50 +++--------- .../coding/three/download/FileDownloader.java | 79 +++++++++++++------ .../download/api/ConnectionException.java | 4 + .../three/download/impl/ConnectionImpl.java | 62 +++++++-------- .../download/impl/ConnectionManagerImpl.java | 6 +- .../three/download/FileDownloaderTest.java | 9 ++- 6 files changed, 107 insertions(+), 103 deletions(-) diff --git a/group04/498654356/one/src/org/coding/three/download/DownloadThread.java b/group04/498654356/one/src/org/coding/three/download/DownloadThread.java index 2675e31851..84a0d94c73 100644 --- a/group04/498654356/one/src/org/coding/three/download/DownloadThread.java +++ b/group04/498654356/one/src/org/coding/three/download/DownloadThread.java @@ -1,60 +1,36 @@ package org.coding.three.download; -import java.io.File; -import java.io.IOException; import java.io.RandomAccessFile; -import java.util.Arrays; +import java.util.concurrent.CyclicBarrier; import org.coding.three.download.api.Connection; public class DownloadThread extends Thread{ - String filePath = "D:\\a.jpg"; - - FileDownloader fileDownloader; + CyclicBarrier barrier; Connection conn; int startPos; int endPos; + String destpath; - public DownloadThread(FileDownloader fileDownloader, Connection conn, int startPos, int endPos){ - this.fileDownloader = fileDownloader; + public DownloadThread(CyclicBarrier barrier, Connection conn, int startPos, int endPos, String destpath) { + this.barrier = barrier; this.conn = conn; this.startPos = startPos; this.endPos = endPos; + this.destpath = destpath; } public void run(){ - RandomAccessFile accessFile = null; try { - synchronized (DownloadThread.class) { - File file = new File(filePath); - if(!file.exists()) { - file.createNewFile(); - accessFile = new RandomAccessFile(file, "rw"); - accessFile.setLength(conn.getContentLength()); - } byte[] b = conn.read(startPos, endPos); - accessFile = new RandomAccessFile(new File(filePath), "rw"); - System.out.println(Thread.currentThread().getName() + " --> 读取数据 " + b.length ); - accessFile.seek(startPos); - accessFile.write(b); - } - } catch (IOException e) { + RandomAccessFile raf = new RandomAccessFile(destpath, "rw"); + raf.seek(startPos); + raf.write(b); + raf.close(); + conn.close(); + barrier.await(); + } catch (Exception e) { e.printStackTrace(); - } finally { - fileDownloader.addFinshCount(); - if(fileDownloader.isFinsh()) { - fileDownloader.listener.notifyFinished(); - } - if(accessFile != null) { - try { - accessFile.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - if(conn != null) { - conn.close(); - } } } } diff --git a/group04/498654356/one/src/org/coding/three/download/FileDownloader.java b/group04/498654356/one/src/org/coding/three/download/FileDownloader.java index 4cfd75f1da..69e83d1eae 100644 --- a/group04/498654356/one/src/org/coding/three/download/FileDownloader.java +++ b/group04/498654356/one/src/org/coding/three/download/FileDownloader.java @@ -1,22 +1,26 @@ package org.coding.three.download; +import java.io.File; +import java.io.RandomAccessFile; +import java.util.concurrent.CyclicBarrier; + import org.coding.three.download.api.Connection; -import org.coding.three.download.api.ConnectionException; import org.coding.three.download.api.ConnectionManager; import org.coding.three.download.api.DownloadListener; public class FileDownloader { String url; + String destPath; + private int threadCount; DownloadListener listener; - ConnectionManager cm; - - public FileDownloader(String _url) { + public FileDownloader(String _url, String destPath, int threadCount) { this.url = _url; - + this.destPath = destPath; + this.threadCount = threadCount; } public void execute(){ @@ -36,23 +40,57 @@ public void execute(){ Connection conn = null; try { conn = cm.open(this.url); - int length = conn.getContentLength(); - // TODO - int size = length / THREAD_COUNT; - for(int i = 0; i < THREAD_COUNT; i++) { - int start = i * size; - int end = start + size - 1; - if(i == THREAD_COUNT - 1) { - end += length % THREAD_COUNT; + int length = conn.getContentLength(); + createDownloadFile(length); + int[][] threadData = allocationData(length); + CyclicBarrier barrier = new CyclicBarrier(this.threadCount, new Runnable() { + @Override + public void run() { + listener.notifyFinished(); } - new DownloadThread(this, conn, start, end).start(); + }); + // TODO + for(int i = 0; i < this.threadCount; i++) { + new DownloadThread(barrier, conn, threadData[i][0], threadData[i][1], this.destPath).start(); } - } catch (ConnectionException e) { + } catch (Exception e) { e.printStackTrace(); + } finally { + conn.close(); } } + private int[][] allocationData(int length) { + int[][] threadData = new int[this.threadCount][2]; + int size = length / this.threadCount; + int offset = length % this.threadCount; + for(int i = 0; i < this.threadCount; i++) { + int start = i * size; + int end = (i + 1) * size -1; + if(i + 1 == this.threadCount) { + end += offset; + } + threadData[i][0] = start; + threadData[i][1] = end; + + } + return threadData; + } + + + private void createDownloadFile(int length) throws Exception { + File file = new File(destPath); + if(file.exists()) { + file.delete(); + } + RandomAccessFile raf = new RandomAccessFile(destPath, "rw"); + for(int i = 0; i < length; i++) { + raf.writeByte(0); + } + raf.close(); + } + public void setListener(DownloadListener listener) { this.listener = listener; } @@ -65,17 +103,6 @@ public DownloadListener getListener(){ } - private static final int THREAD_COUNT = 3; - private int finshCount; - - public synchronized void addFinshCount(){ - finshCount++; - } - - public synchronized boolean isFinsh() { - return THREAD_COUNT == finshCount; - } - } \ No newline at end of file diff --git a/group04/498654356/one/src/org/coding/three/download/api/ConnectionException.java b/group04/498654356/one/src/org/coding/three/download/api/ConnectionException.java index 7393d8824b..a07cc52e39 100644 --- a/group04/498654356/one/src/org/coding/three/download/api/ConnectionException.java +++ b/group04/498654356/one/src/org/coding/three/download/api/ConnectionException.java @@ -9,4 +9,8 @@ public ConnectionException(String msg) { super(msg); } + public ConnectionException(Throwable t) { + super(t); + } + } diff --git a/group04/498654356/one/src/org/coding/three/download/impl/ConnectionImpl.java b/group04/498654356/one/src/org/coding/three/download/impl/ConnectionImpl.java index afd71c78ee..b81dc72dc4 100644 --- a/group04/498654356/one/src/org/coding/three/download/impl/ConnectionImpl.java +++ b/group04/498654356/one/src/org/coding/three/download/impl/ConnectionImpl.java @@ -1,64 +1,64 @@ package org.coding.three.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 org.coding.three.download.api.Connection; +import org.coding.three.download.api.ConnectionException; public class ConnectionImpl implements Connection{ - private String url; - private int length; - private InputStream inputStream; - public ConnectionImpl (String url) throws Exception{ - super(); - this.url = url; - URL u = new URL(url); - int length = u.openConnection().getContentLength(); - this.length = length; + private static final int BUFFER_SIZE = 1024; + private URL url; + public ConnectionImpl (String url) throws ConnectionException { + try { + this.url = new URL(url); + } catch (MalformedURLException e) { + throw new ConnectionException(e); + } } @Override public byte[] read(int startPos, int endPos) throws IOException { - URL u = new URL(this.url); - HttpURLConnection urlConnection = (HttpURLConnection) u.openConnection(); - urlConnection.setRequestMethod("GET"); - urlConnection.setConnectTimeout(5000); + HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); // *** urlConnection.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos); - System.out.println(Thread.currentThread() + "---> startPos = " + startPos + ", endPos = " + endPos ); + InputStream is = urlConnection.getInputStream(); int size = endPos - startPos + 1; - byte[] data = new byte[size * 2]; - InputStream inputStream = urlConnection.getInputStream(); - this.inputStream = inputStream; - // *** 从 0 开始 - byte[] b = new byte[1024]; - int length = 0; - int count = 0; - int dataLength = 0; - while((length = inputStream.read(b)) != -1) { - int destPos = count * 1024; - for(int i = 0; i < length; i++) { - data[destPos + i] = b[i]; - dataLength++; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buffer = new byte[BUFFER_SIZE]; + int len = 0; + while(baos.size() < size) { + if((len = is.read(buffer)) < 0) { + break; } - count++; + baos.write(buffer, 0, len); } - return Arrays.copyOf(data, dataLength); + if(baos.size() > size) { + return Arrays.copyOf(baos.toByteArray(), size); + } + return baos.toByteArray(); } @Override public int getContentLength() { - return this.length; + try { + return url.openConnection().getContentLength(); + } catch (IOException e) { + e.printStackTrace(); + } + return -1; } @Override public void close() { try { - this.inputStream.close(); + url.openStream().close(); } catch (IOException e) { e.printStackTrace(); } diff --git a/group04/498654356/one/src/org/coding/three/download/impl/ConnectionManagerImpl.java b/group04/498654356/one/src/org/coding/three/download/impl/ConnectionManagerImpl.java index d8f19033d3..e595cb3ccb 100644 --- a/group04/498654356/one/src/org/coding/three/download/impl/ConnectionManagerImpl.java +++ b/group04/498654356/one/src/org/coding/three/download/impl/ConnectionManagerImpl.java @@ -8,11 +8,7 @@ public class ConnectionManagerImpl implements ConnectionManager { @Override public Connection open(String url) throws ConnectionException { - try { - return new ConnectionImpl(url); - } catch (Exception e) { - throw new ConnectionException(e.getMessage()); - } + return new ConnectionImpl(url); } } diff --git a/group04/498654356/one/test/org/coding/three/download/FileDownloaderTest.java b/group04/498654356/one/test/org/coding/three/download/FileDownloaderTest.java index e384154293..63d98a4636 100644 --- a/group04/498654356/one/test/org/coding/three/download/FileDownloaderTest.java +++ b/group04/498654356/one/test/org/coding/three/download/FileDownloaderTest.java @@ -22,14 +22,15 @@ public void tearDown() throws Exception { public void testDownload() { // String url = "http://7xq43s.com1.z0.glb.clouddn.com/yunanding-6.jpg"; - String url = "http://orig04.deviantart.net/93d4/f/2007/314/9/5/audrey_tautou_by_shimoda7.jpg"; // String url = "http://www.yinwang.org/blog-cn/2016/11/17/all-about-hillary"; +// String url = "http://orig04.deviantart.net/93d4/f/2007/314/9/5/audrey_tautou_by_shimoda7.jpg"; + String url = "http://pic36.nipic.com/20131230/1081324_162447228136_2.jpg"; + String destpath = "D:/b.jpg"; + int threadCount = 3; - FileDownloader downloader = new FileDownloader(url); - + FileDownloader downloader = new FileDownloader(url, destpath, threadCount); ConnectionManager cm = new ConnectionManagerImpl(); downloader.setConnectionManager(cm); - downloader.setListener(new DownloadListener() { @Override public void notifyFinished() { 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 023/287] =?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 024/287] 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 025/287] 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 8f8af8cf17c26f6207121374db775dc4f7ed8cc6 Mon Sep 17 00:00:00 2001 From: zj <2258659044@qq.com> Date: Thu, 16 Mar 2017 17:54:31 +0800 Subject: [PATCH 026/287] =?UTF-8?q?=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coderising/download/DownloadThread.java | 42 +++---------------- .../coderising/download/FileDownloader.java | 36 ++++++++++------ .../download/impl/ConnectionImpl.java | 2 +- 3 files changed, 30 insertions(+), 50 deletions(-) diff --git a/group12/2258659044/zj-2017/src/com/coderising/download/DownloadThread.java b/group12/2258659044/zj-2017/src/com/coderising/download/DownloadThread.java index b4d218399f..3c13facd32 100644 --- a/group12/2258659044/zj-2017/src/com/coderising/download/DownloadThread.java +++ b/group12/2258659044/zj-2017/src/com/coderising/download/DownloadThread.java @@ -1,8 +1,6 @@ package com.coderising.download; import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; @@ -31,35 +29,6 @@ public DownloadThread(String downloadPath, Connection conn, int startPos, this.endPos = endPos; } - /** - * 这种操作存在弊端, - * 若文件过大,调用conn.read读取过程中程序中断 - * 将无法缓存任何数据 - */ - /*public void run() { - - try { - - //请求服务器下载部分文件 指定文件的位置 读取指定位子的字节 - byte[] buffer = conn.read(startPos, endPos); - //随机访问文件流 - RandomAccessFile raf = new RandomAccessFile(tempFile, "rwd"); - //随机写文件的时候从哪个位置开始写 - raf.seek(startPos);//定位文件 - //写文件 - raf.write(buffer); - raf.close(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } finally { - if (conn != null) { - conn.close(); - } - } - }*/ - public void run() { try { @@ -75,8 +44,8 @@ public void run() { tempFile = file; //获取指定文件段的下载流 InputStream in = conn.getDownloadStream(startPos, endPos); - if(in == null){ - return; + if(in == null){//重新请求连接 + run(); } //随机访问文件流 RandomAccessFile raf = new RandomAccessFile(tempFile, "rwd"); @@ -90,10 +59,9 @@ public void run() { downloadSize += length; } raf.close(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); + } catch (Exception e) { + run(); + e.printStackTrace(); } finally { if (conn != null) { conn.close(); diff --git a/group12/2258659044/zj-2017/src/com/coderising/download/FileDownloader.java b/group12/2258659044/zj-2017/src/com/coderising/download/FileDownloader.java index cb84d148c7..721f2c77e0 100644 --- a/group12/2258659044/zj-2017/src/com/coderising/download/FileDownloader.java +++ b/group12/2258659044/zj-2017/src/com/coderising/download/FileDownloader.java @@ -31,18 +31,7 @@ public void execute(){ conn = cm.open(this.url); int length = conn.getContentLength(); //分配下载块 - int blockSize = length / threadNum; - DownloadThread[] threads = new DownloadThread[threadNum]; - for (int thread = 1; thread <= threadNum; thread++) { - int startIndex = (thread - 1) * blockSize; - int endIndex = thread * blockSize-1; - if (thread == threadNum) {//最后一个线程下载的长度 - endIndex = length; - } - DownloadThread thr = new DownloadThread(downloadPath,cm.open(this.url),startIndex,endIndex); - threads[thread-1] = thr; - thr.start(); - } + DownloadThread[] threads = assignDownloadPart(length); //判断所有线程是否下载完成 new NotifyCaller(listener,threads,length).start(); @@ -54,6 +43,29 @@ public void execute(){ } } } + + /** + * 分配下载块并启动下载 + * @param length + * @return + * @throws ConnectionException + */ + private DownloadThread[] assignDownloadPart(int length) + throws ConnectionException { + int blockSize = length / threadNum; + DownloadThread[] threads = new DownloadThread[threadNum]; + for (int thread = 1; thread <= threadNum; thread++) { + int startIndex = (thread - 1) * blockSize; + int endIndex = thread * blockSize-1; + if (thread == threadNum) {//最后一个线程下载的长度 + endIndex = length; + } + DownloadThread thr = new DownloadThread(downloadPath,cm.open(this.url),startIndex,endIndex); + threads[thread-1] = thr; + thr.start(); + } + return threads; + } public void setListener(DownloadListener listener) { this.listener = listener; diff --git a/group12/2258659044/zj-2017/src/com/coderising/download/impl/ConnectionImpl.java b/group12/2258659044/zj-2017/src/com/coderising/download/impl/ConnectionImpl.java index 0ec6bf08e7..8f5a0a8757 100644 --- a/group12/2258659044/zj-2017/src/com/coderising/download/impl/ConnectionImpl.java +++ b/group12/2258659044/zj-2017/src/com/coderising/download/impl/ConnectionImpl.java @@ -7,7 +7,7 @@ import com.coderising.download.api.Connection; -public class ConnectionImpl implements Connection{ +class ConnectionImpl implements Connection{ /*http连接*/ private HttpURLConnection httpConnection; From cd169fc47038a0fb0b15cb6ddd8bc1912e8bbe28 Mon Sep 17 00:00:00 2001 From: JayXu Date: Thu, 16 Mar 2017 18:04:07 +0800 Subject: [PATCH 027/287] 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 028/287] 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 029/287] 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 030/287] 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 c2e16447cecea1791f3e9692f36e680677975ea9 Mon Sep 17 00:00:00 2001 From: gongxun Date: Tue, 21 Mar 2017 18:45:14 +0800 Subject: [PATCH 031/287] =?UTF-8?q?=E4=B8=AD=E9=80=94=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=E4=BF=9D=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group17/785396327/3.12/link/LinkedList.java | 25 ++++++++++++++----- .../785396327/3.12/link/LinkedListTest.java | 15 ++++++++++- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/group17/785396327/3.12/link/LinkedList.java b/group17/785396327/3.12/link/LinkedList.java index e9925e8ae8..f9fc09bfef 100644 --- a/group17/785396327/3.12/link/LinkedList.java +++ b/group17/785396327/3.12/link/LinkedList.java @@ -21,10 +21,9 @@ public void add(T o) { } private Node getLast() { - Node last = null; - while (head.next != null) { - last = head; - head = head.next; + Node last = head; + while (last.next != null) { + last = last.next; } return last; } @@ -252,7 +251,21 @@ public void removeDuplicateValues() { * @param max */ public void removeRange(int min, int max) { - + Integer first = (Integer) get(0); + Integer last = (Integer) getLast().data; + if (first > max || last < min) + return; + List indexRange = new ArrayList(); + Node temp = (Node) head; + int index = 0; + while (temp != null) { + if (temp.data >= min && temp.data <= max) { + indexRange.add(index); + } + index++; + temp = temp.next; + } + remove(indexRange.get(0), indexRange.size()); } /** @@ -261,7 +274,7 @@ public void removeRange(int min, int max) { * * @param list */ - public LinkedList intersection(LinkedList list) { + public LinkedList intersection(LinkedList list) { return null; } } diff --git a/group17/785396327/3.12/link/LinkedListTest.java b/group17/785396327/3.12/link/LinkedListTest.java index 83df19d4fa..057844b0c8 100644 --- a/group17/785396327/3.12/link/LinkedListTest.java +++ b/group17/785396327/3.12/link/LinkedListTest.java @@ -18,7 +18,7 @@ public void startUp() { linkedList.add("1"); linkedList.add("2"); linkedList.add("3"); - System.out.println(linkedList); +// System.out.println(linkedList); } @After @@ -115,4 +115,17 @@ public void removeDuplicateValues() { System.out.println(linkedList); } + @Test + public void removeRange() { + LinkedList list = new LinkedList(); + list.add(1); + list.add(3); + list.add(4); + list.add(5); + list.add(7); + System.out.println(list); + list.removeRange(1, 6); + System.out.println(list); + } + } From c8521e294e4720b76274fc98aa108a5039e1386e Mon Sep 17 00:00:00 2001 From: maishihang <446031103@qq.com> Date: Tue, 21 Mar 2017 22:17:52 +0800 Subject: [PATCH 032/287] update ArrayUtil 20170321 --- .../src/com/coderising/array/ArrayUtil.java | 206 ++++++++++-------- 1 file changed, 110 insertions(+), 96 deletions(-) diff --git a/group12/446031103/src/com/coderising/array/ArrayUtil.java b/group12/446031103/src/com/coderising/array/ArrayUtil.java index a771999a22..30506ef87a 100644 --- a/group12/446031103/src/com/coderising/array/ArrayUtil.java +++ b/group12/446031103/src/com/coderising/array/ArrayUtil.java @@ -4,6 +4,8 @@ import java.util.Arrays; import java.util.List; +import com.sun.xml.internal.bind.v2.runtime.unmarshaller.XsiNilLoader.Array; + public class ArrayUtil { /** @@ -14,13 +16,15 @@ public class ArrayUtil { * @return */ public void reverseArray(int[] origin){ - int end = origin.length-1; - int temp ; - for (int i = 0; i < end; i++,end--) { - temp=origin[i]; - origin[i]=origin[end]; - origin[end] = temp; + if(null ==origin ||0==origin.length){ + return; + } + for (int i = 0,j=origin.length-1; i < j; i++,j--) { + int temp=origin[i] ; + origin[i]= origin[j]; + origin[i]=temp; } + } /** @@ -32,23 +36,18 @@ public void reverseArray(int[] origin){ */ public int[] removeZero(int[] oldArray){ - int zeroCnt = 0; - for (int i : oldArray) { - if(0==i){ - zeroCnt++; - } - - } - int size = 0; - int [] result = new int[oldArray.length-zeroCnt]; - for (int i : oldArray) { - if(0!=i){ - result[size]=i; - size++; + if(null==oldArray||oldArray.length ==0){ + return null; + } + int notZeroCnt = 0; + int [] temp = new int[oldArray.length]; + for (int i = 0; i < oldArray.length; i++) { + if(oldArray[i]!=0){ + temp[notZeroCnt++] = oldArray[i]; } - } - return result; + System.arraycopy(temp, 0, temp, 0, notZeroCnt); + return temp; } /** @@ -60,31 +59,34 @@ public int[] removeZero(int[] oldArray){ */ public int[] merge(int[] array1, int[] array2){ - //合拼数组,缺排序,缺去重 + if(null==array1&&null==array2){ + return null; + } int [] temp = new int[array1.length+array2.length]; - System.arraycopy(array1, 0, temp, 0, array1.length); - System.arraycopy(array2, 0, temp, array1.length, array2.length); - List resultList= new ArrayList(); - for (int i : temp) { - if(!resultList.contains(i)) - resultList.add(i); - }//已去重数组,缺排序 - int [] result = new int[resultList.size()]; - for (int i = 0; i < resultList.size(); i++) { - result[i] = resultList.get(i); - } - //冒泡排序 - for (int i = 0; i < result.length-1; i++) { - for (int j = 0; j < result.length-i-1; j++) { - if(result[j]>result[j+1]){ - int tempInt = result[j]; - result[j] =result[j+1]; - result[j+1] = tempInt; - } + int i = 0; + int j = 0; + int count = 0; + while (iarray2[j]){ + temp[count++] = array2[j++]; + } + if(array1[i]==array2[j]){ + temp[count++] = array2[j]; + i++; + j++; } - - } - return result; + } + while(i==array1.length&&j resultList= new ArrayList(); - if(max!=second) - add(first,second,max,resultList); - int [] result = new int[resultList.size()]; - for (int i = 0; i < resultList.size(); i++) { - result[i] = resultList.get(i); - } - return result; + if(1==max){ + return new int[0]; + } + if(2==max){ + return new int[]{1,1}; + } + int [] temp = new int [max] ; + temp[0] = 1; + temp[1] = 1; + int cnt = 2; + for (int i = 2 ; i < max; i++) { + temp[i] = temp[i-1] + temp[i-2]; + if(temp[i]>=max){ + break; + }else{ + cnt++; + } + } + return Arrays.copyOf(temp, cnt); } /** @@ -126,23 +137,30 @@ public int[] fibonacci(int max){ * @return */ public int[] getPrimes(int max){ - List resultList= new ArrayList(); + if(max<2){ + return new int[0]; + } + int [] temp = new int[max]; + int cnt = 0; for (int i = 2; i < max; i++) { - boolean isAdd = true; - for (int j = 2; j < i; j++) { - if(0==i%j){ - isAdd = false; - break; - } + if(isPrime(i)){ + temp[cnt++] = i; } - if(isAdd) - resultList.add(i); } - int [] result = new int[resultList.size()]; - for (int i = 0; i < resultList.size(); i++) { - result[i] = resultList.get(i); + return Arrays.copyOf(temp, cnt); + } + + private boolean isPrime(int n){ + int i = 2; + while(i resultList= new ArrayList(); - for (int i = 1; i < max; i++) { - int temp = 0; + if(max<0){ + return null; + } + int cnt = 0; + int [] temp = new int[max]; + for (int i = 2; i < max; i++) { + int sum = 0; for (int j = 1; j < i; j++) { - if(0==i%j){ - temp+=j; + if(i%j==0){ + sum+=j; } } - if(i==temp) - resultList.add(i); - } - int [] result = new int[resultList.size()]; - for (int i = 0; i < resultList.size(); i++) { - result[i] = resultList.get(i); + if(sum==i){ + temp[cnt++] = i; + } } - return result; + return Arrays.copyOf(temp, cnt); } /** @@ -179,24 +198,19 @@ public int[] getPerfectNumbers(int max){ * @return */ public String join(int[] array, String seperator){ - return Arrays.toString(array).replace("[", "").replace("]", "").replace(", ", seperator); + if(null==array||array.length==0){ + return ""; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < array.length; i++) { + sb.append(array[i]); + if(i add(int number1,int number2,int max,List resultList){ - if(number2 Date: Thu, 23 Mar 2017 20:09:47 +0800 Subject: [PATCH 033/287] =?UTF-8?q?=E5=A4=9A=E7=BA=BF=E7=A8=8B=E4=B8=8B?= =?UTF-8?q?=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/com/coderising/array/ArrayUtil.java | 96 +++++++++++++ .../coderising/download/DownloadThread.java | 50 +++++++ .../coderising/download/FileDownloader.java | 126 ++++++++++++++++++ .../download/FileDownloaderTest.java | 59 ++++++++ .../coderising/download/api/Connection.java | 23 ++++ .../download/api/ConnectionException.java | 5 + .../download/api/ConnectionManager.java | 10 ++ .../download/api/DownloadListener.java | 5 + .../download/impl/ConnectionImpl.java | 73 ++++++++++ .../download/impl/ConnectionManagerImpl.java | 15 +++ .../coderising/litestruts/LoginAction.java | 39 ++++++ .../src/com/coderising/litestruts/Struts.java | 34 +++++ .../com/coderising/litestruts/StrutsTest.java | 43 ++++++ .../src/com/coderising/litestruts/View.java | 23 ++++ .../src/com/coding/basic/ArrayList.java | 32 +++++ .../src/com/coding/basic/BinaryTreeNode.java | 32 +++++ .../src/com/coding/basic/Iterator.java | 7 + .../src/com/coding/basic/LinkedList.java | 124 +++++++++++++++++ .../src/com/coding/basic/List.java | 9 ++ .../src/com/coding/basic/Queue.java | 19 +++ .../src/com/coding/basic/Stack.java | 22 +++ 21 files changed, 846 insertions(+) create mode 100644 group12/563253496/week3_file_download/src/com/coderising/array/ArrayUtil.java create mode 100644 group12/563253496/week3_file_download/src/com/coderising/download/DownloadThread.java create mode 100644 group12/563253496/week3_file_download/src/com/coderising/download/FileDownloader.java create mode 100644 group12/563253496/week3_file_download/src/com/coderising/download/FileDownloaderTest.java create mode 100644 group12/563253496/week3_file_download/src/com/coderising/download/api/Connection.java create mode 100644 group12/563253496/week3_file_download/src/com/coderising/download/api/ConnectionException.java create mode 100644 group12/563253496/week3_file_download/src/com/coderising/download/api/ConnectionManager.java create mode 100644 group12/563253496/week3_file_download/src/com/coderising/download/api/DownloadListener.java create mode 100644 group12/563253496/week3_file_download/src/com/coderising/download/impl/ConnectionImpl.java create mode 100644 group12/563253496/week3_file_download/src/com/coderising/download/impl/ConnectionManagerImpl.java create mode 100644 group12/563253496/week3_file_download/src/com/coderising/litestruts/LoginAction.java create mode 100644 group12/563253496/week3_file_download/src/com/coderising/litestruts/Struts.java create mode 100644 group12/563253496/week3_file_download/src/com/coderising/litestruts/StrutsTest.java create mode 100644 group12/563253496/week3_file_download/src/com/coderising/litestruts/View.java create mode 100644 group12/563253496/week3_file_download/src/com/coding/basic/ArrayList.java create mode 100644 group12/563253496/week3_file_download/src/com/coding/basic/BinaryTreeNode.java create mode 100644 group12/563253496/week3_file_download/src/com/coding/basic/Iterator.java create mode 100644 group12/563253496/week3_file_download/src/com/coding/basic/LinkedList.java create mode 100644 group12/563253496/week3_file_download/src/com/coding/basic/List.java create mode 100644 group12/563253496/week3_file_download/src/com/coding/basic/Queue.java create mode 100644 group12/563253496/week3_file_download/src/com/coding/basic/Stack.java diff --git a/group12/563253496/week3_file_download/src/com/coderising/array/ArrayUtil.java b/group12/563253496/week3_file_download/src/com/coderising/array/ArrayUtil.java new file mode 100644 index 0000000000..e5ddb476a6 --- /dev/null +++ b/group12/563253496/week3_file_download/src/com/coderising/array/ArrayUtil.java @@ -0,0 +1,96 @@ +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 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){ + return null; + } + + /** + * 给定两个已经排序好的整形数组, 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){ + return null; + } + /** + * 把一个已经存满数据的数组 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){ + return null; + } + + /** + * 斐波那契数列为: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){ + return null; + } + + /** + * 返回小于给定最大值max的所有素数数组 + * 例如max = 23, 返回的数组为[2,3,5,7,11,13,17,19] + * @param max + * @return + */ + public int[] getPrimes(int max){ + return null; + } + + /** + * 所谓“完数”, 是指这个数恰好等于它的因子之和,例如6=1+2+3 + * 给定一个最大值max, 返回一个数组, 数组中是小于max 的所有完数 + * @param max + * @return + */ + public int[] getPerfectNumbers(int max){ + return null; + } + + /** + * 用seperator 把数组 array给连接起来 + * 例如array= [3,8,9], seperator = "-" + * 则返回值为"3-8-9" + * @param array + * @param s + * @return + */ + public String join(int[] array, String seperator){ + return null; + } + + +} diff --git a/group12/563253496/week3_file_download/src/com/coderising/download/DownloadThread.java b/group12/563253496/week3_file_download/src/com/coderising/download/DownloadThread.java new file mode 100644 index 0000000000..a3dc676a90 --- /dev/null +++ b/group12/563253496/week3_file_download/src/com/coderising/download/DownloadThread.java @@ -0,0 +1,50 @@ +package com.coderising.download; + +import com.coderising.download.api.Connection; +import com.sun.org.apache.xpath.internal.SourceTree; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.concurrent.BrokenBarrierException; +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; + } + + public void run() { + System.out.println("Begin to read [" + startPos + "-" + endPos + "]"); + + try { + 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 (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (BrokenBarrierException e) { + e.printStackTrace(); + } + + } +} diff --git a/group12/563253496/week3_file_download/src/com/coderising/download/FileDownloader.java b/group12/563253496/week3_file_download/src/com/coderising/download/FileDownloader.java new file mode 100644 index 0000000000..8b35a9a11d --- /dev/null +++ b/group12/563253496/week3_file_download/src/com/coderising/download/FileDownloader.java @@ -0,0 +1,126 @@ +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 java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.concurrent.CyclicBarrier; + + +public class FileDownloader { + + String url; + 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() { + @Override + public void run() { + listener.notifyFinished(); + } + }); + + + Connection conn = null; + try { + + conn = cm.open(this.url); + + int length = conn.getContentLength(); + + this.createPlaceHolderFile(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(); + } + + //new DownloadThread(conn, 0, length - 1, localFile, barrier).start(); + + } catch (ConnectionException e) { + e.printStackTrace(); + } finally { + if (conn != null) { + conn.close(); + } + } + } + + private void createPlaceHolderFile(String fileName, int contentLen) { + try { + RandomAccessFile file = new RandomAccessFile(fileName, "rw"); + for (int i = 0; i < contentLen; i++) { + file.write(0); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + + } + + 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 this.listener; + } + +} diff --git a/group12/563253496/week3_file_download/src/com/coderising/download/FileDownloaderTest.java b/group12/563253496/week3_file_download/src/com/coderising/download/FileDownloaderTest.java new file mode 100644 index 0000000000..7ec4c1f2e3 --- /dev/null +++ b/group12/563253496/week3_file_download/src/com/coderising/download/FileDownloaderTest.java @@ -0,0 +1,59 @@ +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://localhost:8080/test.jpg"; + String url ="http://desk.fd.zol-img.com.cn/t_s1920x1080c5/g3/M04/0B/06/Cg-4V1Q_K_2IS20UAAvKmTmHyYIAAQLGwOZI-YAC8qx308.jpg"; + FileDownloader downloader = new FileDownloader(url,"d:/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/group12/563253496/week3_file_download/src/com/coderising/download/api/Connection.java b/group12/563253496/week3_file_download/src/com/coderising/download/api/Connection.java new file mode 100644 index 0000000000..0957eaf7f4 --- /dev/null +++ b/group12/563253496/week3_file_download/src/com/coderising/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/group12/563253496/week3_file_download/src/com/coderising/download/api/ConnectionException.java b/group12/563253496/week3_file_download/src/com/coderising/download/api/ConnectionException.java new file mode 100644 index 0000000000..1551a80b3d --- /dev/null +++ b/group12/563253496/week3_file_download/src/com/coderising/download/api/ConnectionException.java @@ -0,0 +1,5 @@ +package com.coderising.download.api; + +public class ConnectionException extends Exception { + +} diff --git a/group12/563253496/week3_file_download/src/com/coderising/download/api/ConnectionManager.java b/group12/563253496/week3_file_download/src/com/coderising/download/api/ConnectionManager.java new file mode 100644 index 0000000000..ce045393b1 --- /dev/null +++ b/group12/563253496/week3_file_download/src/com/coderising/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/group12/563253496/week3_file_download/src/com/coderising/download/api/DownloadListener.java b/group12/563253496/week3_file_download/src/com/coderising/download/api/DownloadListener.java new file mode 100644 index 0000000000..bf9807b307 --- /dev/null +++ b/group12/563253496/week3_file_download/src/com/coderising/download/api/DownloadListener.java @@ -0,0 +1,5 @@ +package com.coderising.download.api; + +public interface DownloadListener { + public void notifyFinished(); +} diff --git a/group12/563253496/week3_file_download/src/com/coderising/download/impl/ConnectionImpl.java b/group12/563253496/week3_file_download/src/com/coderising/download/impl/ConnectionImpl.java new file mode 100644 index 0000000000..37b413558d --- /dev/null +++ b/group12/563253496/week3_file_download/src/com/coderising/download/impl/ConnectionImpl.java @@ -0,0 +1,73 @@ +package com.coderising.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.net.URLConnection; +import java.util.Arrays; + +import com.coderising.download.api.Connection; + +public class ConnectionImpl implements Connection { + + static final int BUFFER_SIZE = 1024; + URL url; + + ConnectionImpl(String _url) { + try { + url = new URL(_url); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + } + + + @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[] buffer = new byte[BUFFER_SIZE]; + int totalLen = endPos - startPos + 1; + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + while (baos.size() < totalLen) { + int len = is.read(buffer); + if (len < 0) { + break; + } + baos.write(buffer); + } + if (baos.size() > totalLen) { + byte[] temp = baos.toByteArray(); + return Arrays.copyOf(temp, totalLen); + } + return baos.toByteArray(); + + + } + + @Override + public int getContentLength() { + try { + URLConnection conn = url.openConnection(); + return conn.getContentLength(); + } catch (IOException e) { + e.printStackTrace(); + } + return -1; + + + } + + @Override + public void close() { + + + } + +} diff --git a/group12/563253496/week3_file_download/src/com/coderising/download/impl/ConnectionManagerImpl.java b/group12/563253496/week3_file_download/src/com/coderising/download/impl/ConnectionManagerImpl.java new file mode 100644 index 0000000000..f4a83cdbf6 --- /dev/null +++ b/group12/563253496/week3_file_download/src/com/coderising/download/impl/ConnectionManagerImpl.java @@ -0,0 +1,15 @@ +package com.coderising.download.impl; + +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); + //return null; + } + +} diff --git a/group12/563253496/week3_file_download/src/com/coderising/litestruts/LoginAction.java b/group12/563253496/week3_file_download/src/com/coderising/litestruts/LoginAction.java new file mode 100644 index 0000000000..dcdbe226ed --- /dev/null +++ b/group12/563253496/week3_file_download/src/com/coderising/litestruts/LoginAction.java @@ -0,0 +1,39 @@ +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/group12/563253496/week3_file_download/src/com/coderising/litestruts/Struts.java b/group12/563253496/week3_file_download/src/com/coderising/litestruts/Struts.java new file mode 100644 index 0000000000..85e2e22de3 --- /dev/null +++ b/group12/563253496/week3_file_download/src/com/coderising/litestruts/Struts.java @@ -0,0 +1,34 @@ +package com.coderising.litestruts; + +import java.util.Map; + + + +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字段中。 + + */ + + return null; + } + +} diff --git a/group12/563253496/week3_file_download/src/com/coderising/litestruts/StrutsTest.java b/group12/563253496/week3_file_download/src/com/coderising/litestruts/StrutsTest.java new file mode 100644 index 0000000000..b8c81faf3c --- /dev/null +++ b/group12/563253496/week3_file_download/src/com/coderising/litestruts/StrutsTest.java @@ -0,0 +1,43 @@ +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/group12/563253496/week3_file_download/src/com/coderising/litestruts/View.java b/group12/563253496/week3_file_download/src/com/coderising/litestruts/View.java new file mode 100644 index 0000000000..07df2a5dab --- /dev/null +++ b/group12/563253496/week3_file_download/src/com/coderising/litestruts/View.java @@ -0,0 +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; + } +} diff --git a/group12/563253496/week3_file_download/src/com/coding/basic/ArrayList.java b/group12/563253496/week3_file_download/src/com/coding/basic/ArrayList.java new file mode 100644 index 0000000000..1f185736f9 --- /dev/null +++ b/group12/563253496/week3_file_download/src/com/coding/basic/ArrayList.java @@ -0,0 +1,32 @@ +package com.coding.basic; + +public class ArrayList implements List { + + private int size = 0; + + private Object[] elementData = new Object[100]; + + 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 Iterator iterator(){ + return null; + } + +} diff --git a/group12/563253496/week3_file_download/src/com/coding/basic/BinaryTreeNode.java b/group12/563253496/week3_file_download/src/com/coding/basic/BinaryTreeNode.java new file mode 100644 index 0000000000..d7ac820192 --- /dev/null +++ b/group12/563253496/week3_file_download/src/com/coding/basic/BinaryTreeNode.java @@ -0,0 +1,32 @@ +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; + } + + public BinaryTreeNode insert(Object o){ + return null; + } + +} diff --git a/group12/563253496/week3_file_download/src/com/coding/basic/Iterator.java b/group12/563253496/week3_file_download/src/com/coding/basic/Iterator.java new file mode 100644 index 0000000000..06ef6311b2 --- /dev/null +++ b/group12/563253496/week3_file_download/src/com/coding/basic/Iterator.java @@ -0,0 +1,7 @@ +package com.coding.basic; + +public interface Iterator { + public boolean hasNext(); + public Object next(); + +} diff --git a/group12/563253496/week3_file_download/src/com/coding/basic/LinkedList.java b/group12/563253496/week3_file_download/src/com/coding/basic/LinkedList.java new file mode 100644 index 0000000000..4fdb03db8a --- /dev/null +++ b/group12/563253496/week3_file_download/src/com/coding/basic/LinkedList.java @@ -0,0 +1,124 @@ +package com.coding.basic; + + + +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){ + + } + /** + * 假定当前链表和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/group12/563253496/week3_file_download/src/com/coding/basic/List.java b/group12/563253496/week3_file_download/src/com/coding/basic/List.java new file mode 100644 index 0000000000..10d13b5832 --- /dev/null +++ b/group12/563253496/week3_file_download/src/com/coding/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/group12/563253496/week3_file_download/src/com/coding/basic/Queue.java b/group12/563253496/week3_file_download/src/com/coding/basic/Queue.java new file mode 100644 index 0000000000..36e516e266 --- /dev/null +++ b/group12/563253496/week3_file_download/src/com/coding/basic/Queue.java @@ -0,0 +1,19 @@ +package com.coding.basic; + +public class Queue { + + public void enQueue(Object o){ + } + + public Object deQueue(){ + return null; + } + + public boolean isEmpty(){ + return false; + } + + public int size(){ + return -1; + } +} diff --git a/group12/563253496/week3_file_download/src/com/coding/basic/Stack.java b/group12/563253496/week3_file_download/src/com/coding/basic/Stack.java new file mode 100644 index 0000000000..a5a04de76d --- /dev/null +++ b/group12/563253496/week3_file_download/src/com/coding/basic/Stack.java @@ -0,0 +1,22 @@ +package com.coding.basic; + +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; + } +} From 6c48050319e9645d9cdeecd63700ddd6a2093e3b Mon Sep 17 00:00:00 2001 From: maishihang <446031103@qq.com> Date: Thu, 23 Mar 2017 23:04:00 +0800 Subject: [PATCH 034/287] update 2 weekWork update 2 weekWork --- .../coderising/litestruts/Configuration.java | 91 +++++++++++++++ .../litestruts/ConfigurationTest.java | 39 +++++++ .../coderising/litestruts/LoginAction.java | 3 - .../coderising/litestruts/ReflectionUtil.java | 75 ++++++++++++ .../litestruts/ReflectionUtilTest.java | 96 +++++++++++++++ .../src/com/coderising/litestruts/Struts.java | 109 +++++------------- 6 files changed, 331 insertions(+), 82 deletions(-) create mode 100644 group12/446031103/src/com/coderising/litestruts/Configuration.java create mode 100644 group12/446031103/src/com/coderising/litestruts/ConfigurationTest.java create mode 100644 group12/446031103/src/com/coderising/litestruts/ReflectionUtil.java create mode 100644 group12/446031103/src/com/coderising/litestruts/ReflectionUtilTest.java diff --git a/group12/446031103/src/com/coderising/litestruts/Configuration.java b/group12/446031103/src/com/coderising/litestruts/Configuration.java new file mode 100644 index 0000000000..1df7369eff --- /dev/null +++ b/group12/446031103/src/com/coderising/litestruts/Configuration.java @@ -0,0 +1,91 @@ +package com.coderising.litestruts; + +import java.io.InputStream; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.Element; +import org.dom4j.io.SAXReader; + +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); + } + + + + private void parseXML(InputStream is) { + SAXReader reader = new SAXReader(); + try { + Document document = reader.read(is); + Element struts = document.getRootElement(); + Iterator actions = struts.elementIterator(); + while (actions.hasNext()) { + Element action = (Element) actions.next(); + String actionName=action.attributeValue("name"); + String actionClass=action.attributeValue("class"); + ActionConfig ac = new ActionConfig(actionName,actionClass); + Iterator results = action.elementIterator(); + while (results.hasNext()) { + Element result = (Element) results.next(); + String name = result.attributeValue("name"); + String viewName = result.getStringValue(); + ac.addViewResult(name, viewName); + } + this.actions.put(actionName, ac); + } + } catch (DocumentException e) { + + e.printStackTrace(); + } + + } + + + + public String getClassName(String actionName) { + ActionConfig actionConfig = actions.get(actionName); + if(null==actionConfig) + return null; + return actionConfig.getClassName(); + } + + public String getResultView(String actionName, String resultName) { + ActionConfig actionConfig =actions.get(actionName); + if(null==actionConfig) + return null; + return actionConfig.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/group12/446031103/src/com/coderising/litestruts/ConfigurationTest.java b/group12/446031103/src/com/coderising/litestruts/ConfigurationTest.java new file mode 100644 index 0000000000..f4af430eef --- /dev/null +++ b/group12/446031103/src/com/coderising/litestruts/ConfigurationTest.java @@ -0,0 +1,39 @@ +package com.coderising.litestruts; + + + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class ConfigurationTest { + Configuration cfg = new Configuration("struts.xml"); + @Before + public void setUp() throws Exception { + } + + @After + 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"); + 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/group12/446031103/src/com/coderising/litestruts/LoginAction.java b/group12/446031103/src/com/coderising/litestruts/LoginAction.java index 39af2d5c26..dcdbe226ed 100644 --- a/group12/446031103/src/com/coderising/litestruts/LoginAction.java +++ b/group12/446031103/src/com/coderising/litestruts/LoginAction.java @@ -36,7 +36,4 @@ public void setPassword(String password){ public String getMessage(){ return this.message; } - public void setMessage(String message){ - this.message = message; - } } diff --git a/group12/446031103/src/com/coderising/litestruts/ReflectionUtil.java b/group12/446031103/src/com/coderising/litestruts/ReflectionUtil.java new file mode 100644 index 0000000000..c9bbd312ef --- /dev/null +++ b/group12/446031103/src/com/coderising/litestruts/ReflectionUtil.java @@ -0,0 +1,75 @@ +package com.coderising.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) { + + return getMethods(clz,"set"); + } + + public static List getGetterMethods(Class clz) { + return getMethods(clz,"get"); + } + + public static List getMethods(Class clz,String startsWithName) { + List methods = new ArrayList<>(); + for (Method method : clz.getDeclaredMethods()) { + if(method.getName().startsWith(startsWithName)){ + methods.add(method); + } + } + return methods; + } + + public static void setParams(Object o, Map params) { + List methods = getSetterMethods(o.getClass()); + for (String name : params.keySet()) { + String methodName = "set"+name; + for (Method method : methods) { + if(methodName.equalsIgnoreCase(method.getName())){ + try { + method.invoke(o, params.get(name)); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + }; + } + + } + } + + public static Map getParams(Object o) { + Map params = new HashMap<>(); + List methods = getGetterMethods(o.getClass()); + for (Method method : methods) { + try { + String name=method.getName(); + name = name.replaceFirst("get", "").toLowerCase(); + Object value = method.invoke(o); + params.put(name, value); + } catch (IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + return params; + } + +} diff --git a/group12/446031103/src/com/coderising/litestruts/ReflectionUtilTest.java b/group12/446031103/src/com/coderising/litestruts/ReflectionUtilTest.java new file mode 100644 index 0000000000..f1b233be37 --- /dev/null +++ b/group12/446031103/src/com/coderising/litestruts/ReflectionUtilTest.java @@ -0,0 +1,96 @@ +package com.coderising.litestruts; + +import static org.junit.Assert.*; + +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.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class ReflectionUtilTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testGetSetterMethod() throws ClassNotFoundException { + String name = "com.coderising.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 ClassNotFoundException { + String name = "com.coderising.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 testSetterParams() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException { + String name = "com.coderising.litestruts.LoginAction"; + Class clz = Class.forName(name); + Object o = clz.newInstance(); + + Map params = new HashMap(); + params.put("name","test"); + params.put("password","1234"); + ReflectionUtil.setParams(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 testGetterParams() throws ClassNotFoundException, InstantiationException, IllegalAccessException { + String name = "com.coderising.litestruts.LoginAction"; + Class clz = Class.forName(name); + LoginAction la = (LoginAction) clz.newInstance(); + la.setName("test"); + la.setPassword("123456"); + Map params =ReflectionUtil.getParams(la); + Assert.assertEquals(3, params.size()); + + Assert.assertEquals(null, params.get("messaage") ); + Assert.assertEquals("test", params.get("name") ); + Assert.assertEquals("123456", params.get("password") ); + } +} diff --git a/group12/446031103/src/com/coderising/litestruts/Struts.java b/group12/446031103/src/com/coderising/litestruts/Struts.java index 8f5913d836..c4466c1d02 100644 --- a/group12/446031103/src/com/coderising/litestruts/Struts.java +++ b/group12/446031103/src/com/coderising/litestruts/Struts.java @@ -9,6 +9,7 @@ import java.lang.reflect.Method; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; import org.dom4j.Document; @@ -24,92 +25,42 @@ * @version: V1.0 */ public class Struts { + private final static Configuration cfg = new Configuration("struts.xml"); public static View runAction(String actionName, Map parameters) { - Map xmlDoc = getXMLDOC(actionName); - Map viewMap = new HashMap(); - View view = new View(); - view.setParameters(viewMap); - try { - Class classz = Class.forName(xmlDoc.get(actionName)); - LoginAction la = (LoginAction) classz.newInstance(); - la.setName(parameters.get("name")); - la.setPassword(parameters.get("password")); - Method exectue = classz.getMethod("execute", null); - Object result = exectue.invoke(la, null); - Field[] fields = classz.getDeclaredFields(); - for (Field field : fields) { - PropertyDescriptor pd = new PropertyDescriptor(field.getName(), classz); - Method readMethod = pd.getReadMethod(); - viewMap.put(field.getName(), (String) readMethod.invoke(la, null)); - } - view.setJsp(xmlDoc.get(result)); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (SecurityException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (NoSuchMethodException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (InvocationTargetException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IntrospectionException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + /* - * 0. 读取配置文件struts.xml 1. 根据actionName找到相对应的class , 例如LoginAction, 通过反射实例化(创建对象), + * 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, + * 那就应该调用 setName和setPassword方法 + * 2. 通过反射调用对象的exectue 方法, 并获得返回值,例如"success" + * 3.通过反射找到对象的所有getter方法(例如 getMessage), 通过反射来调用, 把值和属性形成一个HashMap , 例如 {"message": "登录成功"} , + * 放到View对象的parameters + * 4. 根据struts.xml中的 配置,以及execute的返回值, 确定哪一个jsp, * 放到View对象的jsp字段中。 */ - return view; - } - /** - * @MethodName: getXMLDOC - * @Description: 解析xml文件 - * @param actionName - * @return - * @return: Map - */ - private static Map getXMLDOC(String actionName) { - Map xmldoc = new HashMap(); - // 解析struts.xml文件 - // 创建SAXReader的对象reader - SAXReader reader = new SAXReader(); + String className = cfg.getClassName(actionName); + try { - // 通过reader对象的read方法读取struts.xml,得到document对象 - Document document = reader.read(new File("src/com/coderising/litestruts/struts.xml")); - // 获取根节点 - Element struts = document.getRootElement(); - // 迭代节点 - Iterator actions = struts.elementIterator(); - while (actions.hasNext()) { - Element action = (Element) actions.next(); - if (actionName.equals(action.attributeValue("name"))) { - xmldoc.put(action.attributeValue("name"), action.attributeValue("class")); - Iterator results = action.elementIterator(); - while (results.hasNext()) { - Element result = (Element) results.next(); - xmldoc.put(result.attributeValue("name"), result.getStringValue()); - } - break; - } - } - } catch (DocumentException e) { + Class clz = Class.forName(className); + Object o = clz.newInstance(); + ReflectionUtil.setParams(o, parameters); + Method exectue = clz.getDeclaredMethod("execute"); + String resultName=(String) exectue.invoke(o); + Map params = ReflectionUtil.getParams(o); + String resultView = cfg.getResultView(actionName, resultName); + View v = new View(); + v.setJsp(resultView); + v.setParameters(params); + return v; + } catch (Exception e) { + // TODO Auto-generated catch block e.printStackTrace(); - } - return xmldoc; + } + + + 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 035/287] =?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 036/287] 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 037/287] 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 038/287] 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ָ - // 2DownloadListener, Ƕ߳أĿͻ˲֪ʲôʱҪʵ̶ִֵ߳Ժ󣬵listenernotifiedFinishedͻ˾յ֪ͨ - // ʵ˼· - // 1. ҪConnectionManager open ӣȻͨ Connection.getContentLengthļij - // 2. 3߳أעÿ߳ҪȵConnectionManageropen - // Ȼ 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 039/287] 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ָ + // 2DownloadListener, Ƕ߳أĿͻ˲֪ʲôʱҪʵ̶ִֵ߳Ժ󣬵listenernotifiedFinishedͻ˾յ֪ͨ + // ʵ˼· + // 1. ҪConnectionManager open ӣȻͨ Connection.getContentLengthļij + // 2. 3߳أעÿ߳ҪȵConnectionManageropen + // Ȼ 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 040/287] =?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 041/287] 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 3a4f31676698ba17929f5e019ac4e48eb91000ea Mon Sep 17 00:00:00 2001 From: qilei Date: Sun, 26 Mar 2017 18:00:40 +0800 Subject: [PATCH 042/287] =?UTF-8?q?=E5=AE=8C=E5=96=84=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 --- group04/916758663/learn01/learn01.iml | 2 +- group04/916758663/learn03/pom.xml | 32 ++++++++ .../com/example/download/DownloadThread.java | 50 ++++++++++++ .../com/example/download/FileDownloader.java | 76 +++++++++++++++++++ .../main/java/com/example/download/Utils.java | 24 ++++++ .../com/example/download/api/Connection.java | 23 ++++++ .../download/api/ConnectionException.java | 5 ++ .../download/api/ConnectionManager.java | 10 +++ .../download/api/DownloadListener.java | 5 ++ .../example/download/impl/ConnectionImpl.java | 58 ++++++++++++++ .../download/impl/ConnectionManagerImpl.java | 16 ++++ .../example/download/FileDownloaderTest.java | 57 ++++++++++++++ .../java/com/example/download/UtilsTest.java | 31 ++++++++ .../download/impl/ConnectionImplTest.java | 49 ++++++++++++ 14 files changed, 437 insertions(+), 1 deletion(-) create mode 100644 group04/916758663/learn03/pom.xml create mode 100644 group04/916758663/learn03/src/main/java/com/example/download/DownloadThread.java create mode 100644 group04/916758663/learn03/src/main/java/com/example/download/FileDownloader.java create mode 100644 group04/916758663/learn03/src/main/java/com/example/download/Utils.java create mode 100644 group04/916758663/learn03/src/main/java/com/example/download/api/Connection.java create mode 100644 group04/916758663/learn03/src/main/java/com/example/download/api/ConnectionException.java create mode 100644 group04/916758663/learn03/src/main/java/com/example/download/api/ConnectionManager.java create mode 100644 group04/916758663/learn03/src/main/java/com/example/download/api/DownloadListener.java create mode 100644 group04/916758663/learn03/src/main/java/com/example/download/impl/ConnectionImpl.java create mode 100644 group04/916758663/learn03/src/main/java/com/example/download/impl/ConnectionManagerImpl.java create mode 100644 group04/916758663/learn03/src/test/java/com/example/download/FileDownloaderTest.java create mode 100644 group04/916758663/learn03/src/test/java/com/example/download/UtilsTest.java create mode 100644 group04/916758663/learn03/src/test/java/com/example/download/impl/ConnectionImplTest.java diff --git a/group04/916758663/learn01/learn01.iml b/group04/916758663/learn01/learn01.iml index 6e0c17c683..97c857d442 100644 --- a/group04/916758663/learn01/learn01.iml +++ b/group04/916758663/learn01/learn01.iml @@ -1,6 +1,6 @@ - + diff --git a/group04/916758663/learn03/pom.xml b/group04/916758663/learn03/pom.xml new file mode 100644 index 0000000000..82848b035e --- /dev/null +++ b/group04/916758663/learn03/pom.xml @@ -0,0 +1,32 @@ + + 4.0.0 + + com.example + download + 1.0-SNAPSHOT + jar + + download + http://maven.apache.org + + + UTF-8 + + + + + junit + junit + 4.12 + test + + + + org.assertj + assertj-core + 3.6.2 + test + + + diff --git a/group04/916758663/learn03/src/main/java/com/example/download/DownloadThread.java b/group04/916758663/learn03/src/main/java/com/example/download/DownloadThread.java new file mode 100644 index 0000000000..6239bc13d2 --- /dev/null +++ b/group04/916758663/learn03/src/main/java/com/example/download/DownloadThread.java @@ -0,0 +1,50 @@ +package com.example.download; + + +import com.example.download.api.Connection; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +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 file; + CountDownLatch latch; + + public DownloadThread( Connection conn, int startPos, int endPos,String file,CountDownLatch latch){ + + this.conn = conn; + this.startPos = startPos; + this.endPos = endPos; + this.file = file; + this.latch = latch; + } + public void run(){ + RandomAccessFile randomAccessFile = null; + try { + byte[] data = conn.read(startPos, endPos); + randomAccessFile = new RandomAccessFile(file, "rw"); + randomAccessFile.seek(startPos); + randomAccessFile.write(data); + latch.countDown(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + }finally { + try { + if (randomAccessFile != null) { + randomAccessFile.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + conn.close(); + } + } +} diff --git a/group04/916758663/learn03/src/main/java/com/example/download/FileDownloader.java b/group04/916758663/learn03/src/main/java/com/example/download/FileDownloader.java new file mode 100644 index 0000000000..743955e329 --- /dev/null +++ b/group04/916758663/learn03/src/main/java/com/example/download/FileDownloader.java @@ -0,0 +1,76 @@ +package com.example.download; + + +import com.example.download.api.Connection; +import com.example.download.api.ConnectionException; +import com.example.download.api.ConnectionManager; +import com.example.download.api.DownloadListener; +import java.util.concurrent.CountDownLatch; + +public class FileDownloader { + + String url; + + String localFile; + + DownloadListener listener; + + ConnectionManager cm; + + private CountDownLatch latch = new CountDownLatch(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方法 + + // 下面的代码是示例代码, 也就是说只有一个线程, 你需要改造成多线程的。 + Connection conn = null; + try { + conn = cm.open(this.url); + int length = conn.getContentLength(); + int[][] array = Utils.split(length, 3); + for (int i = 0; i < 3; i++) { + new DownloadThread(conn,array[i][0],array[i][1],localFile,latch).start(); + } + + latch.await(); + + this.getListener().notifyFinished(); + + } catch (ConnectionException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally{ + } + + } + + 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/group04/916758663/learn03/src/main/java/com/example/download/Utils.java b/group04/916758663/learn03/src/main/java/com/example/download/Utils.java new file mode 100644 index 0000000000..521583d7e5 --- /dev/null +++ b/group04/916758663/learn03/src/main/java/com/example/download/Utils.java @@ -0,0 +1,24 @@ +package com.example.download; + +/** + * Created by qilei on 17/3/26. + */ +public class Utils { + + public static int[][] split(int len, int count) { + int[][] result = new int[count][2]; + int baseLen = (int)Math.ceil(((double)len / count)); + for (int i = 0; i < count; i++) { + int startPos = baseLen * i ; + int endPos = baseLen * (i + 1) -1; + if (i == count - 1) { + if (endPos > len - 1) { + endPos = len - 1; + } + } + result[i][0] = startPos; + result[i][1] = endPos; + } + return result; + } +} diff --git a/group04/916758663/learn03/src/main/java/com/example/download/api/Connection.java b/group04/916758663/learn03/src/main/java/com/example/download/api/Connection.java new file mode 100644 index 0000000000..d3906b1859 --- /dev/null +++ b/group04/916758663/learn03/src/main/java/com/example/download/api/Connection.java @@ -0,0 +1,23 @@ +package com.example.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/group04/916758663/learn03/src/main/java/com/example/download/api/ConnectionException.java b/group04/916758663/learn03/src/main/java/com/example/download/api/ConnectionException.java new file mode 100644 index 0000000000..ffbd61ec31 --- /dev/null +++ b/group04/916758663/learn03/src/main/java/com/example/download/api/ConnectionException.java @@ -0,0 +1,5 @@ +package com.example.download.api; + +public class ConnectionException extends Exception { + +} diff --git a/group04/916758663/learn03/src/main/java/com/example/download/api/ConnectionManager.java b/group04/916758663/learn03/src/main/java/com/example/download/api/ConnectionManager.java new file mode 100644 index 0000000000..1888a879ef --- /dev/null +++ b/group04/916758663/learn03/src/main/java/com/example/download/api/ConnectionManager.java @@ -0,0 +1,10 @@ +package com.example.download.api; + +public interface ConnectionManager { + /** + * 给定一个url , 打开一个连接 + * @param url + * @return + */ + public Connection open(String url) throws ConnectionException; +} diff --git a/group04/916758663/learn03/src/main/java/com/example/download/api/DownloadListener.java b/group04/916758663/learn03/src/main/java/com/example/download/api/DownloadListener.java new file mode 100644 index 0000000000..9cc73ddee6 --- /dev/null +++ b/group04/916758663/learn03/src/main/java/com/example/download/api/DownloadListener.java @@ -0,0 +1,5 @@ +package com.example.download.api; + +public interface DownloadListener { + public void notifyFinished(); +} diff --git a/group04/916758663/learn03/src/main/java/com/example/download/impl/ConnectionImpl.java b/group04/916758663/learn03/src/main/java/com/example/download/impl/ConnectionImpl.java new file mode 100644 index 0000000000..62ee66f1c5 --- /dev/null +++ b/group04/916758663/learn03/src/main/java/com/example/download/impl/ConnectionImpl.java @@ -0,0 +1,58 @@ +package com.example.download.impl; + +import com.example.download.api.Connection; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; + + +public class ConnectionImpl implements Connection { + + private URL url; + + ConnectionImpl(String urlStr){ + try { + url = new URL(urlStr); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + } + + @Override + public byte[] read(int startPos, int endPos) throws IOException { + URLConnection urlConnection = url.openConnection(); + urlConnection.setRequestProperty("Range", "bytes=" + startPos + "-" + + endPos); + InputStream inputStream = urlConnection.getInputStream(); + int len = endPos + 1 - startPos; + int bytesRead = 0; + byte[] buffer = new byte[len]; + while (bytesRead < len) { + int result = inputStream.read(buffer, bytesRead, len - bytesRead); + if (result == -1){ + break; + } + bytesRead += result; + } + inputStream.close(); + return buffer; + } + + @Override + public int getContentLength() { + try { + URLConnection urlConnection = url.openConnection(); + return urlConnection.getContentLength(); + } catch (IOException e) { + e.printStackTrace(); + } + return -1; + } + + @Override + public void close() { + } + +} diff --git a/group04/916758663/learn03/src/main/java/com/example/download/impl/ConnectionManagerImpl.java b/group04/916758663/learn03/src/main/java/com/example/download/impl/ConnectionManagerImpl.java new file mode 100644 index 0000000000..d346c4d350 --- /dev/null +++ b/group04/916758663/learn03/src/main/java/com/example/download/impl/ConnectionManagerImpl.java @@ -0,0 +1,16 @@ +package com.example.download.impl; + + +import com.example.download.api.Connection; +import com.example.download.api.ConnectionException; +import com.example.download.api.ConnectionManager; + +public class ConnectionManagerImpl implements ConnectionManager { + + @Override + public Connection open(String url) throws ConnectionException { + Connection conn = new ConnectionImpl(url); + return conn; + } + +} diff --git a/group04/916758663/learn03/src/test/java/com/example/download/FileDownloaderTest.java b/group04/916758663/learn03/src/test/java/com/example/download/FileDownloaderTest.java new file mode 100644 index 0000000000..7dbeffd108 --- /dev/null +++ b/group04/916758663/learn03/src/test/java/com/example/download/FileDownloaderTest.java @@ -0,0 +1,57 @@ +package com.example.download; + + +import com.example.download.api.ConnectionManager; +import com.example.download.api.DownloadListener; +import com.example.download.impl.ConnectionManagerImpl; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Created by qilei on 17/3/14. + */ +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 file = "/Users/qilei/tmp/tmp.jpg"; + FileDownloader downloader = new FileDownloader(url,file); + + 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("下载完成!"); + } + +} \ No newline at end of file diff --git a/group04/916758663/learn03/src/test/java/com/example/download/UtilsTest.java b/group04/916758663/learn03/src/test/java/com/example/download/UtilsTest.java new file mode 100644 index 0000000000..ff41d07731 --- /dev/null +++ b/group04/916758663/learn03/src/test/java/com/example/download/UtilsTest.java @@ -0,0 +1,31 @@ +package com.example.download; + +import org.junit.Test; +import static org.assertj.core.api.Assertions.*; + +/** + * Created by qilei on 17/3/26. + */ +public class UtilsTest { + + @Test + public void testSplit(){ + int len = 10; + + int[][] result = Utils.split(10,3); + + assertThat(result[0][0]).isEqualTo(0); + assertThat(result[0][1]).isEqualTo(3); + assertThat(result[2][0]).isEqualTo(8); + assertThat(result[2][1]).isEqualTo(9); + } + + @Test + public void testMath(){ + double a = Math.ceil((double)10 / 3); + double b = Math.floor((double)10 / 3); + System.out.println(""); + + } + +} diff --git a/group04/916758663/learn03/src/test/java/com/example/download/impl/ConnectionImplTest.java b/group04/916758663/learn03/src/test/java/com/example/download/impl/ConnectionImplTest.java new file mode 100644 index 0000000000..7b21df4109 --- /dev/null +++ b/group04/916758663/learn03/src/test/java/com/example/download/impl/ConnectionImplTest.java @@ -0,0 +1,49 @@ +package com.example.download.impl; + +import static org.assertj.core.api.Assertions.*; + +import com.example.download.api.Connection; +import com.example.download.api.ConnectionException; +import com.example.download.api.ConnectionManager; +import org.junit.Before; +import org.junit.Test; + +/** + * Created by qilei on 17/3/24. + */ +public class ConnectionImplTest { + + private Connection connection; + + @Before + public void setup(){ + ConnectionManager cm = new ConnectionManagerImpl(); + String url ="http://www.hinews.cn/pic/0/13/91/26/13912621_821796.jpg"; + try { + connection = cm.open(url); + } catch (ConnectionException e) { + e.printStackTrace(); + } + } + + @Test + public void read() throws Exception { + byte[] data = null; + data = connection.read(0, 35469); + assertThat(data.length).isEqualTo(35470); + + data = connection.read(0, 1023); + assertThat(data.length).isEqualTo(1024); + + data = connection.read(1024, 2023); + assertThat(data.length).isEqualTo(1000); + + } + + @Test + public void getContentLength() throws Exception { + int contentLength = connection.getContentLength(); + assertThat(contentLength).isEqualTo(35470); + } + +} \ 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 043/287] =?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 044/287] 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 710ed8809cd56827752dd4a3aae93e40fd839265 Mon Sep 17 00:00:00 2001 From: hejj <844028312@qq.com> Date: Mon, 27 Mar 2017 09:42:10 +0800 Subject: [PATCH 045/287] =?UTF-8?q?=E7=AC=AC=E4=B8=89=E6=AC=A1=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group04/844028312/three/.classpath | 7 + group04/844028312/three/.gitignore | 1 + group04/844028312/three/.project | 17 + .../.settings/org.eclipse.jdt.core.prefs | 12 + .../src/com/coderising/array/ArrayUtil.java | 96 ++++ .../coderising/download/DownloadThread.java | 48 ++ .../coderising/download/FileDownloader.java | 86 ++++ .../download/FileDownloaderTest.java | 115 +++++ .../coderising/download/api/Connection.java | 23 + .../download/api/ConnectionException.java | 5 + .../download/api/ConnectionManager.java | 10 + .../download/api/DownloadListener.java | 5 + .../download/impl/ConnectionImpl.java | 54 +++ .../download/impl/ConnectionManagerImpl.java | 33 ++ .../coderising/litestruts/LoginAction.java | 39 ++ .../src/com/coderising/litestruts/Struts.java | 37 ++ .../com/coderising/litestruts/StrutsTest.java | 43 ++ .../src/com/coderising/litestruts/View.java | 23 + .../src/com/coderising/litestruts/struts.xml | 11 + .../three/src/com/coding/basic/ArrayList.java | 32 ++ .../src/com/coding/basic/BinaryTreeNode.java | 32 ++ .../three/src/com/coding/basic/Iterator.java | 7 + .../src/com/coding/basic/LinkedList.java | 417 ++++++++++++++++++ .../src/com/coding/basic/LinkedListTest.java | 145 ++++++ .../three/src/com/coding/basic/List.java | 9 + .../three/src/com/coding/basic/Queue.java | 19 + .../three/src/com/coding/basic/Stack.java | 22 + 27 files changed, 1348 insertions(+) create mode 100644 group04/844028312/three/.classpath create mode 100644 group04/844028312/three/.gitignore create mode 100644 group04/844028312/three/.project create mode 100644 group04/844028312/three/.settings/org.eclipse.jdt.core.prefs create mode 100644 group04/844028312/three/src/com/coderising/array/ArrayUtil.java create mode 100644 group04/844028312/three/src/com/coderising/download/DownloadThread.java create mode 100644 group04/844028312/three/src/com/coderising/download/FileDownloader.java create mode 100644 group04/844028312/three/src/com/coderising/download/FileDownloaderTest.java create mode 100644 group04/844028312/three/src/com/coderising/download/api/Connection.java create mode 100644 group04/844028312/three/src/com/coderising/download/api/ConnectionException.java create mode 100644 group04/844028312/three/src/com/coderising/download/api/ConnectionManager.java create mode 100644 group04/844028312/three/src/com/coderising/download/api/DownloadListener.java create mode 100644 group04/844028312/three/src/com/coderising/download/impl/ConnectionImpl.java create mode 100644 group04/844028312/three/src/com/coderising/download/impl/ConnectionManagerImpl.java create mode 100644 group04/844028312/three/src/com/coderising/litestruts/LoginAction.java create mode 100644 group04/844028312/three/src/com/coderising/litestruts/Struts.java create mode 100644 group04/844028312/three/src/com/coderising/litestruts/StrutsTest.java create mode 100644 group04/844028312/three/src/com/coderising/litestruts/View.java create mode 100644 group04/844028312/three/src/com/coderising/litestruts/struts.xml create mode 100644 group04/844028312/three/src/com/coding/basic/ArrayList.java create mode 100644 group04/844028312/three/src/com/coding/basic/BinaryTreeNode.java create mode 100644 group04/844028312/three/src/com/coding/basic/Iterator.java create mode 100644 group04/844028312/three/src/com/coding/basic/LinkedList.java create mode 100644 group04/844028312/three/src/com/coding/basic/LinkedListTest.java create mode 100644 group04/844028312/three/src/com/coding/basic/List.java create mode 100644 group04/844028312/three/src/com/coding/basic/Queue.java create mode 100644 group04/844028312/three/src/com/coding/basic/Stack.java diff --git a/group04/844028312/three/.classpath b/group04/844028312/three/.classpath new file mode 100644 index 0000000000..3e0fb272a8 --- /dev/null +++ b/group04/844028312/three/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/group04/844028312/three/.gitignore b/group04/844028312/three/.gitignore new file mode 100644 index 0000000000..ae3c172604 --- /dev/null +++ b/group04/844028312/three/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/group04/844028312/three/.project b/group04/844028312/three/.project new file mode 100644 index 0000000000..64a356de63 --- /dev/null +++ b/group04/844028312/three/.project @@ -0,0 +1,17 @@ + + + coding2017 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/group04/844028312/three/.settings/org.eclipse.jdt.core.prefs b/group04/844028312/three/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..d17b6724d1 --- /dev/null +++ b/group04/844028312/three/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,12 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/group04/844028312/three/src/com/coderising/array/ArrayUtil.java b/group04/844028312/three/src/com/coderising/array/ArrayUtil.java new file mode 100644 index 0000000000..e5ddb476a6 --- /dev/null +++ b/group04/844028312/three/src/com/coderising/array/ArrayUtil.java @@ -0,0 +1,96 @@ +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 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){ + return null; + } + + /** + * 给定两个已经排序好的整形数组, 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){ + return null; + } + /** + * 把一个已经存满数据的数组 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){ + return null; + } + + /** + * 斐波那契数列为: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){ + return null; + } + + /** + * 返回小于给定最大值max的所有素数数组 + * 例如max = 23, 返回的数组为[2,3,5,7,11,13,17,19] + * @param max + * @return + */ + public int[] getPrimes(int max){ + return null; + } + + /** + * 所谓“完数”, 是指这个数恰好等于它的因子之和,例如6=1+2+3 + * 给定一个最大值max, 返回一个数组, 数组中是小于max 的所有完数 + * @param max + * @return + */ + public int[] getPerfectNumbers(int max){ + return null; + } + + /** + * 用seperator 把数组 array给连接起来 + * 例如array= [3,8,9], seperator = "-" + * 则返回值为"3-8-9" + * @param array + * @param s + * @return + */ + public String join(int[] array, String seperator){ + return null; + } + + +} diff --git a/group04/844028312/three/src/com/coderising/download/DownloadThread.java b/group04/844028312/three/src/com/coderising/download/DownloadThread.java new file mode 100644 index 0000000000..580da85576 --- /dev/null +++ b/group04/844028312/three/src/com/coderising/download/DownloadThread.java @@ -0,0 +1,48 @@ +package com.coderising.download; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +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.impl.ConnectionManagerImpl; + +public class DownloadThread extends Thread{ + + Connection conn; + int startPos; + int endPos; + CyclicBarrier barrier; + String url; + public DownloadThread(CyclicBarrier barrier, String url, int startPos, int endPos){ + this.barrier=barrier; + //this.conn = conn; + this.startPos = startPos; + this.endPos = endPos; + this.url=url; + } + public void run(){ + try { + ConnectionManager cm = new ConnectionManagerImpl(); + conn=cm.open(url); + + byte[] b=conn.read(startPos, endPos); + + RandomAccessFile randomFile = new RandomAccessFile("D://test.zip", "rw"); + write(randomFile,b); + barrier.await(); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + public synchronized void write(RandomAccessFile randomFile ,byte[] b) throws IOException{ + randomFile.seek(startPos); + randomFile.write(b); + randomFile.close(); + } +} diff --git a/group04/844028312/three/src/com/coderising/download/FileDownloader.java b/group04/844028312/three/src/com/coderising/download/FileDownloader.java new file mode 100644 index 0000000000..9d81ef03be --- /dev/null +++ b/group04/844028312/three/src/com/coderising/download/FileDownloader.java @@ -0,0 +1,86 @@ +package com.coderising.download; + +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; + + +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 { + + + CyclicBarrier cb = new CyclicBarrier(4, new Runnable() { + @Override + public void run() { + // TODO Auto-generated method stub + listener.notifyFinished(); + + } + }); + conn=cm.open(url); + int length = conn.getContentLength(); + new DownloadThread(cb,url,0,length/4).start(); + new DownloadThread(cb,url,length/4+1,(length/4)*2).start(); + new DownloadThread(cb,url,(length/4)*2+1,(length/4)*3).start(); + new DownloadThread(cb,url,(length/4)*3+1,length-1).start(); + + + } catch (Exception 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/group04/844028312/three/src/com/coderising/download/FileDownloaderTest.java b/group04/844028312/three/src/com/coderising/download/FileDownloaderTest.java new file mode 100644 index 0000000000..b1cc492c33 --- /dev/null +++ b/group04/844028312/three/src/com/coderising/download/FileDownloaderTest.java @@ -0,0 +1,115 @@ +package com.coderising.download; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadPoolExecutor; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +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 FileDownloaderTest { + boolean downloadFinished = false; + private static Integer pages=1; // 网页数 + + private static boolean exeFlag=true; // 执行标识 + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testDownload() { + + String url="http://mirrors.hust.edu.cn/apache/tomcat/tomcat-8/v8.0.41/bin/apache-tomcat-8.0.41-windows-x64.zip"; + 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 (Exception e) { + e.printStackTrace(); + } + } + System.out.println("下载完成!"); + + + + } + + //http://image.so.com/v?ie=utf-8&src=hao_360so&q=%E9%AB%98%E5%9C%86%E5%9C%86&correct=%E9%AB%98%E5%9C%86%E5%9C%86&fromurl=http%3A%2F%2Fwww.cesiu.org.cn%2Fomdsj%2F2010674.html&gsrc=1#multiple=0&dataindex=57&id=537876d111c8adfec7fbda2b80a4f67b + @Test + public void testOpen() throws ConnectionException { + + + + ExecutorService executorService=Executors.newFixedThreadPool(10); // 创建ExecutorService 连接池创建固定的10个初始线程 + + while(exeFlag){ + if(pages<=100){ +// executorService.execute(new Runnable(){ +// +// @Override +// public void run() { +// // TODO Auto-generated method stub +// System.out.println(Thread.currentThread().getName()); +// System.out.println("爬取了第"+pages+"网页..."); +// pages++; +// } +// +// }); + new Runnable(){ + + @Override + public void run() { + // TODO Auto-generated method stub + System.out.println(Thread.currentThread().getName()); + System.out.println("爬取了第"+pages+"网页..."); + pages++; + } + + }.run();; + + }else{ + if(((ThreadPoolExecutor)executorService).getActiveCount()==0){ // 活动线程是0 + executorService.shutdown(); // 结束所有线程 + exeFlag=false; + System.out.println("爬虫任务已经完成"); + } + } + try { + // Thread.sleep(2000); // 线程休息0.1秒 + } catch (Exception e) { + e.printStackTrace(); + } + + } + + } +} diff --git a/group04/844028312/three/src/com/coderising/download/api/Connection.java b/group04/844028312/three/src/com/coderising/download/api/Connection.java new file mode 100644 index 0000000000..0957eaf7f4 --- /dev/null +++ b/group04/844028312/three/src/com/coderising/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/group04/844028312/three/src/com/coderising/download/api/ConnectionException.java b/group04/844028312/three/src/com/coderising/download/api/ConnectionException.java new file mode 100644 index 0000000000..c3ed7396e7 --- /dev/null +++ b/group04/844028312/three/src/com/coderising/download/api/ConnectionException.java @@ -0,0 +1,5 @@ +package com.coderising.download.api; + +public class ConnectionException extends Exception { + +} diff --git a/group04/844028312/three/src/com/coderising/download/api/ConnectionManager.java b/group04/844028312/three/src/com/coderising/download/api/ConnectionManager.java new file mode 100644 index 0000000000..ce045393b1 --- /dev/null +++ b/group04/844028312/three/src/com/coderising/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/group04/844028312/three/src/com/coderising/download/api/DownloadListener.java b/group04/844028312/three/src/com/coderising/download/api/DownloadListener.java new file mode 100644 index 0000000000..bf9807b307 --- /dev/null +++ b/group04/844028312/three/src/com/coderising/download/api/DownloadListener.java @@ -0,0 +1,5 @@ +package com.coderising.download.api; + +public interface DownloadListener { + public void notifyFinished(); +} diff --git a/group04/844028312/three/src/com/coderising/download/impl/ConnectionImpl.java b/group04/844028312/three/src/com/coderising/download/impl/ConnectionImpl.java new file mode 100644 index 0000000000..4849434761 --- /dev/null +++ b/group04/844028312/three/src/com/coderising/download/impl/ConnectionImpl.java @@ -0,0 +1,54 @@ +package com.coderising.download.impl; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.util.Arrays; + +import com.coderising.download.api.Connection; + +public class ConnectionImpl implements Connection{ + HttpURLConnection urlConnection; + + + + public HttpURLConnection getUrlConnection() { + return urlConnection; + } + + public void setUrlConnection(HttpURLConnection urlConnection) { + this.urlConnection = urlConnection; + } + + @Override + public byte[] read(int startPos, int endPos) throws IOException { + byte[] buffer = new byte[endPos-startPos+1]; + int count=0; + urlConnection.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos); + InputStream ips=urlConnection.getInputStream(); + //ips.skip(startPos); + while(count 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字段中。 + + */ + + + return null; + } + +} diff --git a/group04/844028312/three/src/com/coderising/litestruts/StrutsTest.java b/group04/844028312/three/src/com/coderising/litestruts/StrutsTest.java new file mode 100644 index 0000000000..b8c81faf3c --- /dev/null +++ b/group04/844028312/three/src/com/coderising/litestruts/StrutsTest.java @@ -0,0 +1,43 @@ +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/group04/844028312/three/src/com/coderising/litestruts/View.java b/group04/844028312/three/src/com/coderising/litestruts/View.java new file mode 100644 index 0000000000..07df2a5dab --- /dev/null +++ b/group04/844028312/three/src/com/coderising/litestruts/View.java @@ -0,0 +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; + } +} diff --git a/group04/844028312/three/src/com/coderising/litestruts/struts.xml b/group04/844028312/three/src/com/coderising/litestruts/struts.xml new file mode 100644 index 0000000000..e5d9aebba8 --- /dev/null +++ b/group04/844028312/three/src/com/coderising/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 diff --git a/group04/844028312/three/src/com/coding/basic/ArrayList.java b/group04/844028312/three/src/com/coding/basic/ArrayList.java new file mode 100644 index 0000000000..1f185736f9 --- /dev/null +++ b/group04/844028312/three/src/com/coding/basic/ArrayList.java @@ -0,0 +1,32 @@ +package com.coding.basic; + +public class ArrayList implements List { + + private int size = 0; + + private Object[] elementData = new Object[100]; + + 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 Iterator iterator(){ + return null; + } + +} diff --git a/group04/844028312/three/src/com/coding/basic/BinaryTreeNode.java b/group04/844028312/three/src/com/coding/basic/BinaryTreeNode.java new file mode 100644 index 0000000000..d7ac820192 --- /dev/null +++ b/group04/844028312/three/src/com/coding/basic/BinaryTreeNode.java @@ -0,0 +1,32 @@ +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; + } + + public BinaryTreeNode insert(Object o){ + return null; + } + +} diff --git a/group04/844028312/three/src/com/coding/basic/Iterator.java b/group04/844028312/three/src/com/coding/basic/Iterator.java new file mode 100644 index 0000000000..06ef6311b2 --- /dev/null +++ b/group04/844028312/three/src/com/coding/basic/Iterator.java @@ -0,0 +1,7 @@ +package com.coding.basic; + +public interface Iterator { + public boolean hasNext(); + public Object next(); + +} diff --git a/group04/844028312/three/src/com/coding/basic/LinkedList.java b/group04/844028312/three/src/com/coding/basic/LinkedList.java new file mode 100644 index 0000000000..df43a6dec7 --- /dev/null +++ b/group04/844028312/three/src/com/coding/basic/LinkedList.java @@ -0,0 +1,417 @@ +package com.coding.basic; + +import java.util.Arrays; + +public class LinkedList implements List { + + private Node head; + private Node last; + private int size=0; + public void add(Object o){ + if(head==null){ + head =new Node(); + head.data=o; + last=head; + } + else{ + Node temp=new Node(); + temp.data=o; + last.next=temp; + last=temp; + } + size++; + } + public boolean enCapacity(int index){ + if(index>=0&&index7->10 , 逆置后变为 10->7->3 + */ + public void reverse(){ + Node temp1=last; + for(int i=size-2;i>=0;i--){ + Node temp2=indexOf(i); + temp1.next=temp2; + temp1=temp2; + } + head.next=null; + temp1=head; + head=last; + last=temp1; + } + + + /** + * 删除一个单链表的前半部分 + * 例如:list = 2->5->7->8 , 删除以后的值为 7->8 + * 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10 + + */ + public void removeFirstHalf(){ + if(size>1){ + Node index=indexOf(size/2-1); + index.next=null; + last=index; + size=size-size/2; + } + } + + /** + * 从第i个元素开始, 删除length 个元素 , 注意i从0开始 + * @param i + * @param length + */ + public void remove(int i, int length){//1 2 3 4 5 + if( i=0){ + int len=length+i>size? size-i:length; + int j=0; + while(j0 && i>=0){ + Node before=indexOf(i-1); + Node after=indexOf(length+i); + if(before==null&&after==null){ + head=null; + last=null; + size=0; + } + else if(before==null&&after!=null){ + head=after; + size=size-length; + } + else if(before!=null&&after==null){ + before.next=null; + last=before; + size=size-length; + } + else{ + before.next=after; + size=size-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){ + if(list==null){ + return null; + } + int size=list.size; + int jude=0; + int [] newInt=new int[size]; + while(jude0){ + int index=(int) list.get(jude); + if(index>=0&&index0){ + int index=(int) list.get(jude); + for(int i=0;imin){ + start=i; + } + if((int)temp.data>=max){ + end=i; + break; + } + i++; + temp=temp.next; + } + if(start==-1){ + start=0; + } + if(end==-1){ + end=size; + } + this.remove(start,end-start); + + } + + /** + * 假设当前链表和参数list指定的链表均以元素依值递增有序排列(同一表中的元素值各不相同) + * 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列 + * @param list + */ + public LinkedList intersection( LinkedList list){ + if(list==null){ + return null; + } + int i=0; + int j=0; + LinkedList c=new LinkedList(); + while(i(int)list.get(j)){ + j++; + } + else{ + i++; + } + } + return c; + } +} diff --git a/group04/844028312/three/src/com/coding/basic/LinkedListTest.java b/group04/844028312/three/src/com/coding/basic/LinkedListTest.java new file mode 100644 index 0000000000..0c965c90bd --- /dev/null +++ b/group04/844028312/three/src/com/coding/basic/LinkedListTest.java @@ -0,0 +1,145 @@ +package com.coding.basic; + +import static org.junit.Assert.*; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class LinkedListTest { + private LinkedList linkedList; + @Before + public void setUp() throws Exception { + linkedList=new LinkedList(); + for(int i=0;i<10;i++){ + linkedList.add(i); + } + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testAddObject() { + + System.out.println(linkedList.size()); + } + + @Test + public void testAddIntObject() { + linkedList.add(10, "@"); + System.out.println(linkedList.size()); + } + + @Test + public void testGet() { + System.out.println(linkedList.get(100)); + } + + @Test + public void testRemoveInt() { + System.out.println(linkedList.remove(9)); + System.out.println(linkedList.size()); + } + + @Test + public void testSize() { + fail("Not yet implemented"); + } + + @Test + public void testAddFirst() { + linkedList.addFirst("aa"); + System.out.println(linkedList.size()); + } + + @Test + public void testAddLast() { + linkedList.addLast("bb"); + System.out.println(linkedList.size()); + } + + @Test + public void testRemoveFirst() { + linkedList.removeFirst(); + System.out.println(linkedList.size()); + } + + @Test + public void testRemoveLast() { + linkedList.removeLast(); + System.out.println(linkedList.size()); + } + + @Test + public void testIterator() { + fail("Not yet implemented"); + } + + @Test + public void testReverse() { + linkedList.reverse(); + System.out.println(linkedList.size()); + } + + @Test + public void testRemoveFirstHalf() { + linkedList.removeFirstHalf(); + System.out.println(linkedList.size()); + } + + @Test + public void testRemoveIntInt() { + linkedList.remove(2, 5);//0 1 2 3 4 5 6 7 8 9 + System.out.println(linkedList.size()); + } + + @Test + public void testGetElements() { + LinkedList list=new LinkedList(); + list.add(1); + list.add(3); + list.add(2); + list.add(7); + int [] a=linkedList.getElements(list); + System.out.println(a); + + } + + @Test + public void testSubtract() { + LinkedList list=new LinkedList(); + list.add(1); + list.add(3); + list.add(2); + list.add(10); + linkedList.subtract(list); + System.out.println(linkedList); + } + + @Test + public void testRemoveDuplicateValues() { + linkedList.add(1); + linkedList.add(2); + linkedList.add(3); + linkedList.removeDuplicateValues(); + System.out.println(linkedList); + } + + @Test + public void testRemoveRange() { + linkedList.removeRange(2, 5); + System.out.println(linkedList); + } + + @Test + public void testIntersection() { + LinkedList list=new LinkedList(); + list.add(5); + list.add(6); + LinkedList c=linkedList.intersection(list); + System.out.println(c); + } + +} diff --git a/group04/844028312/three/src/com/coding/basic/List.java b/group04/844028312/three/src/com/coding/basic/List.java new file mode 100644 index 0000000000..10d13b5832 --- /dev/null +++ b/group04/844028312/three/src/com/coding/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/group04/844028312/three/src/com/coding/basic/Queue.java b/group04/844028312/three/src/com/coding/basic/Queue.java new file mode 100644 index 0000000000..36e516e266 --- /dev/null +++ b/group04/844028312/three/src/com/coding/basic/Queue.java @@ -0,0 +1,19 @@ +package com.coding.basic; + +public class Queue { + + public void enQueue(Object o){ + } + + public Object deQueue(){ + return null; + } + + public boolean isEmpty(){ + return false; + } + + public int size(){ + return -1; + } +} diff --git a/group04/844028312/three/src/com/coding/basic/Stack.java b/group04/844028312/three/src/com/coding/basic/Stack.java new file mode 100644 index 0000000000..a5a04de76d --- /dev/null +++ b/group04/844028312/three/src/com/coding/basic/Stack.java @@ -0,0 +1,22 @@ +package com.coding.basic; + +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; + } +} From 1b8675309a83f5ded46e4f27538deb72d6c856aa Mon Sep 17 00:00:00 2001 From: zj <2258659044@qq.com> Date: Mon, 27 Mar 2017 10:48:37 +0800 Subject: [PATCH 046/287] =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jvm/loader/ClassFileLoader.java | 32 +++ .../src/com/coding/basic/BinaryTree.java | 130 ++++++----- .../zj-2017/src/com/coding/basic/Queue.java | 54 ++--- .../zj-2017/src/com/coding/basic/Stack.java | 58 ++--- .../coding/basic/{ => array}/ArrayList.java | 5 +- .../basic}/array/ArrayUtil.java | 3 +- .../coding/basic/linklist/LRUPageFrame.java | 60 +++++ .../basic/{ => linklist}/LinkedList.java | 6 +- .../jvm/loader/ClassFileloaderTest.java | 88 +++++++ .../com/coderising/jvm/loader/EmployeeV1.java | 28 +++ .../basic/{ => array}/ArrayListTest.java | 218 +++++++++--------- .../basic}/array/ArrayUtilTest.java | 6 +- .../basic/linklist/LRUPageFrameTest.java | 31 +++ .../basic/{ => linklist}/LinkedListTest.java | 4 +- 14 files changed, 487 insertions(+), 236 deletions(-) create mode 100644 group12/2258659044/zj-2017/src/com/coderising/jvm/loader/ClassFileLoader.java rename group12/2258659044/zj-2017/src/com/coding/basic/{ => array}/ArrayList.java (91%) rename group12/2258659044/zj-2017/src/com/{coderising => coding/basic}/array/ArrayUtil.java (94%) create mode 100644 group12/2258659044/zj-2017/src/com/coding/basic/linklist/LRUPageFrame.java rename group12/2258659044/zj-2017/src/com/coding/basic/{ => linklist}/LinkedList.java (93%) create mode 100644 group12/2258659044/zj-2017/src/test/com/coderising/jvm/loader/ClassFileloaderTest.java create mode 100644 group12/2258659044/zj-2017/src/test/com/coderising/jvm/loader/EmployeeV1.java rename group12/2258659044/zj-2017/src/test/com/coding/basic/{ => array}/ArrayListTest.java (91%) rename group12/2258659044/zj-2017/src/test/com/{coderising => coding/basic}/array/ArrayUtilTest.java (91%) create mode 100644 group12/2258659044/zj-2017/src/test/com/coding/basic/linklist/LRUPageFrameTest.java rename group12/2258659044/zj-2017/src/test/com/coding/basic/{ => linklist}/LinkedListTest.java (93%) diff --git a/group12/2258659044/zj-2017/src/com/coderising/jvm/loader/ClassFileLoader.java b/group12/2258659044/zj-2017/src/com/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..c1b702238d --- /dev/null +++ b/group12/2258659044/zj-2017/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,32 @@ +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/group12/2258659044/zj-2017/src/com/coding/basic/BinaryTree.java b/group12/2258659044/zj-2017/src/com/coding/basic/BinaryTree.java index 3449517197..0b8eafc282 100644 --- a/group12/2258659044/zj-2017/src/com/coding/basic/BinaryTree.java +++ b/group12/2258659044/zj-2017/src/com/coding/basic/BinaryTree.java @@ -1,64 +1,66 @@ -package com.coding.basic; - -public class BinaryTree { - - //根节点 - private BinaryTreeNode root; - - @SuppressWarnings({ "rawtypes", "unchecked" }) - public > BinaryTreeNode insert(T o){ - - BinaryTreeNode treeNode = new BinaryTreeNode(); - treeNode.setData(o); - if(root == null){ - root = treeNode; - }else{ - BinaryTreeNode currentNode = root; - BinaryTreeNode parent; - while(true){ - parent = currentNode; - if(((Comparable)currentNode.getData()).compareTo(o)>0){//向左放 - currentNode = currentNode.getLeft(); - if(currentNode == null){ - parent.setLeft(treeNode); - treeNode.setParent(parent); - break; - } - }else{//向右放 - currentNode = currentNode.getRight(); - if(currentNode == null){ - parent.setRight(treeNode); - treeNode.setParent(parent); - break; - } - } - } - } - return treeNode; - } - - /** - * 先序遍历 - * @param node - * @return - */ - public List traversalBefore(BinaryTreeNode node){ - //所有数据集合 - List datas = new ArrayList(); - return traversal(node,datas); - } - private List traversal(BinaryTreeNode node,List datas){ - - if(node !=null){ - datas.add(node.getData()); - traversal(node.getLeft(),datas); - traversal(node.getRight(),datas); - } - return datas; - } - - public BinaryTreeNode getRoot() { - return root; - } - -} +package com.coding.basic; + +import com.coding.basic.array.ArrayList; + +public class BinaryTree { + + //根节点 + private BinaryTreeNode root; + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public > BinaryTreeNode insert(T o){ + + BinaryTreeNode treeNode = new BinaryTreeNode(); + treeNode.setData(o); + if(root == null){ + root = treeNode; + }else{ + BinaryTreeNode currentNode = root; + BinaryTreeNode parent; + while(true){ + parent = currentNode; + if(((Comparable)currentNode.getData()).compareTo(o)>0){//向左放 + currentNode = currentNode.getLeft(); + if(currentNode == null){ + parent.setLeft(treeNode); + treeNode.setParent(parent); + break; + } + }else{//向右放 + currentNode = currentNode.getRight(); + if(currentNode == null){ + parent.setRight(treeNode); + treeNode.setParent(parent); + break; + } + } + } + } + return treeNode; + } + + /** + * 先序遍历 + * @param node + * @return + */ + public List traversalBefore(BinaryTreeNode node){ + //所有数据集合 + List datas = new ArrayList(); + return traversal(node,datas); + } + private List traversal(BinaryTreeNode node,List datas){ + + if(node !=null){ + datas.add(node.getData()); + traversal(node.getLeft(),datas); + traversal(node.getRight(),datas); + } + return datas; + } + + public BinaryTreeNode getRoot() { + return root; + } + +} diff --git a/group12/2258659044/zj-2017/src/com/coding/basic/Queue.java b/group12/2258659044/zj-2017/src/com/coding/basic/Queue.java index e29ff65ddf..aa8429ac59 100644 --- a/group12/2258659044/zj-2017/src/com/coding/basic/Queue.java +++ b/group12/2258659044/zj-2017/src/com/coding/basic/Queue.java @@ -1,26 +1,28 @@ -package com.coding.basic; - -public class Queue { - - private LinkedList element = new LinkedList(); - - public void enQueue(Object o){ - - element.add(o); - } - - public Object deQueue(){ - - return element.removeFirst(); - } - - public boolean isEmpty(){ - - return element.size()==0; - } - - public int size(){ - - return element.size(); - } -} +package com.coding.basic; + +import com.coding.basic.linklist.LinkedList; + +public class Queue { + + private LinkedList element = new LinkedList(); + + public void enQueue(Object o){ + + element.add(o); + } + + public Object deQueue(){ + + return element.removeFirst(); + } + + public boolean isEmpty(){ + + return element.size()==0; + } + + public int size(){ + + return element.size(); + } +} diff --git a/group12/2258659044/zj-2017/src/com/coding/basic/Stack.java b/group12/2258659044/zj-2017/src/com/coding/basic/Stack.java index 03709097e5..2b08e856c1 100644 --- a/group12/2258659044/zj-2017/src/com/coding/basic/Stack.java +++ b/group12/2258659044/zj-2017/src/com/coding/basic/Stack.java @@ -1,28 +1,30 @@ -package com.coding.basic; - -public class Stack { - - private ArrayList elementData = new ArrayList(); - - public void push(Object o){ - - elementData.add(o); - } - - public Object pop(){ - - return elementData.remove(size()-1); - } - - public Object peek(){ - - return elementData.get(size()-1); - } - public boolean isEmpty(){ - - return size()==0; - } - public int size(){ - return elementData.size(); - } -} +package com.coding.basic; + +import com.coding.basic.array.ArrayList; + +public class Stack { + + private ArrayList elementData = new ArrayList(); + + public void push(Object o){ + + elementData.add(o); + } + + public Object pop(){ + + return elementData.remove(size()-1); + } + + public Object peek(){ + + return elementData.get(size()-1); + } + public boolean isEmpty(){ + + return size()==0; + } + public int size(){ + return elementData.size(); + } +} diff --git a/group12/2258659044/zj-2017/src/com/coding/basic/ArrayList.java b/group12/2258659044/zj-2017/src/com/coding/basic/array/ArrayList.java similarity index 91% rename from group12/2258659044/zj-2017/src/com/coding/basic/ArrayList.java rename to group12/2258659044/zj-2017/src/com/coding/basic/array/ArrayList.java index f1fbf7e8b1..4bbf60adf9 100644 --- a/group12/2258659044/zj-2017/src/com/coding/basic/ArrayList.java +++ b/group12/2258659044/zj-2017/src/com/coding/basic/array/ArrayList.java @@ -1,7 +1,10 @@ -package com.coding.basic; +package com.coding.basic.array; import java.util.NoSuchElementException; +import com.coding.basic.Iterator; +import com.coding.basic.List; + public class ArrayList implements List { private int size = 0; diff --git a/group12/2258659044/zj-2017/src/com/coderising/array/ArrayUtil.java b/group12/2258659044/zj-2017/src/com/coding/basic/array/ArrayUtil.java similarity index 94% rename from group12/2258659044/zj-2017/src/com/coderising/array/ArrayUtil.java rename to group12/2258659044/zj-2017/src/com/coding/basic/array/ArrayUtil.java index 3f41a350e8..de11fdbca5 100644 --- a/group12/2258659044/zj-2017/src/com/coderising/array/ArrayUtil.java +++ b/group12/2258659044/zj-2017/src/com/coding/basic/array/ArrayUtil.java @@ -1,6 +1,5 @@ -package com.coderising.array; +package com.coding.basic.array; -import com.coding.basic.ArrayList; public class ArrayUtil { diff --git a/group12/2258659044/zj-2017/src/com/coding/basic/linklist/LRUPageFrame.java b/group12/2258659044/zj-2017/src/com/coding/basic/linklist/LRUPageFrame.java new file mode 100644 index 0000000000..f727e48fd2 --- /dev/null +++ b/group12/2258659044/zj-2017/src/com/coding/basic/linklist/LRUPageFrame.java @@ -0,0 +1,60 @@ +package com.coding.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/group12/2258659044/zj-2017/src/com/coding/basic/LinkedList.java b/group12/2258659044/zj-2017/src/com/coding/basic/linklist/LinkedList.java similarity index 93% rename from group12/2258659044/zj-2017/src/com/coding/basic/LinkedList.java rename to group12/2258659044/zj-2017/src/com/coding/basic/linklist/LinkedList.java index 86a90383f4..0132efaa00 100644 --- a/group12/2258659044/zj-2017/src/com/coding/basic/LinkedList.java +++ b/group12/2258659044/zj-2017/src/com/coding/basic/linklist/LinkedList.java @@ -1,7 +1,11 @@ -package com.coding.basic; +package com.coding.basic.linklist; import java.util.NoSuchElementException; +import com.coding.basic.Iterator; +import com.coding.basic.List; +import com.coding.basic.Stack; + public class LinkedList implements List { private Node head; diff --git a/group12/2258659044/zj-2017/src/test/com/coderising/jvm/loader/ClassFileloaderTest.java b/group12/2258659044/zj-2017/src/test/com/coderising/jvm/loader/ClassFileloaderTest.java new file mode 100644 index 0000000000..4845e8de5b --- /dev/null +++ b/group12/2258659044/zj-2017/src/test/com/coderising/jvm/loader/ClassFileloaderTest.java @@ -0,0 +1,88 @@ +package test.com.coderising.jvm.loader; + +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 Date: Mon, 27 Mar 2017 11:13:10 +0800 Subject: [PATCH 047/287] =?UTF-8?q?383117348=E5=AD=97=E8=8A=82=E7=A0=81?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E8=AF=BB=E5=8F=96=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jvm/loader/ClassFileLoader.java | 65 ++++++++++++++++ .../jvm/test/ClassFileloaderTest.java | 76 +++++++++++++++++++ .../com/coderising/jvm/test/EmployeeV1.java | 30 ++++++++ 3 files changed, 171 insertions(+) create mode 100644 group27/383117348/src/com/coderising/jvm/loader/ClassFileLoader.java create mode 100644 group27/383117348/src/com/coderising/jvm/test/ClassFileloaderTest.java create mode 100644 group27/383117348/src/com/coderising/jvm/test/EmployeeV1.java diff --git a/group27/383117348/src/com/coderising/jvm/loader/ClassFileLoader.java b/group27/383117348/src/com/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..898bb73495 --- /dev/null +++ b/group27/383117348/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,65 @@ +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 { + + private List clzPaths = new ArrayList(); + + public byte[] readBinaryCode(String className){ + className = className.replace(".", "\\"); + File file = new File(getClassPath()+"\\"+className+".class"); + + 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; + } + +} diff --git a/group27/383117348/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group27/383117348/src/com/coderising/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..33229dccb2 --- /dev/null +++ b/group27/383117348/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,76 @@ +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 = "E:\\MyGit\\coding2017\\group27\\383117348\\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(); + System.out.println(clzPath); + 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/group27/383117348/src/com/coderising/jvm/test/EmployeeV1.java b/group27/383117348/src/com/coderising/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..d36b122f60 --- /dev/null +++ b/group27/383117348/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 0e6cf0946b7a939641df0d6569d0b5d406622efe Mon Sep 17 00:00:00 2001 From: x_zhaohu Date: Mon, 27 Mar 2017 12:00:21 +0800 Subject: [PATCH 048/287] =?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 049/287] 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 050/287] 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 zcmeI3X>1(j8OH}o8@67wmxVn7)tU2c7(n$t?R~W{|?lboveCT?kqrot;4H+lpO2UW# zebjtU>WpQNSWB$3M7qY74<}VuQ68UMR+mXPHpJs)@%ZE^6_X}Tthljky5(B;x|zm= z+nBM-vYA9#z2&5W;`M&%vT7^qB+6zxsl|59Y$xlMO8p<+<0v&!;8UhRqgz`tWwbG| zB3>>d|Js-v%&We1-=|E3Xt`|4;#|#xSm; zUw@SV0MGw}{eS+8hT*}humw7y3F=`!+yvv{n=lqGgTIY7j0^B*_&NLt9)Vi84X%U> zmm9`A@HX^99$tr|@GLBaYIqRl!%UbC)8Ol1z-wPHjMH!mcEeg&1FIncw}1iff8H>D z4JTkTtOpk!g)}UH*)R)c!dSQtu7zvh!ewXxZ^1cu9ge~wcn;d35i;;7d(fi@JDg0`EgDxzTC6sm zF^hN!#&pc7W_cxto6SVJG3Az3@MFS+apvPvg=r_Vw)*;?)HHR3s+?N0NHt)7!>llG zpi$j~^g*AWYG$3sY{J-)SXli^e_9@XYaL@?m=WSLFBXO7d+YFcJf)Zy1*CB9%zDb7 zKec06d9&CYv9KwX>xOmR-A%dfAA4<^`!}8Gd*+}tvbN1@Ti3txpx3g-7-|bARbwxk zFhS|>+Vu^kHM|Ez$J5Cgc_V0nN?%w=CPn2+*~?rxxpa|}w2KO-M8i~LGO1;h(-c@_ zTQ!nbRmJb}O4QP(3%4G$D1w_MrfxWBPkQy=bwc@*43etiQpH@}g;IkEb!}etBX+`F zurL@lNhy1&>7SM!i3CG@V2Pc{+SooeV0&#otvrS`Co0>E;m!W0HNB^gV0LfAHc2w$ zy zq}UwP=a@8DI3s2aYqRH8AHu~Y6G zUj3_e5@?Z54b(p-f4Iv#`byvP&*YCkli#&AclJoW^A)e7HGg>Dn1ObJ>Sc0^8q$nE z6@1aflaznNVz& zsA92!R~=`$cE)nk8God;PRdH+GF&SB5iuEjZ=njVVq(~kFKQngUZ3gIHze(P%#<~Q zHq>O6&iLZVYBap0x^DWWD3o*x-Bg}FP=~&16-gIM;$q&xM%2l(Ex8v_1tk3j8Xph#EzTGeZX;ixx7d$?*vfKrfyCWGZ+|sP|$Y zJ!}2D7=HkAP}e}opl?$Or-IuQbL?2T$(*Vsl(kzXe{lcFkGUd-U!i{+6I@wT(tsxf zJ@h9oWyL(YO9jUmxF#=^;sw`YcB|_2U59)vN*9}hi(v!&S@)=rGSpBXi>Imi^ns2R zOzQz3<7Ou`S@m2Uv?Rztd^atW9#%qmx4K!3#YB3BDvO{JM{Y5T^^K-nMf|!3)i{vgQS{|C?kb#NEl0+lcUMuF`2`{9@HDjbKy zAp8IQun+cv1x3)$9{yJ#`~8j32CeV_+z+$hPM86*_rD!(gPWle-ePZm4i3P6*auzE z37eoD+F(7b0}CF8h42tO0QbXuxDW1udGH>4{`2r8EQe*V6z+j}AhCkG;ZBfv!3>xV zw?Gw0tRM&Vkc5Ts5X^zuFca>8>)^|94O|UZ!WA$YE{98D6s%#1TMZY(Mes*#^d7te zZ^H?A3HHN2coxKtPs1MA4ZC0`?11gC4WhqDfk=T!fk=T!f&W_tmivElv&KzkaC^;d z7WXs3{Z(iKD%)O(ekD|#BAg&`OLdzr;ZPOYy0yW|SoNkP=o7u|$NKg^m4ALkZ|Bqb zmX7?EV><3N?fj`$Z}kap^~&BC_YxxWPH!S~snfiTtx`d*`>;+XteNZS>fgDBGP&+f z0-e)HlVGPREy0X4yNRy$H*NHu-NR3>XG6Yyqt~)k_rZIrx$nrCAuV_tR^&GylXmj0 z&EAn6ROh$8yIDfEx?>+u@A*?LL{4(uP4p$)6*}Q{tjcw__3rE@!}(Kd>46T2^F_(c z(Z2@`hnK%?rRrpl>6-OUs#p{^>#b!YYRh>&EMIF1=-+)uH+yTg)2aUFw&gdsFreNe zTk|h$7Nu3RSa&wRwn-$Sr(FkfJ?#`nQ}5UY`ED&MsLBxg*6-6ryu;hPT?hNlZqM(1 zIg~*LCo%AskM}<9hcm-sh>9Z_Mf&r~2}up&*16NWq=^*=drxl4?^*TxrWMruQDmFm z*g&A3*x!6B*=T16V)MFVBaK>HMn=)KBX@ecwljmxoj&WG*_z+fCY@37`re+i`KAMd zL{m;7Wl;||8Eof*6k$*M#01GUR=XK1;T8?-jMOw#KBNpa(iGJe%$;l>(r3D@eFnP+ zbFsOH$y_kM`3V|-u?+*BT4Xqw8WM2y?np2kb6i1$w_sk%v>*3SaMB1#@IQB6q||AtL= z`Jgr)63GX3@<^aOu8R*dfVW|b*WA;;;)l7OoobO{)&}d8_F3)XPs!R9Zr5KtaZj&x zwb$_+v(sy9F06=*G{5;pR=!|@NjOD?RMbZ-X{YMkMI|a!Cf5deY**y?p#~jVF^hC2 zvnqIm7Jf?Sml^R<-(p1JQQu-7_30}3&XYcRpkiI-)WSnK)fsJe37qI;qFxf2@LL}e z0}HRFIy|A5QJuT6l8Vg(A5cS8GWutnz!<%U4mt8*P0e@jRFijLJ*$@gOwMn=kZwv+ 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: Mon, 27 Mar 2017 14:02:31 +0800 Subject: [PATCH 051/287] =?UTF-8?q?383117348=E4=BF=AE=E6=94=B9=E5=AD=97?= =?UTF-8?q?=E8=8A=82=E7=A0=81=E6=96=87=E4=BB=B6=E8=AF=BB=E5=8F=96=E8=B7=AF?= =?UTF-8?q?=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jvm/loader/ClassFileLoader.java | 68 +++++++++++-------- 1 file changed, 40 insertions(+), 28 deletions(-) diff --git a/group27/383117348/src/com/coderising/jvm/loader/ClassFileLoader.java b/group27/383117348/src/com/coderising/jvm/loader/ClassFileLoader.java index 898bb73495..09051be9b6 100644 --- a/group27/383117348/src/com/coderising/jvm/loader/ClassFileLoader.java +++ b/group27/383117348/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -12,37 +12,49 @@ public class ClassFileLoader { private List clzPaths = new ArrayList(); - public byte[] readBinaryCode(String className){ + public byte[] readBinaryCode(String className) { className = className.replace(".", "\\"); - File file = new File(getClassPath()+"\\"+className+".class"); - - 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 { + 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; + } + return null; } public void addClassPath(String path) { @@ -55,10 +67,10 @@ public void addClassPath(String path) { public String getClassPath() { String paths = ""; - for(String s:clzPaths){ - paths+=s+";"; + for (String s : clzPaths) { + paths += s + ";"; } - paths = paths.substring(0, paths.length()-1); + paths = paths.substring(0, paths.length() - 1); return paths; } From 457ddfb80a6dcb5836163f98b8925a82279d1de1 Mon Sep 17 00:00:00 2001 From: zhanglei <383117348@qq.com> Date: Mon, 27 Mar 2017 14:03:39 +0800 Subject: [PATCH 052/287] =?UTF-8?q?383117348=E7=A7=BB=E5=8A=A8=E4=BA=86lin?= =?UTF-8?q?kedlist=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group27/383117348/src/com/coding/basic/Queue.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/group27/383117348/src/com/coding/basic/Queue.java b/group27/383117348/src/com/coding/basic/Queue.java index 84cb43e3db..4bd32c067b 100644 --- a/group27/383117348/src/com/coding/basic/Queue.java +++ b/group27/383117348/src/com/coding/basic/Queue.java @@ -2,6 +2,8 @@ import org.junit.Test; +import com.coding.basic.linklist.LinkedList; + public class Queue { private int size = 0; private LinkedList linkedList = new LinkedList(); From 186bcc3ce0b36dc2ce2a325b0f63181bff1200d8 Mon Sep 17 00:00:00 2001 From: GordenChow <513274874@qq.com> Date: Mon, 27 Mar 2017 14:54:38 +0800 Subject: [PATCH 053/287] =?UTF-8?q?=E6=A0=B9=E6=8D=AE=E5=88=98=E8=80=81?= =?UTF-8?q?=E5=B8=88=E6=96=87=E4=BB=B6=E5=A4=B9=E7=BB=93=E6=9E=84=E9=87=8D?= =?UTF-8?q?=E6=9E=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group27/513274874/.gitignore | 1 + group27/513274874/data-structure/.classpath | 7 + group27/513274874/data-structure/.gitignore | 1 + group27/513274874/data-structure/.project | 17 ++ group27/513274874/data-structure/down.jpg | Bin 0 -> 14104 bytes .../coderising/download/DownloadThread.java | 30 ++ .../coderising/download/FileDownloader.java | 73 +++++ .../download/FileDownloaderTest.java | 59 ++++ .../coderising/download/api/Connection.java | 23 ++ .../download/api/ConnectionException.java | 5 + .../download/api/ConnectionManager.java | 10 + .../download/api/DownloadListener.java | 5 + .../coderising/download/demo/DownThread.java | 72 +++++ .../coderising/download/demo/MutilDown.java | 72 +++++ .../download/impl/ConnectionImpl.java | 100 +++++++ .../download/impl/ConnectionManagerImpl.java | 29 ++ .../coderising/litestruts/LoginAction.java | 39 +++ .../src/com/coderising/litestruts/Struts.java | 254 +++++++++++++++++ .../com/coderising/litestruts/StrutsTest.java | 53 ++++ .../src/com/coderising/litestruts/View.java | 23 ++ .../src/com/coderising/litestruts/struts.xml | 11 + .../src/com/coding/basic/ArrayList.java | 124 ++++++++ .../src/com/coding/basic/BinaryTreeNode.java | 32 +++ .../src/com/coding/basic/Iterator.java | 7 + .../src/com/coding/basic/List.java | 9 + .../src/com/coding/basic/Queue.java | 50 ++++ .../src/com/coding/basic/Stack.java | 65 +++++ .../src/com/coding/basic/array/ArrayUtil.java | 262 +++++++++++++++++ .../com/coding/basic/array/ArrayUtilTest.java | 110 +++++++ .../coding/basic/linklist/LRUPageFrame.java | 60 ++++ .../basic/linklist/LRUPageFrameTest.java | 31 ++ .../com/coding/basic/linklist/LinkedList.java | 268 ++++++++++++++++++ .../test/com/coding/basic/ArrayListTest.java | 151 ++++++++++ .../jvm/loader/ClassFileLoader.java | 34 +++ .../jvm/test/ClassFileloaderTest.java | 92 ++++++ .../com/coderising/jvm/test/EmployeeV1.java | 28 ++ 36 files changed, 2207 insertions(+) create mode 100644 group27/513274874/.gitignore create mode 100644 group27/513274874/data-structure/.classpath create mode 100644 group27/513274874/data-structure/.gitignore create mode 100644 group27/513274874/data-structure/.project create mode 100644 group27/513274874/data-structure/down.jpg create mode 100644 group27/513274874/data-structure/src/com/coderising/download/DownloadThread.java create mode 100644 group27/513274874/data-structure/src/com/coderising/download/FileDownloader.java create mode 100644 group27/513274874/data-structure/src/com/coderising/download/FileDownloaderTest.java create mode 100644 group27/513274874/data-structure/src/com/coderising/download/api/Connection.java create mode 100644 group27/513274874/data-structure/src/com/coderising/download/api/ConnectionException.java create mode 100644 group27/513274874/data-structure/src/com/coderising/download/api/ConnectionManager.java create mode 100644 group27/513274874/data-structure/src/com/coderising/download/api/DownloadListener.java create mode 100644 group27/513274874/data-structure/src/com/coderising/download/demo/DownThread.java create mode 100644 group27/513274874/data-structure/src/com/coderising/download/demo/MutilDown.java create mode 100644 group27/513274874/data-structure/src/com/coderising/download/impl/ConnectionImpl.java create mode 100644 group27/513274874/data-structure/src/com/coderising/download/impl/ConnectionManagerImpl.java create mode 100644 group27/513274874/data-structure/src/com/coderising/litestruts/LoginAction.java create mode 100644 group27/513274874/data-structure/src/com/coderising/litestruts/Struts.java create mode 100644 group27/513274874/data-structure/src/com/coderising/litestruts/StrutsTest.java create mode 100644 group27/513274874/data-structure/src/com/coderising/litestruts/View.java create mode 100644 group27/513274874/data-structure/src/com/coderising/litestruts/struts.xml create mode 100644 group27/513274874/data-structure/src/com/coding/basic/ArrayList.java create mode 100644 group27/513274874/data-structure/src/com/coding/basic/BinaryTreeNode.java create mode 100644 group27/513274874/data-structure/src/com/coding/basic/Iterator.java create mode 100644 group27/513274874/data-structure/src/com/coding/basic/List.java create mode 100644 group27/513274874/data-structure/src/com/coding/basic/Queue.java create mode 100644 group27/513274874/data-structure/src/com/coding/basic/Stack.java create mode 100644 group27/513274874/data-structure/src/com/coding/basic/array/ArrayUtil.java create mode 100644 group27/513274874/data-structure/src/com/coding/basic/array/ArrayUtilTest.java create mode 100755 group27/513274874/data-structure/src/com/coding/basic/linklist/LRUPageFrame.java create mode 100755 group27/513274874/data-structure/src/com/coding/basic/linklist/LRUPageFrameTest.java create mode 100644 group27/513274874/data-structure/src/com/coding/basic/linklist/LinkedList.java create mode 100644 group27/513274874/data-structure/test/com/coding/basic/ArrayListTest.java create mode 100755 group27/513274874/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java create mode 100755 group27/513274874/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java create mode 100755 group27/513274874/mini-jvm/src/com/coderising/jvm/test/EmployeeV1.java diff --git a/group27/513274874/.gitignore b/group27/513274874/.gitignore new file mode 100644 index 0000000000..3f330393a1 --- /dev/null +++ b/group27/513274874/.gitignore @@ -0,0 +1 @@ +/homework/ diff --git a/group27/513274874/data-structure/.classpath b/group27/513274874/data-structure/.classpath new file mode 100644 index 0000000000..2d7497573f --- /dev/null +++ b/group27/513274874/data-structure/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/group27/513274874/data-structure/.gitignore b/group27/513274874/data-structure/.gitignore new file mode 100644 index 0000000000..ae3c172604 --- /dev/null +++ b/group27/513274874/data-structure/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/group27/513274874/data-structure/.project b/group27/513274874/data-structure/.project new file mode 100644 index 0000000000..b6d8ce6204 --- /dev/null +++ b/group27/513274874/data-structure/.project @@ -0,0 +1,17 @@ + + + coding2017 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/group27/513274874/data-structure/down.jpg b/group27/513274874/data-structure/down.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d7fccb49d254800f2d6c17911498e8523b68b0d7 GIT binary patch literal 14104 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 literal 0 HcmV?d00001 diff --git a/group27/513274874/data-structure/src/com/coderising/download/DownloadThread.java b/group27/513274874/data-structure/src/com/coderising/download/DownloadThread.java new file mode 100644 index 0000000000..ff496b8d4d --- /dev/null +++ b/group27/513274874/data-structure/src/com/coderising/download/DownloadThread.java @@ -0,0 +1,30 @@ +package com.coderising.download; + +import com.coderising.download.api.Connection; + +import java.io.IOException; +import java.io.RandomAccessFile; + +public class DownloadThread extends Thread{ + + Connection conn; + int startPos; + int endPos; + + // 将下载到的字节输出到raf中 + private RandomAccessFile raf ; + + public DownloadThread( Connection conn, int startPos, int endPos){ + + this.conn = conn; + this.startPos = startPos; + this.endPos = endPos; + } + public void run(){ + try { + byte[] buff = conn.read(startPos,endPos); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/group27/513274874/data-structure/src/com/coderising/download/FileDownloader.java b/group27/513274874/data-structure/src/com/coderising/download/FileDownloader.java new file mode 100644 index 0000000000..31cb31f730 --- /dev/null +++ b/group27/513274874/data-structure/src/com/coderising/download/FileDownloader.java @@ -0,0 +1,73 @@ +package com.coderising.download; + +import com.coderising.download.api.Connection; +import com.coderising.download.api.ConnectionException; +import com.coderising.download.api.DownloadListener; +import com.coderising.download.api.ConnectionManager; + + +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/group27/513274874/data-structure/src/com/coderising/download/FileDownloaderTest.java b/group27/513274874/data-structure/src/com/coderising/download/FileDownloaderTest.java new file mode 100644 index 0000000000..d8874d5981 --- /dev/null +++ b/group27/513274874/data-structure/src/com/coderising/download/FileDownloaderTest.java @@ -0,0 +1,59 @@ +package com.coderising.download; + +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 com.coderising.download.api.ConnectionManager; + +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/group27/513274874/data-structure/src/com/coderising/download/api/Connection.java b/group27/513274874/data-structure/src/com/coderising/download/api/Connection.java new file mode 100644 index 0000000000..9710e270e1 --- /dev/null +++ b/group27/513274874/data-structure/src/com/coderising/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/group27/513274874/data-structure/src/com/coderising/download/api/ConnectionException.java b/group27/513274874/data-structure/src/com/coderising/download/api/ConnectionException.java new file mode 100644 index 0000000000..8dbfe95dda --- /dev/null +++ b/group27/513274874/data-structure/src/com/coderising/download/api/ConnectionException.java @@ -0,0 +1,5 @@ +package com.coderising.download.api; + +public class ConnectionException extends Exception { + +} diff --git a/group27/513274874/data-structure/src/com/coderising/download/api/ConnectionManager.java b/group27/513274874/data-structure/src/com/coderising/download/api/ConnectionManager.java new file mode 100644 index 0000000000..fb44ede457 --- /dev/null +++ b/group27/513274874/data-structure/src/com/coderising/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/group27/513274874/data-structure/src/com/coderising/download/api/DownloadListener.java b/group27/513274874/data-structure/src/com/coderising/download/api/DownloadListener.java new file mode 100644 index 0000000000..4cd0b3eab1 --- /dev/null +++ b/group27/513274874/data-structure/src/com/coderising/download/api/DownloadListener.java @@ -0,0 +1,5 @@ +package com.coderising.download.api; + +public interface DownloadListener { + public void notifyFinished(); +} diff --git a/group27/513274874/data-structure/src/com/coderising/download/demo/DownThread.java b/group27/513274874/data-structure/src/com/coderising/download/demo/DownThread.java new file mode 100644 index 0000000000..18b21da57c --- /dev/null +++ b/group27/513274874/data-structure/src/com/coderising/download/demo/DownThread.java @@ -0,0 +1,72 @@ +package com.coderising.download.demo; + +import java.io.InputStream; +import java.io.RandomAccessFile; + +public class DownThread extends Thread { + + // 定义字节数组(取水的竹筒)的长度 + private final int BUFF_LEN = 32; + + // 定义下载的起始点 + private long start; + + // 定义下载的结束点 + private long end; + + // 下载资源对应的输入流 + private InputStream is; + + // 将下载到的字节输出到raf中 + private RandomAccessFile raf; + + + // 构造器,传入输入流,输出流和下载起始点、结束点 + public DownThread(long start, long end, InputStream is, RandomAccessFile raf) { + // 输出该线程负责下载的字节位置 + System.out.println(start + "---->" + end); + this.start = start; + this.end = end; + this.is = is; + this.raf = raf; + } + + @Override + 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(); + } + } + } +} \ No newline at end of file diff --git a/group27/513274874/data-structure/src/com/coderising/download/demo/MutilDown.java b/group27/513274874/data-structure/src/com/coderising/download/demo/MutilDown.java new file mode 100644 index 0000000000..6358700d4f --- /dev/null +++ b/group27/513274874/data-structure/src/com/coderising/download/demo/MutilDown.java @@ -0,0 +1,72 @@ +package com.coderising.download.demo; + +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 = "down.jpg"; + InputStream[] isArr = new InputStream[DOWN_THREAD_NUM]; + RandomAccessFile[] outArr = new RandomAccessFile[DOWN_THREAD_NUM]; + try { + // 创建一个URL对象 + 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; + } + +} \ No newline at end of file diff --git a/group27/513274874/data-structure/src/com/coderising/download/impl/ConnectionImpl.java b/group27/513274874/data-structure/src/com/coderising/download/impl/ConnectionImpl.java new file mode 100644 index 0000000000..ea9ad0f25e --- /dev/null +++ b/group27/513274874/data-structure/src/com/coderising/download/impl/ConnectionImpl.java @@ -0,0 +1,100 @@ +package com.coderising.download.impl; + +import com.coderising.download.api.Connection; + +import java.io.*; +import java.net.URL; +import java.net.URLConnection; + +public class ConnectionImpl implements Connection { + private URL url; + + // 定义字节数组(取水的竹筒)的长度 + private final int BUFF_LEN = 32; + + // 下载资源对应的输入流 + private InputStream is; + + + ByteArrayOutputStream bos; + + @Override + public byte[] read(int startPos, int endPos) throws IOException { + + this.is = url.openStream(); + + is.skip(startPos); + // 定义读取输入流内容的的缓存数组(竹筒) + byte[] buff = new byte[BUFF_LEN]; + // 本线程负责下载资源的大小 + long contentLen = endPos - startPos; + bos = new ByteArrayOutputStream((int) contentLen); + BufferedInputStream in = new BufferedInputStream(is); + int len = 0; + while (-1 != (len = in.read(buff, 0, BUFF_LEN))) { + bos.write(buff, 0, len); + } + return bos.toByteArray(); + } +// @Override +// public byte[] read(int startPos, int endPos) throws IOException { +// raf = new RandomAccessFile("newfile.jpg", "rw"); +// this.is = url.openStream(); +// +// is.skip(startPos); +// raf.seek(startPos); +// // 定义读取输入流内容的的缓存数组(竹筒) +// byte[] buff = new byte[BUFF_LEN]; +// // 本线程负责下载资源的大小 +// long contentLen = endPos - startPos; +// ByteArrayOutputStream bos = new ByteArrayOutputStream((int) contentLen); +// // 定义最多需要读取几次就可以完成本线程的下载 +// 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); +// } +// +// return null; +// } + + @Override + public int getContentLength() { + int length = 0; + // 打开该URL对应的URLConnection + URLConnection con = null; + try { + con = url.openConnection(); + } catch (IOException e) { + e.printStackTrace(); + } + // 获取连接URL资源的长度 + length = con.getContentLength(); + return length; + } + + @Override + public void close() { + try { + if (is != null) { + is.close(); + } + if (bos != null) { + bos.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + + } + + public ConnectionImpl(URL url) { + this.url = url; + } +} diff --git a/group27/513274874/data-structure/src/com/coderising/download/impl/ConnectionManagerImpl.java b/group27/513274874/data-structure/src/com/coderising/download/impl/ConnectionManagerImpl.java new file mode 100644 index 0000000000..2f04b22b9d --- /dev/null +++ b/group27/513274874/data-structure/src/com/coderising/download/impl/ConnectionManagerImpl.java @@ -0,0 +1,29 @@ +package com.coderising.download.impl; + +import com.coderising.download.api.ConnectionException; +import com.coderising.download.api.Connection; +import com.coderising.download.api.ConnectionManager; + +import java.net.MalformedURLException; +import java.net.URL; + +public class ConnectionManagerImpl implements ConnectionManager { + + @Override + public Connection open(String url) throws ConnectionException { + + Connection connection = null; + try { + if(url == null || "".equals(url.trim())) return null; + + URL urlO = new URL(url); + connection = new ConnectionImpl(urlO); + + + } catch (MalformedURLException e) { + e.printStackTrace(); + } + return connection; + } + +} diff --git a/group27/513274874/data-structure/src/com/coderising/litestruts/LoginAction.java b/group27/513274874/data-structure/src/com/coderising/litestruts/LoginAction.java new file mode 100644 index 0000000000..dcdbe226ed --- /dev/null +++ b/group27/513274874/data-structure/src/com/coderising/litestruts/LoginAction.java @@ -0,0 +1,39 @@ +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/group27/513274874/data-structure/src/com/coderising/litestruts/Struts.java b/group27/513274874/data-structure/src/com/coderising/litestruts/Struts.java new file mode 100644 index 0000000000..02a8146b0c --- /dev/null +++ b/group27/513274874/data-structure/src/com/coderising/litestruts/Struts.java @@ -0,0 +1,254 @@ +package com.coderising.litestruts; + +import org.dom4j.Attribute; +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.File; +import java.io.FileNotFoundException; +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 { + + private static Struts instance = null; + private static Map<String, StrutsXml> strutsXml; + + private Struts() { + } + + /** + * 单例模式初始化struts.xml,而不是每次跑runAction的时候都要初始化一次 + * + * @return + */ + public static Struts init() throws FileNotFoundException { + + if (instance == null) { + /** + * 0. 读取配置文件struts.xml + */ + //创建SAXReader对象 + SAXReader reader = new SAXReader(); + //读取文件 转换成Document + Document document = null; + try { + document = reader.read(new File("src/com/coding/coderising/litestruts/struts.xml")); + } catch (DocumentException e) { + e.printStackTrace(); + } + //获取根节点元素对象 + Element root = document.getRootElement(); + if ("struts".equals(root.getName())) { + strutsXml = new HashMap<String, StrutsXml>(); + + Iterator<Element> actions = root.elementIterator(); + while (actions.hasNext()) { + Element action = actions.next(); + List<Attribute> attrList = action.attributes(); + + String actionName = null; + StrutsXml xml = null; + if (!"action".equals(action.getName())) { + continue; + } + //遍历属性节点 + for (Attribute attribute : attrList) { + xml = new StrutsXml(); + if ("name".equals(attribute.getName())) { + actionName = attribute.getValue(); + } + if ("class".equals(attribute.getName())) { + xml.setClazz(attribute.getValue()); + //获取result信息 + Iterator<Element> results = action.elementIterator(); + while (results.hasNext()) { + Element result = results.next(); + List<Attribute> resultList = result.attributes(); + for (Attribute resultAttr : resultList) { + //System.out.println(resultAttr.getValue() + " ,"+result.getText()); + xml.getResult().put(resultAttr.getValue(), result.getText()); + } + } + + } + //System.out.println("属性"+attribute.getName() +":" + attribute.getValue()); + } + + strutsXml.put(actionName, xml); + } + } else { + throw new FileNotFoundException("not a struts XML file !"); + } + + + instance = new Struts(); + } + return instance; + } + + public static View runAction(String actionName, Map<String, String> parameters) { + + if (instance == null) return null; + if (actionName == null || "".equals(actionName.trim())) return null; + View view = new View(); + StrutsXml struts = strutsXml.get(actionName); + + Class clazz = null; + /** + * 1. 根据actionName找到相对应的class , 例如LoginAction, 通过反射实例化(创建对象) + * 据parameters中的数据,调用对象的setter方法, 例如parameters中的数据是 + * ("name"="test" , "password"="1234") ,那就应该调用 setName和setPassword方法 + */ + //获取相应处理的action + if (struts != null) { + String className = struts.getClazz(); + try { + clazz = Class.forName(className); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } else { + throw new NullPointerException("action not found in struts file !"); + } + + if (clazz != null) { + Object action = null; + try { + action = clazz.newInstance(); + + //反射调用设置参数 + for (Map.Entry<String, String> entry : parameters.entrySet()) { + String para = entry.getKey(); + if (!checkField(clazz, para)) continue; + //根据习惯,类的属性首字母在调用时大写,例如属性名是 age,则类方法为getAge + PropertyDescriptor pd = new PropertyDescriptor(para, clazz); + + Method setMethod = pd.getWriteMethod();//获得set方法 + + setMethod.invoke(action, entry.getValue()); + + } + /** + * 2. 通过反射调用对象的exectue 方法, 并获得返回值,例如"success" + */ + //执行execute() + Method excuteMethod = clazz.getDeclaredMethod("execute"); + String result = (String) excuteMethod.invoke(action); + //通过xml文件获取返回值 + String jsp = struts.getResult().get(result); + + if (jsp == null || jsp.trim().equals("")) { + throw new NullPointerException("the requested file is not found !"); + } + /** + * 3. 通过反射找到对象的所有getter方法(例如 getMessage), + * 通过反射来调用, 把值和属性形成一个HashMap , 例如 {"message": "登录成功"} , + * 放到View对象的parameters + */ + //执行get方法 + Map<String, String> viewMap = new HashMap<>(); + Field[] fields = clazz.getDeclaredFields();//获得属性 + + for (Field field : fields) { + String getMethodName = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1); + Method getMethod = clazz.getDeclaredMethod(getMethodName); + String returnVal = (String) getMethod.invoke(action); + viewMap.put(field.getName(), returnVal); + } + /** + * 4. 根据struts.xml中的 <result> 配置,以及execute的返回值, 确定哪一个jsp, + * 放到View对象的jsp字段中。 + */ + view.setJsp(jsp); + view.setParameters(viewMap); + + } catch (IntrospectionException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InstantiationException e) { + e.printStackTrace(); + } + } + + return view; + + + } + + private static boolean checkField(Class clazz, String fieldName) { + if (fieldName == null || fieldName.trim().equals("")) return false; + Field[] fields = clazz.getDeclaredFields(); + for (Field field : fields) { + if (fieldName.equals(field.getName())) return true; + } + return false; + } + + + public static void main(String args[]) { + try { + Struts.init(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + Map<String, String> paras = new HashMap<>(); + paras.put("name", "test"); + paras.put("password", "1234"); + View view = Struts.runAction("login", paras); + } +} + +class StrutsXml { + private String actionName; + private String clazz; + private Map<String, String> result = new HashMap<>(); + + public StrutsXml(String actionName, String clazz, Map<String, String> result) { + this.actionName = actionName; + this.clazz = clazz; + this.result = result; + } + + public StrutsXml() { + } + + public String getActionName() { + return actionName; + } + + public void setActionName(String actionName) { + this.actionName = actionName; + } + + public String getClazz() { + return clazz; + } + + public void setClazz(String clazz) { + this.clazz = clazz; + } + + public Map<String, String> getResult() { + return result; + } + + public void setResult(Map<String, String> result) { + this.result = result; + } +} \ No newline at end of file diff --git a/group27/513274874/data-structure/src/com/coderising/litestruts/StrutsTest.java b/group27/513274874/data-structure/src/com/coderising/litestruts/StrutsTest.java new file mode 100644 index 0000000000..c6341d662d --- /dev/null +++ b/group27/513274874/data-structure/src/com/coderising/litestruts/StrutsTest.java @@ -0,0 +1,53 @@ +package com.coderising.litestruts; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + + + + + +public class StrutsTest { + @Before + public void before() throws Exception { + Struts.init(); + } + + @After + public void after() throws Exception { + } + + @Test + public void testLoginActionSuccess() { + + String actionName = "login"; + + Map<String,String> params = new HashMap<String,String>(); + 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<String,String> params = new HashMap<String,String>(); + 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/group27/513274874/data-structure/src/com/coderising/litestruts/View.java b/group27/513274874/data-structure/src/com/coderising/litestruts/View.java new file mode 100644 index 0000000000..07df2a5dab --- /dev/null +++ b/group27/513274874/data-structure/src/com/coderising/litestruts/View.java @@ -0,0 +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; + } +} diff --git a/group27/513274874/data-structure/src/com/coderising/litestruts/struts.xml b/group27/513274874/data-structure/src/com/coderising/litestruts/struts.xml new file mode 100644 index 0000000000..0582b7d4ea --- /dev/null +++ b/group27/513274874/data-structure/src/com/coderising/litestruts/struts.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<struts> + <action name="login" class="com.coderising.litestruts.LoginAction"> + <result name="success">/jsp/homepage.jsp</result> + <result name="fail">/jsp/showLogin.jsp</result> + </action> + <action name="logout" class="com.coderising.litestruts.LogoutAction"> + <result name="success">/jsp/welcome.jsp</result> + <result name="error">/jsp/error.jsp</result> + </action> +</struts> diff --git a/group27/513274874/data-structure/src/com/coding/basic/ArrayList.java b/group27/513274874/data-structure/src/com/coding/basic/ArrayList.java new file mode 100644 index 0000000000..9e55e92529 --- /dev/null +++ b/group27/513274874/data-structure/src/com/coding/basic/ArrayList.java @@ -0,0 +1,124 @@ + +package com.coding.basic; + +import java.util.Arrays; + +/** + * @autor zhougd 20170306 + * 数组实现ArrayList + */ +public class ArrayList implements List { + + private int size = 0; + + private Object[] elementData; + + //扩容默认值 + private static final int INCREAMENT_CAP = 10; + + //含参数的构造函数 + public ArrayList(int size, Object[] elementData) { + this.size = size; + this.elementData = elementData; + } + + //默认100容量的构造函数 + public ArrayList() { + this.size = 0; + this.elementData = new Object[100]; + } + + @Override + public void add(Object o) { + //判断超过容量自动扩容 + if (this.size + 1 > this.elementData.length) { + increase(); + } + this.elementData[size++] = o; + } + + @Override + public void add(int index, Object o) { + if (index < 0 || index > this.size) { + throw new IndexOutOfBoundsException("Index out of bound!"); + } + //判断超过容量自动扩容 + if (this.size + 1 > this.elementData.length) { + increase(); + } + this.size++; + //index后面数组后移一位 + for (int cur = this.size; cur > index; cur--) { + this.elementData[cur] = this.elementData[cur - 1]; + } + + this.elementData[index] = o; + + } + + public Object get(int index) { + if (index < 0 || index > this.size) { + throw new IndexOutOfBoundsException("Index out of bound!"); + } + return this.elementData[index]; + } + + public Object remove(int index) { + Object o = this.get(index); + + //index后面的数向前移动一位 + for (int cur = index + 1; cur < this.size; cur++) { + this.elementData[cur] = this.elementData[cur + 1]; + } + //最后一个元素删除 + this.elementData[this.size-1] = null; + + this.size--; + return o; + } + + public int size() { + return this.size + 1; + } + + public Iterator iterator() { + return new ArrayListIterator(); + } + + @Override + public String toString() { + String arrayStr = "ArrayList{ size = " + this.size() + " , "; + + arrayStr += "elementData=["; + for(int i = 0 ;i<this.size();i++){ + arrayStr += + i == this.size()-1 ? + elementData[i]+"]":elementData[i]+"," ; + } + arrayStr+= " }"; + return arrayStr; + + } + + private void increase() { + this.elementData = Arrays.copyOf(this.elementData, this.elementData.length + INCREAMENT_CAP); + } + + private class ArrayListIterator implements Iterator { + + private int currentIndex = 0; + private int count = size(); + + @Override + public boolean hasNext() { + return currentIndex < count-1; + } + + @Override + public Object next() { + currentIndex++; + return get(currentIndex); + } + } +} + diff --git a/group27/513274874/data-structure/src/com/coding/basic/BinaryTreeNode.java b/group27/513274874/data-structure/src/com/coding/basic/BinaryTreeNode.java new file mode 100644 index 0000000000..266eff3d56 --- /dev/null +++ b/group27/513274874/data-structure/src/com/coding/basic/BinaryTreeNode.java @@ -0,0 +1,32 @@ +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; + } + + public BinaryTreeNode insert(Object o){ + return null; + } + +} diff --git a/group27/513274874/data-structure/src/com/coding/basic/Iterator.java b/group27/513274874/data-structure/src/com/coding/basic/Iterator.java new file mode 100644 index 0000000000..dbe8b9afb2 --- /dev/null +++ b/group27/513274874/data-structure/src/com/coding/basic/Iterator.java @@ -0,0 +1,7 @@ +package com.coding.basic; + +public interface Iterator { + public boolean hasNext(); + public Object next(); + +} diff --git a/group27/513274874/data-structure/src/com/coding/basic/List.java b/group27/513274874/data-structure/src/com/coding/basic/List.java new file mode 100644 index 0000000000..396b1f6416 --- /dev/null +++ b/group27/513274874/data-structure/src/com/coding/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/group27/513274874/data-structure/src/com/coding/basic/Queue.java b/group27/513274874/data-structure/src/com/coding/basic/Queue.java new file mode 100644 index 0000000000..9dec7f059a --- /dev/null +++ b/group27/513274874/data-structure/src/com/coding/basic/Queue.java @@ -0,0 +1,50 @@ + +package com.coding.basic; + +import com.coding.basic.linklist.LinkedList; + +/** + * author by zhougd 20170306 + * 链表实现队列 + */ +public class Queue { + private java.util.Queue a;; + /** + * 队列体,初始100个元素 + */ + private List queue = new LinkedList(); + + public Queue(){} + + /** + * 入队 + * @param o + */ + public void enQueue(Object o){ + queue.add(o); + } + + /** + * 出队 + * @return + */ + public Object deQueue(){ + return queue.remove(0); + } + + /** + * 队列是否为空 + * @return + */ + public boolean isEmpty(){ + return queue == null || queue.size() <= 0; + } + + /** + * 获取队列大小 + * @return + */ + public int size(){ + return queue.size(); + } +} diff --git a/group27/513274874/data-structure/src/com/coding/basic/Stack.java b/group27/513274874/data-structure/src/com/coding/basic/Stack.java new file mode 100644 index 0000000000..034e4c7215 --- /dev/null +++ b/group27/513274874/data-structure/src/com/coding/basic/Stack.java @@ -0,0 +1,65 @@ + +package com.coding.basic; + +/** + * 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/array/ArrayUtil.java b/group27/513274874/data-structure/src/com/coding/basic/array/ArrayUtil.java new file mode 100644 index 0000000000..0adc748f61 --- /dev/null +++ b/group27/513274874/data-structure/src/com/coding/basic/array/ArrayUtil.java @@ -0,0 +1,262 @@ +package com.coding.basic.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(final int[] origin) { + int size = origin.length; + if (size <= 0) return; + + int[] newArray = copyOf(origin); + + for (int i = 0; i < size; i++) { + origin[i] = newArray[size - 1 - 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) { + int size = oldArray.length; + int countZero = 0; + //首先判断数组中0的个数 + for (int i : oldArray) { + if (i == 0) countZero++; + } + int[] newArray = new int[size - countZero]; + //cur 命名newArray的游标 + int cur = 0; + for (int i = 0; i < size; i++) { + if (oldArray[i] == 0) continue; + newArray[cur++] = oldArray[i]; + } + + 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) { + //判断数组是否为空 + int size1 = array1.length; + int size2 = array2.length; + if (size1 <= 0 || size2 <= 0) + return size1 <= 0 ? array2 : array1; + + //先将两个数组合并成一个数组 + int[] newArray = new int[size1 + size2]; + System.arraycopy(array1, 0, newArray, 0, size1); + System.arraycopy(array2, 0, newArray, size1, size2); + + + //对数组进行插入排序(假定array1已经是有序数组) + int in, out; + for (out = size1; out < newArray.length; out++) { + in = out; + int temp = newArray[out]; + + while (in > 0 && newArray[in - 1] >= temp) { + //右移 + newArray[in] = newArray[in - 1]; + --in; + } + newArray[in] = temp; + } + 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) { + int oldSize = oldArray.length; + if (oldSize == 0) return new int[size]; + + if (size <= 0) return oldArray; + + int[] newArray = new int[oldSize + size]; + System.arraycopy(oldArray, 0, newArray, 0, oldSize); + + 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[]{}; + //这里的cur指的是数组的下标,从0开始,而不是数学函数1开始 + int cur = 2; + int val_1 = 1; + int val_2 = 1; + while (val_1 + val_2 <= max) { + int temp = val_1; + val_1 = val_2; + val_2 += temp; + ++cur; + } + + int[] newArray = new int[cur]; + for (int i = 0; i < cur; i++) { + if (i == 0 || i == 1) { + newArray[i] = 1; + continue; + } + newArray[i] = newArray[i - 1] + newArray[i - 2]; + + } + return newArray; + } + + /** + * 返回小于给定最大值max的所有素数数组 + * 例如max = 23, 返回的数组为[2,3,5,7,11,13,17,19] + * + * @param max + * @return + */ + public static int[] getPrimes(int max) { + //先确定数组长度 + //判断质数循环 + int count = 0; + for (int i = 1; i < max; i++) { + //去掉偶数 + if (i == 1 || (i % 2 == 0 && i != 2)) continue; + boolean flag = true; + for (int j = 3; j <= Math.sqrt(i); j += 2) { + if (i % j == 0) { + flag = false; + break; + } + } + if (flag) count++; + } + int[] newArray = new int[count]; + int cur = 0; + for (int i = 1; i < max; i++) { + //去掉偶数 + if (i == 1 || (i % 2 == 0 && i != 2)) continue; + //判断到开根号即可 + boolean flag = true; + for (int j = 3; j <= Math.sqrt(i); j += 2) { + if (i % j == 0) { + flag = false; + + } + } + if (flag) { + newArray[cur] = i; + ++cur; + } + + } + + + return newArray; + } + + /** + * 所谓“完数”, 是指这个数恰好等于它的因子之和,例如6=1+2+3 + * 给定一个最大值max, 返回一个数组, 数组中是小于max 的所有完数 + * + * @param max + * @return + */ + public static int[] getPerfectNumbers(int max) { + //求数组长度 + int count = 0; + for (int a = 1; a <= max; a++) { + int sum = 0; + for (int i = 1; i <= a / 2; i++) + if (a % i == 0) + sum += i; + if (a == sum) + ++count; + } + + int[] newArray = new int[count]; + int cur = 0; + for (int a = 1; a <= max; a++) { + int sum = 0; + for (int i = 1; i <= a / 2; i++) + if (a % i == 0) + sum += i; + if (a == sum) { + newArray[cur] = a; + ++cur; + } + } + + return newArray; + } + + /** + * 用seperator 把数组 array给连接起来 + * 例如array= [3,8,9], seperator = "-" + * 则返回值为"3-8-9" + * + * @param array + * @param seperator + * @return + */ + public static String join(int[] array, String seperator) { + int size = array.length; + if (size == 0) return ""; + StringBuffer sb = new StringBuffer(""); + for (int i = 0; i < size - 1; i++) { + sb.append(array[i]).append(seperator); + } + sb.append(array[size - 1]); + return sb.toString(); + } + + + /** + * 类私有函数,复制返回一个新的数组 + */ + private static int[] copyOf(int[] source) { + int size = source.length; + if (size <= 0) return null; + + int[] newArray = new int[size]; + //int[] ints = Arrays.copyOf(origin, size); + System.arraycopy(source, 0, newArray, 0, size); + return newArray; + } + + +} diff --git a/group27/513274874/data-structure/src/com/coding/basic/array/ArrayUtilTest.java b/group27/513274874/data-structure/src/com/coding/basic/array/ArrayUtilTest.java new file mode 100644 index 0000000000..7918ae41fe --- /dev/null +++ b/group27/513274874/data-structure/src/com/coding/basic/array/ArrayUtilTest.java @@ -0,0 +1,110 @@ +package com.coding.basic.array; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * ArrayUtil Tester. + * + * @author <Authors name> + * @version 1.0 + * @since <pre>三月 14, 2017</pre> + */ +public class ArrayUtilTest { + + int[] testArray ; + + @Before + public void before() throws Exception { + } + + @After + public void after() throws Exception { + testArray = new int[]{}; + } + + /** + * Method: reverseArray(final int[] origin) + */ + @Test + public void testReverseArray() throws Exception { + testArray = new int[]{1,3,5,7,9,4,6}; + ArrayUtil.reverseArray(testArray); + Assert.assertArrayEquals(new int[]{6,4,9,7,5,3,1},testArray); + } + + + /** + * Method: removeZero(int[] oldArray) + */ + @Test + public void testRemoveZero() throws Exception { + testArray = new int[]{1,3,0,7,0,4,6}; + int[] newArray = ArrayUtil.removeZero(testArray); + Assert.assertArrayEquals(new int[]{1,3,7,4,6}, newArray); + } + + /** + * Method: merge(int[] array1, int[] array2) + */ + @Test + public void testMerge() throws Exception { + int[] testArray1 = new int[]{1,3,6,8,9}; + int[] testArray2 = new int[]{2,3,3,10,12}; + + int[] mergedArray = ArrayUtil.merge(testArray1,testArray2); + Assert.assertArrayEquals(new int[]{1,2,3,3,3,6,8,9,10,12},mergedArray); + } + + /** + * Method: grow(int[] oldArray, int size) + */ + @Test + public void testGrow() throws Exception { + testArray = new int[]{1,2,3,4,5,6}; + int[] grewArray = ArrayUtil.grow(testArray,4); + Assert.assertArrayEquals(new int[]{1,2,3,4,5,6,0,0,0,0},grewArray); + + } + + /** + * Method: fibonacci(int max) + */ + @Test + public void testFibonacci() throws Exception { + int[] fibArray = ArrayUtil.fibonacci(20); + Assert.assertArrayEquals(new int[]{1,1,2,3,5,8,13},fibArray); + } + + /** + * Method: getPrimes(int max) + */ + @Test + public void testGetPrimes() throws Exception { + testArray = ArrayUtil.getPrimes(23); + Assert.assertArrayEquals(new int[]{2,3,5,7,11,13,17,19},testArray); + } + + /** + * Method: getPerfectNumbers(int max) + */ + @Test + public void testGetPerfectNumbers() throws Exception { + testArray = ArrayUtil.getPerfectNumbers(1000); + Assert.assertArrayEquals(new int[]{6,28,496},testArray); + } + + /** + * Method: join(int[] array, String seperator) + */ + @Test + public void testJoin() throws Exception { + testArray = new int[]{1,2,3,5,7,9,12}; + String seperated = ArrayUtil.join(testArray,"-"); + Assert.assertEquals("1-2-3-5-7-9-12",seperated); + } + + +} diff --git a/group27/513274874/data-structure/src/com/coding/basic/linklist/LRUPageFrame.java b/group27/513274874/data-structure/src/com/coding/basic/linklist/LRUPageFrame.java new file mode 100755 index 0000000000..a4f2c14606 --- /dev/null +++ b/group27/513274874/data-structure/src/com/coding/basic/linklist/LRUPageFrame.java @@ -0,0 +1,60 @@ +package com.coding.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(); + } + +} diff --git a/group27/513274874/data-structure/src/com/coding/basic/linklist/LRUPageFrameTest.java b/group27/513274874/data-structure/src/com/coding/basic/linklist/LRUPageFrameTest.java new file mode 100755 index 0000000000..67cf36067b --- /dev/null +++ b/group27/513274874/data-structure/src/com/coding/basic/linklist/LRUPageFrameTest.java @@ -0,0 +1,31 @@ +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/group27/513274874/data-structure/src/com/coding/basic/linklist/LinkedList.java b/group27/513274874/data-structure/src/com/coding/basic/linklist/LinkedList.java new file mode 100644 index 0000000000..e6d400f483 --- /dev/null +++ b/group27/513274874/data-structure/src/com/coding/basic/linklist/LinkedList.java @@ -0,0 +1,268 @@ + +package com.coding.basic.linklist; + +import com.coding.basic.Iterator; +import com.coding.basic.List; + +import java.util.NoSuchElementException; + +/** + * @author zhougd 20170306 + * 单向链表实现LinkedList + */ + +public class LinkedList implements List { + java.util.LinkedList a; + /** + * 第一个元素 + */ + private Node head; + + /** + * 最后一个元素 + */ + private Node tail; + + /** + * 元素容量 + */ + private int size = 0; + + public void add(Object o){ + Node node = new Node(o); + //判断是否链表为空 + if(this.size() == 0){ + this.addFirst(node); + }else{ + this.addLast(node); + } + + } + public void add(int index , Object o){ + checkIndex(index); + + Node oldNode= this.getNode(index); + Object oldObject = oldNode.getData(); + Node next = oldNode.getNext(); + + //将原位置修改为新元素 + oldNode.setData(o); + //设置下一个元素 + oldNode.setNext(new Node(oldObject)); + //设置下一个元素的下一个元素 + oldNode.getNext().setNext(next); + + size ++; + } + + public Object get(int index){ + checkIndex(index); + return this.getNode(index).getData(); + } + + public Object remove(int index){ + checkIndex(index); + //获取到当前元素和下一个元素 + //把当前元素的值设置成下一个元素的值,删除掉下一个元素,这样的话,不必管上一个元素是什么,是不是第一个元素 + Node node = this.getNode(index); + Object data = node.getData(); + Node nextNode = this.getNode(index + 1); + node.setData(nextNode.getData()); + node.setNext(nextNode.getNext()); + + return data; + } + + public int size(){ + return this.size(); + } + + public void addFirst(Object o){ + Node node = new Node(o); + //原头变为第二 + Node temp = this.head; + this.head = node; + node.next = temp; + size++; + } + public void addLast(Object o){ + Node node = new Node(o); + Node t = this.tail; + if(t == null){ + this.head = node; + }else{ + this.tail.next = node; + this.tail = node; + } + size++; + } + public Object removeFirst(){ + Node head = this.head; + if(head == null){ + throw new NoSuchElementException("No such element !"); + } + this.head = this.head.getNext(); + size--; + return head ; + } + + public Object removeLast(){ + Node node ; + if(this.tail == null){ + throw new NoSuchElementException("No such element !"); + } + node = this.tail; + if(this.head ==this.tail){ + node = this.head; + this.head = null; + this.size = 0; + }else{ + //获取尾元素的上一个元素 + this.tail = this.getNode(this.size-2); + this.tail.setNext(null); + this.size--; + } + + return node; + } + + public Iterator iterator(){ + return new LinkedListIterator(); + } + + private void checkIndex(int index){ + if(index < 0 || index >size()){ + throw new IndexOutOfBoundsException("Index out of bound !"); + } + } + + private Node getNode(int index ){ + + Node node = this.head; + for(int i = 0 ;i<size();i++){ + node = node.next; + } + return node; + } + + private class LinkedListIterator implements Iterator{ + + private int currentIndex = 0; + private int count = size(); + + @Override + public boolean hasNext() { + return currentIndex < count-1; + } + + @Override + public Object next() { + currentIndex++; + return get(currentIndex); + } + } + + private static class Node{ + Object data; + Node next; + + public Node(Object data) { + this.data = data; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + public Node getNext() { + return next; + } + + public void setNext(Node next) { + this.next = 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; + } + + +} \ No newline at end of file diff --git a/group27/513274874/data-structure/test/com/coding/basic/ArrayListTest.java b/group27/513274874/data-structure/test/com/coding/basic/ArrayListTest.java new file mode 100644 index 0000000000..251f5a8d92 --- /dev/null +++ b/group27/513274874/data-structure/test/com/coding/basic/ArrayListTest.java @@ -0,0 +1,151 @@ +package com.coding.basic; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.util.Random; + +/** +* ArrayList Tester. +* +* @author <Authors name> +* @since <pre>三月 6, 2017</pre> +* @version 1.0 +*/ +public class ArrayListTest { + +@Before +public void before() throws Exception { + +} + +@After +public void after() throws Exception { +} + +/** +* +* Method: add(Object o) +* +*/ +@Test +public void testAddO() throws Exception { + ArrayList arrayList = new com.coding.basic.ArrayList(); + arrayList.add(100); + arrayList.add(20); + + for(int i = 1 ;i <= 200 ;i++){ + arrayList.add(new Random().nextInt(100)); + } + + System.out.println(arrayList); + + assert(arrayList.size() == 202); +} + +/** +* +* Method: add(int index, Object o) +* +*/ +@Test +public void testAddForIndexO() throws Exception { + ArrayList arrayList = new com.coding.basic.ArrayList(); + arrayList.add(1); + arrayList.add(2); + arrayList.add(3); + arrayList.add(4); + arrayList.add(5); + + arrayList.add(3,"添加"); + //arrayList.add(100,3); + assert(arrayList.size() == 6); + System.out.println(arrayList); +} + +/** +* +* Method: get(int index) +* +*/ +@Test +public void testGet() throws Exception { + ArrayList arrayList = new com.coding.basic.ArrayList(); + arrayList.add(1); + arrayList.add(2); + arrayList.add(3); + arrayList.add(4); + arrayList.add(5); + + assert(((Integer)arrayList.get(3)).intValue() == 4); +} + +/** +* +* Method: remove(int index) +* +*/ +@Test +public void testRemove() throws Exception { + ArrayList arrayList = new com.coding.basic.ArrayList(); + arrayList.add(1); + arrayList.add(2); + arrayList.add(3); + arrayList.add(4); + arrayList.add(5); + + arrayList.remove(3); + //arrayList.add(100,3); + assert(arrayList.size() == 4); + System.out.println(arrayList); +} + +/** +* +* Method: size() +* +*/ +@Test +public void testSize() throws Exception { +//TODO: Test goes here... + + ArrayList arrayList = new com.coding.basic.ArrayList(); + arrayList.add(100); + arrayList.add(20); + + for(int i = 1 ;i <= 200 ;i++){ + arrayList.add(new Random().nextInt(100)); + } + + System.out.println(arrayList); + + assert(arrayList.size() == 202); +} + +/** +* +* Method: iterator() +* +*/ +@Test +public void testIterator() throws Exception { +//TODO: Test goes here... + ArrayList arrayList = new com.coding.basic.ArrayList(); + arrayList.add(100); + arrayList.add(20); + + for(int i = 1 ;i <= 200 ;i++){ + arrayList.add(new Random().nextInt(100)); + } + System.out.println(arrayList); + + Iterator iterator = arrayList.iterator(); + while(iterator.hasNext()){ + System.out.print(iterator.next() + ","); + } + + assert(arrayList.size() == 202); +} + +} 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 new file mode 100755 index 0000000000..86d4619407 --- /dev/null +++ b/group27/513274874/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,34 @@ +package com.coderising.jvm.loader; + +import java.util.ArrayList; +import java.util.List; + + + +public class ClassFileLoader { + + private List<String> clzPaths = new ArrayList<String>(); + + public byte[] readBinaryCode(String className) { + + return null; + + + } + + + public void addClassPath(String path) { + + } + + + + public String getClassPath(){ + return null; + } + + + + + +} 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 new file mode 100755 index 0000000000..a05534b210 --- /dev/null +++ b/group27/513274874/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,92 @@ +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(); + } + +} diff --git a/group27/513274874/mini-jvm/src/com/coderising/jvm/test/EmployeeV1.java b/group27/513274874/mini-jvm/src/com/coderising/jvm/test/EmployeeV1.java new file mode 100755 index 0000000000..9a36573dd3 --- /dev/null +++ b/group27/513274874/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 From 64076d152bf55e2a28878a251e448063c216d94d Mon Sep 17 00:00:00 2001 From: OnlyLYJ <382266293@qq.com> Date: Mon, 27 Mar 2017 22:05:08 +0800 Subject: [PATCH 054/287] jvm1 done --- .../com/coderising/download/DownloadUtil.java | 2 +- .../coderising/download/FileDownloader.java | 10 +- .../download/impl/ConnectionImpl.java | 14 ++- .../jvm/loader/ClassFileLoader.java | 94 +++++++++++++++ .../jvm/test/ClassFileloaderTest.java | 80 +++++++++++++ .../com/coderising/jvm/test/EmployeeV1.java | 30 +++++ .../{action => litestruts}/LoginAction.java | 2 +- .../src/litestruts/Configuration.java | 109 +++++++++++------- .../src/litestruts/ConfigurationTest.java | 40 +++++-- .../382266293/src/litestruts/StrutsTest.java | 12 +- group12/382266293/src/litestruts/struts.xml | 4 +- 11 files changed, 335 insertions(+), 62 deletions(-) create mode 100644 group12/382266293/src/com/coderising/jvm/loader/ClassFileLoader.java create mode 100644 group12/382266293/src/com/coderising/jvm/test/ClassFileloaderTest.java create mode 100644 group12/382266293/src/com/coderising/jvm/test/EmployeeV1.java rename group12/382266293/src/com/coderising/{action => litestruts}/LoginAction.java (92%) diff --git a/group12/382266293/src/com/coderising/download/DownloadUtil.java b/group12/382266293/src/com/coderising/download/DownloadUtil.java index 8e8f2de727..b01200c51d 100644 --- a/group12/382266293/src/com/coderising/download/DownloadUtil.java +++ b/group12/382266293/src/com/coderising/download/DownloadUtil.java @@ -45,7 +45,7 @@ public static void createTempFile(String tempName, int len) { } public static int calculateConnects(int length) { - int conns = length / 1024 / 1024 / 25; + int conns = length / 1024 / 1024 / 10; if (conns < MIN_CONNECTIONS) { return MIN_CONNECTIONS; } else if (conns > MAX_CONNECTIONS) { diff --git a/group12/382266293/src/com/coderising/download/FileDownloader.java b/group12/382266293/src/com/coderising/download/FileDownloader.java index cc77b380a9..c756248bb1 100644 --- a/group12/382266293/src/com/coderising/download/FileDownloader.java +++ b/group12/382266293/src/com/coderising/download/FileDownloader.java @@ -44,7 +44,7 @@ public void execute() { try { Connection conn = cm.open(this.url); int length = conn.getContentLength(); - checkLength(length, conn); + System.out.println("file length:" + length); setLocation("C:\\"); @@ -52,7 +52,8 @@ public void execute() { String name = conn.getFileName(); setFileName(name); setTempName(name); - + checkLength(length, conn); + DownloadUtil.createTempFile(tempName, length); int connNumbers = DownloadUtil.calculateConnects(length); @@ -143,14 +144,17 @@ private void setAndStartThreadPool(Connection conn, DownloadThread[] threadPool, threadPool[0] = new DownloadThread(conn, beginPos, endPos); setAndStartThread(threadPool[0], tempName); for (int i = 1; i < connectionNumbers; i++) { - Connection con = cm.open(this.url); beginPos = endPos + 1; endPos = beginPos + batch_size; + Connection con = cm.open(this.url); + if (i == connectionNumbers - 1) { endPos = length - 1; } threadPool[i] = new DownloadThread(con, beginPos, endPos); setAndStartThread(threadPool[i], tempName); + + } } diff --git a/group12/382266293/src/com/coderising/download/impl/ConnectionImpl.java b/group12/382266293/src/com/coderising/download/impl/ConnectionImpl.java index 05f31103de..61ed430106 100644 --- a/group12/382266293/src/com/coderising/download/impl/ConnectionImpl.java +++ b/group12/382266293/src/com/coderising/download/impl/ConnectionImpl.java @@ -33,17 +33,27 @@ public byte[] read(int startPos, int endPos) throws IOException { InputStream in = null; ByteArrayOutputStream out = null; try { + httpConn = (HttpURLConnection) url.openConnection(); + httpConn.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos); in = httpConn.getInputStream(); out = new ByteArrayOutputStream(); in = httpConn.getInputStream(); - in.skip(startPos); - byte[] buffer = new byte[endPos-startPos + 1]; + //in.skip(startPos); + int len = 0; byte[] b = new byte[1024]; while((len = in.read(b)) != -1) { out.write(b, 0, len); } + int totalLen = endPos - startPos + 1; + + if (out.size() > totalLen) { + byte[] data = out.toByteArray(); + return data; + } + return out.toByteArray(); + } catch (IOException e) { e.printStackTrace(); } diff --git a/group12/382266293/src/com/coderising/jvm/loader/ClassFileLoader.java b/group12/382266293/src/com/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..f007721e53 --- /dev/null +++ b/group12/382266293/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,94 @@ +package com.coderising.jvm.loader; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.ArrayList; +import java.util.List; + +public class ClassFileLoader { + + private List<String> clzPaths = new ArrayList<String>(); + + public byte[] readBinaryCode(String className) { + + String clzFileName = "//" + className.replaceAll("\\.", "//") + ".class"; + return loadClassFile(clzFileName); + + } + + @SuppressWarnings("resource") + private byte[] loadClassFile(String clzFileName) { + File classFile = getClassFile(clzFileName); + if (null == classFile) { + try { + throw new ClassNotFoundException(clzFileName + " does not exist."); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + + RandomAccessFile raf = null; + ByteArrayOutputStream out = null; + try { + out = new ByteArrayOutputStream(); + raf = new RandomAccessFile(classFile, "r"); + int len = 0; + byte[] b = new byte[1024]; + while ((len = raf.read(b)) != -1) { + out.write(b, 0, len); + } + int totalLen = (int) classFile.length(); + + if (out.size() > totalLen) { + byte[] data = out.toByteArray(); + return data; + } + + return out.toByteArray(); + + } catch (IOException e) { + e.printStackTrace(); + } + return null; + + } + + private File getClassFile(String clzFileName) { + + for (String path : clzPaths) { + File file = new File(path + "//" + clzFileName); + if (file.exists()) { + return file; + } + } + return null; + + } + + public void addClassPath(String path) { + clzPaths.add(path); + } + + public String getClassPath_V1() { + + return null; + } + + public String getClassPath() { + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < clzPaths.size(); i++) { + + sb.append(clzPaths.get(i)); + if (i < clzPaths.size() - 1) { + sb.append(";"); + } + + } + + return sb.toString(); + } + +} diff --git a/group12/382266293/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group12/382266293/src/com/coderising/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..fb2f3be0a6 --- /dev/null +++ b/group12/382266293/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,80 @@ +package com.coderising.jvm.test; + +import java.util.Arrays; + +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\\Administrator\\git\\coding2017n\\group12\\382266293\\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/group12/382266293/src/com/coderising/jvm/test/EmployeeV1.java b/group12/382266293/src/com/coderising/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..d36b122f60 --- /dev/null +++ b/group12/382266293/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 diff --git a/group12/382266293/src/com/coderising/action/LoginAction.java b/group12/382266293/src/com/coderising/litestruts/LoginAction.java similarity index 92% rename from group12/382266293/src/com/coderising/action/LoginAction.java rename to group12/382266293/src/com/coderising/litestruts/LoginAction.java index b1224eb80d..a3ce652047 100644 --- a/group12/382266293/src/com/coderising/action/LoginAction.java +++ b/group12/382266293/src/com/coderising/litestruts/LoginAction.java @@ -1,4 +1,4 @@ -package com.coderising.action; +package com.coderising.litestruts; /** * 这是一个用来展示登录的业务类, 其中的用户名和密码都是硬编码的。 diff --git a/group12/382266293/src/litestruts/Configuration.java b/group12/382266293/src/litestruts/Configuration.java index 9b7d4e8466..4efedbce67 100644 --- a/group12/382266293/src/litestruts/Configuration.java +++ b/group12/382266293/src/litestruts/Configuration.java @@ -1,9 +1,9 @@ package 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; @@ -11,15 +11,13 @@ import static util.Print.*; public class Configuration { - - ActionCfg actionCfg = new ActionCfg(); - + Map<String,ActionCfg> actions = new HashMap<>(); + private static Configuration cfg = new Configuration(); private Configuration() { - + } - public static Configuration getNewInstance() { if (cfg == null) { @@ -28,75 +26,108 @@ public static Configuration getNewInstance() { return cfg; } - private String getFile(String fileName) { + public void parse(String fileName) { String src = this.getClass().getPackage().getName(); - return "file://" + src + "\\" + fileName + ".xml"; + String filepath = src.replace(".", "/") + "/" +fileName; + + InputStream is = this.getClass().getResourceAsStream("/" + filepath); + + parseXML(is); + + try { + is.close(); + } catch (IOException e) { + + } + } - public void parseAction(String src) { - - String fileName = getFile(src); + public void parseXML(InputStream is) { + SAXBuilder reader = new SAXBuilder(); try { - Document doc = reader.build("C:\\struts.xml"); + Document doc = reader.build(is); Element root = doc.getRootElement(); for(Element element : root.getChildren("action")) { - String name = element.getAttributeValue("name"); + String actionName = element.getAttributeValue("name"); String clz = element.getAttributeValue("class"); - actionCfg.actionInfo.put(name, clz); + ActionCfg ac = new ActionCfg(actionName,clz); for(Element e : element.getChildren("result")) { String result = e.getAttributeValue("name"); String jsp = e.getText().trim(); - println("result:" + result + "jsp:" + jsp); - Map<String,String> res = new HashMap<>(); - res.put(result, jsp); - actionCfg.resultInfo.put(name, res); + 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(); + } + + + public String getResultView(String action, String resultName) { + ActionCfg cfg = this.actions.get(action); + if (cfg == null) { + return null; + } + return cfg.getViewResult().get(resultName); } public static void main(String[] args) { Configuration cfg = new Configuration(); - cfg.parseAction("struts"); - Map info = cfg.getActionInfo(); - Map result = cfg.getResultInfo().get("login"); - println(info); - println(result); + cfg.parse("struts.xml"); + String clz = cfg.getClassName("login"); + println(clz); + + } + private static class ActionCfg { - private Map<String,String> actionInfo; - private Map<String,Map<String,String>> resultInfo; - public ActionCfg() { - this.actionInfo = new HashMap<String,String>(); - this.resultInfo = new HashMap<String,Map<String,String>>(); + String name; + String clz; + Map<String,String> viewResult = new HashMap<>(); + + public Map<String, String> getViewResult() { + return viewResult; + } + + public ActionCfg(String name, String clz) { + this.name = name; + this.clz = clz; } - - } + public void addViewResult(String result, String jsp) { + viewResult.put(result, jsp); + + } - public Map<String, Map<String,String>> getResultInfo() { - - return actionCfg.resultInfo; - } + public String getClassName() { + return clz; + } - public Map<String, String> getActionInfo() { - - return actionCfg.actionInfo; } - + + + diff --git a/group12/382266293/src/litestruts/ConfigurationTest.java b/group12/382266293/src/litestruts/ConfigurationTest.java index 1b5d2f43e1..e9d41a07c9 100644 --- a/group12/382266293/src/litestruts/ConfigurationTest.java +++ b/group12/382266293/src/litestruts/ConfigurationTest.java @@ -1,32 +1,54 @@ package litestruts; -import java.util.HashMap; -import java.util.Map; - import org.junit.After; +import org.junit.Assert; 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"); } @After public void tearDown() throws Exception { + } @Test - public void testGetGetterMethods() { - Configuration cfg = Configuration.getNewInstance(); - Map<String,String> actionName = new HashMap<>(); - actionName.put("login","com.coderising.action.LoginAction"); - actionName.put("logout","com.coderising.action.LogoutAction"); + 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"); + Assert.assertEquals("/jsp/homepage.jsp", jsp); - //Assert.assertTrue(cfg.getActionName().containsKey(actionName)); + 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/group12/382266293/src/litestruts/StrutsTest.java b/group12/382266293/src/litestruts/StrutsTest.java index 35686c8e30..4b59f846f5 100644 --- a/group12/382266293/src/litestruts/StrutsTest.java +++ b/group12/382266293/src/litestruts/StrutsTest.java @@ -1,17 +1,19 @@ package litestruts; -import java.beans.IntrospectionException; -import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; import org.junit.Assert; import org.junit.Test; + + + + public class StrutsTest { @Test - public void testLoginActionSuccess() throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException { + public void testLoginActionSuccess() { String actionName = "login"; @@ -27,7 +29,7 @@ public void testLoginActionSuccess() throws InstantiationException, IllegalAcces } @Test - public void testLoginActionFailed() throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException { + public void testLoginActionFailed() { String actionName = "login"; Map<String,String> params = new HashMap<String,String>(); params.put("name","test"); @@ -38,4 +40,4 @@ public void testLoginActionFailed() throws InstantiationException, IllegalAccess Assert.assertEquals("/jsp/showLogin.jsp", view.getJsp()); Assert.assertEquals("login failed,please check your user/pwd", view.getParameters().get("message")); } -} \ No newline at end of file +} diff --git a/group12/382266293/src/litestruts/struts.xml b/group12/382266293/src/litestruts/struts.xml index fb0c2be3de..4c6eeabbd4 100644 --- a/group12/382266293/src/litestruts/struts.xml +++ b/group12/382266293/src/litestruts/struts.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8"?> <struts> - <action name="login" class="com.coderising.action.LoginAction"> + <action name="login" class="com.coderising.litestruts.LoginAction"> <result name="success">/jsp/homepage.jsp</result> <result name="fail">/jsp/showLogin.jsp</result> </action> - <action name="logout" class="com.coderising.action.LogoutAction"> + <action name="logout" class="com.coderising.litestruts.LogoutAction"> <result name="success">/jsp/welcome.jsp</result> <result name="error">/jsp/error.jsp</result> </action> From 08fb35fc227f1e9fdc96135fd862380923b36041 Mon Sep 17 00:00:00 2001 From: OnlyLYJ <382266293@qq.com> Date: Mon, 27 Mar 2017 22:08:40 +0800 Subject: [PATCH 055/287] 1 --- .../382266293/src/com/coderising/jvm/loader/ClassFileLoader.java | 1 - 1 file changed, 1 deletion(-) diff --git a/group12/382266293/src/com/coderising/jvm/loader/ClassFileLoader.java b/group12/382266293/src/com/coderising/jvm/loader/ClassFileLoader.java index f007721e53..9ba4ff935b 100644 --- a/group12/382266293/src/com/coderising/jvm/loader/ClassFileLoader.java +++ b/group12/382266293/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -15,7 +15,6 @@ public byte[] readBinaryCode(String className) { String clzFileName = "//" + className.replaceAll("\\.", "//") + ".class"; return loadClassFile(clzFileName); - } @SuppressWarnings("resource") From 375887c22c0d6fd17a32e5eee278bba45b791205 Mon Sep 17 00:00:00 2001 From: maishihang <446031103@qq.com> Date: Mon, 27 Mar 2017 22:35:40 +0800 Subject: [PATCH 056/287] update 3 weekwork update 3 weekwork --- .../src/com/coding/basic/LinkedList.java | 144 ++++++++++-------- 1 file changed, 84 insertions(+), 60 deletions(-) diff --git a/group12/446031103/src/com/coding/basic/LinkedList.java b/group12/446031103/src/com/coding/basic/LinkedList.java index 33f6d79e65..d60f4a2dee 100644 --- a/group12/446031103/src/com/coding/basic/LinkedList.java +++ b/group12/446031103/src/com/coding/basic/LinkedList.java @@ -1,11 +1,5 @@ package com.coding.basic; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -import org.junit.experimental.theories.Theories; - -import sun.reflect.Reflection; +import java.util.Stack; /** * @@ -233,13 +227,21 @@ public Node(Object data, Node next) { * 把该链表逆置 * 例如链表为 3->7->10 , 逆置后变为 10->7->3 */ - public void reverse(){ - for (int i = size; i <0; i--) { - Node last=(Node) get(i); - if(0==i) - last.next = null; - else - last.next = (Node) get(i-1); + public void reverse(){ + Stack s=new Stack(); + Node currentNode = head; + while(null!=currentNode){ + s.push(currentNode); + Node tempNode=currentNode.next; + currentNode.next = null; + currentNode = tempNode; + } + head = (Node) s.pop(); + currentNode= head; + while(!s.isEmpty()){ + Node tempNode=(Node) s.pop(); + currentNode.next = tempNode; + currentNode = tempNode; } } @@ -250,7 +252,7 @@ public void reverse(){ */ public void removeFirstHalf(){ - for (int i = 0; i < size%2; i++) { + for (int i = 0; i < size/2; i++) { remove(i); } } @@ -261,10 +263,15 @@ public void removeFirstHalf(){ * @param length */ public void remove(int i, int length){ - for (int a = i; a < i+length; a++) { - remove(a); + if(i<0||i>=size){ + throw new IndexOutOfBoundsException(); + } + int len = size-1>=length?length:size-1; + int k = 0; + while(k<len){ + remove(i); + k++; } - } /** * 假定当前链表和list均包含已升序排列的整数 @@ -274,29 +281,12 @@ public void remove(int i, int length){ * 返回的结果应该是[101,301,401,601] * @param list */ - public static int[] getElements(LinkedList list){ - int [] result =new int[list.size]; - Class<?> callClass=Reflection.getCallerClass(); + public int[] getElements(LinkedList list){ + int [] arr = new int [list.size()]; for (int i = 0; i < list.size; i++) { - Node node=(Node) list.get(i); - try { - Method method=callClass.getDeclaredMethod("get", new Class[]{int.class}); - result[i]=(int) method.invoke(callClass, new Object[]{node.data}); - } catch (NoSuchMethodException | SecurityException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (InvocationTargetException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + arr[i] = (int) get((int)list.get(i)); } - return null; + return arr; } /** @@ -321,15 +311,29 @@ public void subtract(LinkedList list){ /** * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 * 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) + * @throws Exception */ - public void removeDuplicateValues(){ - for (int i = 0; i < size; i++) { - Node node=(Node) get(i); - for (int j = i+1; j < size; j++) { - Node newNode=(Node) get(j); - if(newNode.data.equals(node.data)) - remove(j); + public void removeDuplicateValues() throws Exception{ + if(null==head){ + throw new Exception(); + } + Node pre = head; + Node cur =head; + while(null!=cur.next){ + cur = cur.next; + Object o=pre.data; + while(cur.data == o){ + if(null==cur.next){ + pre.next = null; + } + pre.next = cur.next; + size--; + cur = cur.next; + if(null==cur){ + break; + } } + pre = pre.next; } } @@ -340,11 +344,24 @@ public void removeDuplicateValues(){ * @param max */ public void removeRange(int min, int max){ - for (int i = 0; i < size; i++) { - Node node=(Node) get(i); - if((int)node.data>min && (int)node.data<max) - remove(i); + if(null==head){ + return ; + } + Node node = head; + int star = 0; + int end = 0; + int i = 0; + while(null!=node){ + if((int)node.data<=min){ + star = i; + } + if((int)node.data>=max){ + end = i; + break; + } + i++; } + remove(star,end-star); } /** @@ -352,17 +369,24 @@ public void removeRange(int min, int max){ * 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列 * @param list */ - public LinkedList intersection( LinkedList list){ + public LinkedList intersection( LinkedList list){ + if(list==null){ + return null; + } LinkedList newList = new LinkedList(); - for (int i = 0; i < size; i++) { - Node node=(Node) get(i); - for (int j = 0; j < list.size; j++) { - Node newNode=(Node) get(j); - if(newNode.data.equals(node.data)){ - newList.add(node); - break; - } - + int i1=0; + int i2=0; + if(i1<this.size&&i2<list.size()){ + int value1=(int) this.get(i1); + int value2=(int) list.get(i2); + if(value1==value2){ + newList.add(value2); + i1++; + i2++; + }else if(value1<value2){ + i1++; + }else if(value1>value2){ + i2++; } } return newList; From d8e6fb5d403d913fa375f7fafb4548619faeebb0 Mon Sep 17 00:00:00 2001 From: 592146505 <592146505@qq.com> Date: Tue, 28 Mar 2017 09:26:42 +0800 Subject: [PATCH 057/287] 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<E> implements List<E> { + private int size; + private Node<E> head; + + private static class Node<E> { + E data; + Node<E> next; + + Node(E data) { + super(); + this.data = data; + } + + Node(E data, Node<E> 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<E> oldHead = head; + Node<E> newHead = new Node<E>(e); + head = newHead; + // 将原头节点作为新头节点的下一个节点 + head.next = oldHead; + size++; + } + + /** + * 向尾部添加元素 + * + * @param e + */ + void linkLast(E e) { + Node<E> newNode = new Node<E>(e); + if (head == null) { + head = newNode; + } else { + Node<E> 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<E> node) { + Node<E> oldNext = head; + node.next = new Node<E>(e, oldNext); + size++; + } + + public E get(int index) { + checkElementIndex(index); + return node(index).data; + } + + /** + * 获取指定索引处元素,调用此方法请确保索引范围正确 + * + * @param index + * @return + */ + Node<E> node(int index) { + Node<E> node = head; + for (int i = 0; i < index; i++) { + node = node.next; + } + return node; + } + + public E remove(int index) { + checkElementIndex(index); + Node<E> 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<E> unlinkNext(Node<E> node){ + Node<E> 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> 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 8ed01b996e818aaf7efb90772ef13d1e7ff52565 Mon Sep 17 00:00:00 2001 From: txp-reps <tangxp@sunline.cn> Date: Tue, 28 Mar 2017 10:59:04 +0800 Subject: [PATCH 058/287] =?UTF-8?q?=E7=AC=AC=E4=B8=89=E6=AC=A1=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coderising/download/DownloadThread.java | 62 +++ .../coderising/download/FileDownloader.java | 115 +++++ .../download/FileDownloaderTest.java | 58 +++ .../coderising/download/api/Connection.java | 29 ++ .../download/api/ConnectionException.java | 5 + .../download/api/ConnectionManager.java | 11 + .../download/api/DownloadListener.java | 5 + .../download/impl/ConnectionImpl.java | 87 ++++ .../download/impl/ConnectionManagerImpl.java | 42 ++ .../main/java/com/coding/basic/ArrayList.java | 241 ++++----- .../java/com/coding/basic/LinkedList.java | 483 +++++++++++++----- .../java/com/coding/basic/TestLinkedList.java | 110 ++++ .../src/test/java/com/txp/temp/Test.java | 9 + 13 files changed, 1004 insertions(+), 253 deletions(-) create mode 100644 group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/DownloadThread.java create mode 100644 group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/FileDownloader.java create mode 100644 group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/FileDownloaderTest.java create mode 100644 group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/api/Connection.java create mode 100644 group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/api/ConnectionException.java create mode 100644 group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/api/ConnectionManager.java create mode 100644 group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/api/DownloadListener.java create mode 100644 group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/impl/ConnectionImpl.java create mode 100644 group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/impl/ConnectionManagerImpl.java create mode 100644 group04/821655640/learning_projects/project_basic_001/src/test/java/com/coding/basic/TestLinkedList.java create mode 100644 group04/821655640/learning_projects/project_basic_001/src/test/java/com/txp/temp/Test.java diff --git a/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/DownloadThread.java b/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/DownloadThread.java new file mode 100644 index 0000000000..c1c4bc9032 --- /dev/null +++ b/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/DownloadThread.java @@ -0,0 +1,62 @@ +package com.coderising.download; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; + +import com.coderising.download.api.Connection; + +public class DownloadThread extends Thread{ + + Connection conn; + int startPos; + int endPos; + private RandomAccessFile tempFile = null; + public DownloadThread( Connection conn, RandomAccessFile tempFile,String treadName){ + super.setName(treadName); + this.conn = conn; + this.startPos = conn.getStartPos(); + this.endPos = conn.getEndPos(); + this.tempFile = tempFile; + } + public void run(){ + + byte buf[] = null; + int count = (endPos - startPos)/1024; + int seekPos = 0; + try { + for (int i = 1; i < count; i++) { + System.out.println(this.getName() + " : " + (startPos+ 1024*(i-1)) + "-------" + (startPos + 1024*i) ); + buf = new byte[1024]; + conn.read(buf); + seekPos = startPos+ 1024*(i-1); + if (0 != seekPos) { + seekPos--; + } + tempFile.seek(seekPos); + writeToFile(buf); + buf = null; + } + + System.out.println(this.getName() + " : " + (startPos+ 1024*(count-1)) + "------- " + (endPos) ); + buf = new byte[endPos-(startPos+ 1024*(count-1))]; + conn.read(buf); + seekPos = startPos+ 1024*(count-1)-1; + tempFile.seek(seekPos); + writeToFile(buf); + + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private synchronized void writeToFile(byte[] buf) throws IOException { + tempFile.write(buf, 0, buf.length); + } + + + + +} diff --git a/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/FileDownloader.java b/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/FileDownloader.java new file mode 100644 index 0000000000..d1c189316b --- /dev/null +++ b/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/FileDownloader.java @@ -0,0 +1,115 @@ +package com.coderising.download; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.net.URL; +import java.util.UUID; + +import com.coderising.download.api.Connection; +import com.coderising.download.api.ConnectionException; +import com.coderising.download.api.ConnectionManager; +import com.coderising.download.api.DownloadListener; + + +public class FileDownloader { + + private String url; + private String localPath = ""; + private DownloadListener listener; + private 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方法 + + // 下面的代码是示例代码, 也就是说只有一个线程, 你需要改造成多线程的。 + try { + + int length = cm.open(url).getContentLength(); + RandomAccessFile tempFile = CreateTempFile(localPath,cm.open(url)); + + int step = length / 4; + DownloadThread downloadThread0 = new DownloadThread(cm.open(this.url,0,step-1),tempFile,"downLoad_Thread0"); + DownloadThread downloadThread1 = new DownloadThread(cm.open(this.url,step,2*step-1),tempFile,"downLoad_Thread1"); + DownloadThread downloadThread2 = new DownloadThread(cm.open(this.url,2*step,3*step-1),tempFile,"downLoad_Thread2"); + DownloadThread downloadThread3 = new DownloadThread(cm.open(this.url,3*step,length),tempFile,"downLoad_Thread3"); + downloadThread0.start(); + downloadThread1.start(); + downloadThread2.start(); + downloadThread3.start(); + + while(true) { + if (!(downloadThread0.isAlive()||downloadThread1.isAlive()||downloadThread2.isAlive()||downloadThread3.isAlive())) { + tempFile.close(); + this.listener.notifyFinished(); + break; + } + } + + } catch (ConnectionException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + + private RandomAccessFile CreateTempFile(String path,Connection _conn) { + String tempFileName = UUID.randomUUID().toString() + ".jpg"; + RandomAccessFile randomAccessFile = null; + try { + randomAccessFile = new RandomAccessFile(path + File.separator +tempFileName,"rw"); + randomAccessFile.setLength(_conn.getContentLength()); + } catch (FileNotFoundException e1) { + e1.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + + return randomAccessFile; + } + + private boolean ChangeFileName(File _f,Connection _conn) { + String fileName = _conn.getURL().getFile().substring(url.lastIndexOf("/")); + return _f.renameTo(new File(_f.getAbsolutePath()+File.separator+fileName)); + } + + public void setListener(DownloadListener listener) { + this.listener = listener; + } + + + + public void setConnectionManager(ConnectionManager ucm){ + this.cm = ucm; + } + + public DownloadListener getListener(){ + return this.listener; + } + public String getLocalPath() { + return localPath; + } + + public void setLocalPath(String localPath) { + this.localPath = localPath; + } + +} diff --git a/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/FileDownloaderTest.java b/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/FileDownloaderTest.java new file mode 100644 index 0000000000..be1fbff668 --- /dev/null +++ b/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/FileDownloaderTest.java @@ -0,0 +1,58 @@ +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 = "https://static.oschina.net/uploads/img/201701/09170848_HsPK.jpg"; + + FileDownloader downloader = new FileDownloader(url); + downloader.setLocalPath("E:/temp_backup/temp"); + + ConnectionManager cm = new ConnectionManagerImpl(); + downloader.setConnectionManager(cm); + + downloader.setListener(new DownloadListener() { + 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/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/api/Connection.java b/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/api/Connection.java new file mode 100644 index 0000000000..cd390c9296 --- /dev/null +++ b/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/api/Connection.java @@ -0,0 +1,29 @@ +package com.coderising.download.api; + +import java.io.IOException; +import java.net.URL; + +public interface Connection { + + /** + * 给定开始和结束位置, 读取数据, 返回值是字节数组 + * @param startPos 开始位置, 从0开始 + * @param endPos 结束位置 + * @return + */ + public int read(byte data[]) throws IOException; + /** + * 得到数据内容的长度 + * @return + */ + public int getContentLength(); + + /** + * 关闭连接 + */ + public void close(); + + public URL getURL(); + public int getStartPos(); + public int getEndPos(); +} diff --git a/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/api/ConnectionException.java b/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/api/ConnectionException.java new file mode 100644 index 0000000000..f4f05269df --- /dev/null +++ b/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/api/ConnectionException.java @@ -0,0 +1,5 @@ +package com.coderising.download.api; + +public class ConnectionException extends Exception { + private static final long serialVersionUID = 4776347926322882920L; +} diff --git a/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/api/ConnectionManager.java b/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/api/ConnectionManager.java new file mode 100644 index 0000000000..0b3167cd90 --- /dev/null +++ b/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/api/ConnectionManager.java @@ -0,0 +1,11 @@ +package com.coderising.download.api; + +public interface ConnectionManager { + /** + * 给定一个url , 打开一个连接 + * @param url + * @return + */ + public Connection open(String url,int startPos ,int endPos) throws ConnectionException; + public Connection open(String url) throws ConnectionException; +} diff --git a/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/api/DownloadListener.java b/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/api/DownloadListener.java new file mode 100644 index 0000000000..4cd0b3eab1 --- /dev/null +++ b/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/api/DownloadListener.java @@ -0,0 +1,5 @@ +package com.coderising.download.api; + +public interface DownloadListener { + public void notifyFinished(); +} diff --git a/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/impl/ConnectionImpl.java b/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/impl/ConnectionImpl.java new file mode 100644 index 0000000000..4d6fbc4b87 --- /dev/null +++ b/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/impl/ConnectionImpl.java @@ -0,0 +1,87 @@ +package com.coderising.download.impl; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; + +import com.coderising.download.api.Connection; + +public class ConnectionImpl implements Connection{ + + private URLConnection uc = null; + private BufferedInputStream bs = null; + private URL url; + int startPos; + int endPos; + public ConnectionImpl(String path,int _startPos,int _endPos) throws Exception { + try { + if (startPos >= _endPos || _startPos < 0) { + throw new IllegalArgumentException(); + } + this.startPos = _startPos; + this.endPos = _endPos; + url = new URL(path); + uc = url.openConnection(); + uc.setRequestProperty("Range", "bytes=" + _startPos + "-" + _endPos); + bs = new BufferedInputStream(uc.getInputStream()); + } catch (MalformedURLException e) { + e.printStackTrace(); + throw e; + } catch (IOException e) { + e.printStackTrace(); + throw e; + } + } + public ConnectionImpl(String path) throws Exception { + try { + + url = new URL(path); + uc = url.openConnection(); + } catch (MalformedURLException e) { + e.printStackTrace(); + throw e; + } catch (IOException e) { + e.printStackTrace(); + throw e; + } + } + + public int read(byte data[]) { + int ret = 0; + try { + ret = bs.read(data); + } catch (IOException e) { + e.printStackTrace(); + } + return ret; + } + + public int getContentLength() { + return uc.getContentLength(); + } + + public URL getURL() { + return url; + } + + public void close() { + try { + if (null != bs) { + bs.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + + } + + public int getStartPos() { + return this.startPos; + } + public int getEndPos() { + return this.endPos; + } + +} diff --git a/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/impl/ConnectionManagerImpl.java b/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/impl/ConnectionManagerImpl.java new file mode 100644 index 0000000000..68a5b7a7fc --- /dev/null +++ b/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coderising/download/impl/ConnectionManagerImpl.java @@ -0,0 +1,42 @@ +package com.coderising.download.impl; + + +import com.coderising.download.api.Connection; +import com.coderising.download.api.ConnectionException; +import com.coderising.download.api.ConnectionManager; + +public class ConnectionManagerImpl implements ConnectionManager { + + public Connection open(String url,int startPos ,int endPos) throws ConnectionException { + if (null == url || "".equals(url)) { + throw new IllegalArgumentException("参数异常"); + } + + Connection conn = null; + try { + conn = new ConnectionImpl(url,startPos,endPos); + } catch (Exception e) { + e.printStackTrace(); + throw new ConnectionException(); + } + + return conn; + } + + public Connection open(String url) throws ConnectionException { + if (null == url || "".equals(url)) { + throw new IllegalArgumentException("参数异常"); + } + + Connection conn = null; + try { + conn = new ConnectionImpl(url); + } catch (Exception e) { + e.printStackTrace(); + throw new ConnectionException(); + } + + return conn; + } + +} diff --git a/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coding/basic/ArrayList.java b/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coding/basic/ArrayList.java index c168b5efa8..ee70db2150 100644 --- a/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coding/basic/ArrayList.java +++ b/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coding/basic/ArrayList.java @@ -1,119 +1,122 @@ -package com.coding.basic; - -/** - * @ClassName: ArrayList - * @Description: 自增长数组 - * @author: tangxp - * @date: 2017年2月23日 下午10:43:03 - */ -public class ArrayList implements List { - - private final int step = 10; - private Object elementData[] = new Object[100]; - private int size = 0 ; - - - /** - * @Title: add - * @Description: TODO - * @param o , elements of this ArrayList - * @see com.coding.basic.List#add(java.lang.Object) - */ - public void add(Object o) { - add(size,o); - } - - - /** - * @Title: add - * @Description: TODO - * @param index - * @param o - * @see com.coding.basic.List#add(int, java.lang.Object) - */ - public void add(int index, Object o) { - if(index < 0 || index> size) { - throw new IllegalArgumentException("下标越界"); - } - - if(null == o) { - throw new IllegalArgumentException("元素不能为空"); - } - - if(this.checkOutOfBounds()) { - this.autoGrow(this.step); - } - - int i = size; - while(i>index) { - elementData[i] = elementData[--i]; - } - addDriect(i, o); - } - - - public Object get(int index) { - if(index < 0 || index>= size) { - throw new IllegalArgumentException("下标越界"); - } - - return elementData[index]; - } - - public Object remove(int index) { - if(index < 0 || index>= size) { - throw new IllegalArgumentException("下标越界"); - } - - Object o = elementData[index]; - while (index<size-1) { - elementData[index] = elementData[++index]; - } - elementData[size] = null; - this.size--; - return o; - } - - public int size() { - return this.size; - } - - - /** - * @param growSize - * 扩展elementData数组growSize大小 - */ - private void autoGrow(int growSize) { - if (elementData.length>this.size) { - return; - } - Object newElementData[] = new Object[elementData.length+growSize]; - System.arraycopy(elementData, 0, newElementData, 0, elementData.length); - elementData = newElementData; - return; - } - - private void addDriect(int index, Object o) { - elementData[index] = o; - this.size++; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder("["); - for(int i =0;i<this.size;i++) { - sb.append(elementData[i].toString()); - sb.append(","); - } - sb.replace(sb.length()-1, sb.length(), "]"); - return sb.toString(); - } - - private boolean checkOutOfBounds() { - if (elementData.length>this.size) { - return false; - }else { - return true; - } - } -} +package com.coding.basic; + +import java.util.concurrent.CyclicBarrier; + +/** + * @ClassName: ArrayList + * @Description: 自增长数组 + * @author: tangxp + * @date: 2017年2月23日 下午10:43:03 + */ +public class ArrayList implements List { + + private final int step = 10; + private Object elementData[] = new Object[100]; + private int size = 0 ; + + + /** + * @Title: add + * @Description: TODO + * @param o , elements of this ArrayList + * @see com.coding.basic.List#add(java.lang.Object) + */ + public void add(Object o) { + add(size,o); + } + + + /** + * @Title: add + * @Description: TODO + * @param index + * @param o + * @see com.coding.basic.List#add(int, java.lang.Object) + */ + public void add(int index, Object o) { + if(index < 0 || index> size) { + throw new IllegalArgumentException("下标越界"); + } + + if(null == o) { + throw new IllegalArgumentException("元素不能为空"); + } + + if(this.checkOutOfBounds()) { + this.autoGrow(this.step); + } + + int i = size; + while(i>index) { + elementData[i] = elementData[--i]; + } + addDriect(i, o); + } + + + public Object get(int index) { + if(index < 0 || index>= size) { + throw new IllegalArgumentException("下标越界"); + } + + return elementData[index]; + } + + public Object remove(int index) { + if(index < 0 || index>= size) { + throw new IllegalArgumentException("下标越界"); + } + + Object o = elementData[index]; + while (index<size-1) { + elementData[index] = elementData[++index]; + } + elementData[size] = null; + this.size--; + return o; + } + + public int size() { + return this.size; + } + + + /** + * @param growSize + * 扩展elementData数组growSize大小 + */ + private void autoGrow(int growSize) { + if (elementData.length>this.size) { + return; + } + Object newElementData[] = new Object[elementData.length+growSize]; + System.arraycopy(elementData, 0, newElementData, 0, elementData.length); + elementData = newElementData; + return; + } + + private void addDriect(int index, Object o) { + elementData[index] = o; + this.size++; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("["); + for(int i =0;i<this.size;i++) { + sb.append(elementData[i].toString()); + sb.append(","); + } + sb.replace(sb.length()-1, sb.length(), "]"); + return sb.toString(); + } + + private boolean checkOutOfBounds() { + if (elementData.length>this.size) { + return false; + }else { + return true; + } + } + +} diff --git a/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coding/basic/LinkedList.java b/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coding/basic/LinkedList.java index a824ad9372..cad618d536 100644 --- a/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coding/basic/LinkedList.java +++ b/group04/821655640/learning_projects/project_basic_001/src/main/java/com/coding/basic/LinkedList.java @@ -1,134 +1,349 @@ -package com.coding.basic; - - -/** - * @ClassName: LinkedList - * @Description: 带头结点的单向列表. - * @author: tangxp - * @date: 2017年2月23日 下午9:14:28 - */ -public class LinkedList implements List { - - private Node head = new Node(); - private int size ; - - public void add(Object o){ - add(size,o); - } - - public void add(int index , Object o){ - if(index<0 || index>size) { - throw new IllegalArgumentException("目前链表长度不够!"); - } - Node tempHead = head; - int i = 0; - while(i++ < index) { - tempHead = tempHead.next; - } - addDriect(getNode(o),tempHead); - } - - - /** - * @Title: get - * @Description: TODO - * @param index - * @return - * @see com.coding.basic.List#get(int) - */ - public Object get(int index){ - if(index<0|| index>=size) { - throw new IllegalArgumentException("下标超出链表范围!"); - } - Node tempHead = head; - int i = 0; - while(i++ < index) { - tempHead = tempHead.next; - } - return tempHead.next.data; - } - - public Object remove(int index){ - if(index<0 || index>=size) { - throw new IllegalArgumentException("下标超出链表范围!"); - } - Node tempHead = head; - int i = 0; - while(i++ < index) { - tempHead = tempHead.next; - } - - Node removingNode = tempHead.next; - tempHead.next = removingNode.next; - removingNode.next = null; - size--; - return removingNode.data; - } - - public int size(){ - return size; - } - - public void addFirst(Object o){ - add(0,o); - } - public void addLast(Object o){ - add(o); - } - public Object removeFirst(){ - return remove(0); - } - - public Object removeLast(){ - return remove(size-1); - } - - public Iterator iterator(){ - return null; - } - - private void addDriect(Node n,Node before) { - Node temp = before.next; - n.next = temp; - before.next = n; - size++; - } - - private Node getNode(Object o) { - - if(null == o) { - throw new IllegalArgumentException("节点值不能为空"); - } - - Node n = new Node(); - n.data = o; - return n; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder("size: "+size+" {null | ---}--->"); - if(null == head.next) { - return sb.toString(); - } - - Node tempHead = head; - while(null != tempHead.next ) { - sb.append(tempHead.next.toString()); - tempHead = tempHead.next; - } - sb.append("null"); - return sb.toString(); - } - - private static class Node{ - Object data; - Node next; - - @Override - public String toString() { - return "{" + this.data +" |---}--->"; - } - - } -} +package com.coding.basic; + +import java.util.concurrent.CyclicBarrier; + + +/** + * @ClassName: LinkedList + * @Description: 带头结点的单向列表. + * @author: tangxp + * @date: 2017年2月23日 下午9:14:28 + */ +public class LinkedList implements List { + + private Node head = new Node(); + private int size ; + + public void add(Object o){ + add(size,o); + } + + public void add(int index , Object o){ + if(index<0 || index>size) { + throw new IllegalArgumentException("目前链表长度不够!"); + } + Node tempHead = head; + int i = 0; + while(i++ < index) { + tempHead = tempHead.next; + } + addDriect(getNode(o),tempHead); + } + + + /** + * @Title: get + * @Description: TODO + * @param index + * @return + * @see com.coding.basic.List#get(int) + */ + public Object get(int index){ + if(index<0|| index>=size) { + throw new IllegalArgumentException("下标超出链表范围!"); + } + Node tempHead = head; + int i = 0; + while(i++ < index) { + tempHead = tempHead.next; + } + return tempHead.next.data; + } + + public Object remove(int index){ + if(index<0 || index>=size) { + throw new IllegalArgumentException("下标超出链表范围!"); + } + Node tempHead = head; + int i = 0; + while(i++ < index) { + tempHead = tempHead.next; + } + + Node removingNode = tempHead.next; + tempHead.next = removingNode.next; + removingNode.next = null; + size--; + return removingNode.data; + } + + public int size(){ + return size; + } + + public void addFirst(Object o){ + add(0,o); + } + public void addLast(Object o){ + add(o); + } + public Object removeFirst(){ + return remove(0); + } + + public Object removeLast(){ + return remove(size-1); + } + + public Iterator iterator(){ + return null; + } + + private void addDriect(Node n,Node before) { + Node temp = before.next; + n.next = temp; + before.next = n; + size++; + } + + private Node getNode(Object o) { + + if(null == o) { + throw new IllegalArgumentException("节点值不能为空"); + } + + Node n = new Node(); + n.data = o; + return n; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("size: "+size+" {null | ---}--->"); + if(null == head.next) { + return sb.toString(); + } + + Node tempHead = head; + while(null != tempHead.next ) { + sb.append(tempHead.next.toString()); + tempHead = tempHead.next; + } + sb.append("null"); + return sb.toString(); + } + + private static class Node{ + Object data; + Node next; + + @Override + public String toString() { + return "{" + this.data +" |---}--->"; + } + } + + + //数据结构习题 + + /** + * 把该链表逆置 + * 例如链表为 3->7->10 , 逆置后变为 10->7->3 + */ + public boolean reverse(){ + if (this.size()<=0) { + return false; + } + Stack stack = new Stack(); + + while(this.size()>0) { + stack.push(this.removeFirst()); + } + + while(stack.size()>0) { + this.addLast(stack.pop()); + } + + return true; + } + + /** + * 删除一个单链表的前半部分 + * 例如:list = 2->5->7->8 , 删除以后的值为 7->8 + * 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10 + + */ + public boolean removeFirstHalf(){ + if (this.size()<=0) { + return false; + } + //计算中间位置 + int tempCount = this.size(); + tempCount = tempCount%2 == 0 ? tempCount/2 : (tempCount-1)/2; + tempCount--; + while(tempCount >= 0) { + this.removeFirst(); + tempCount --; + } + return true; + } + + /** + * 从第i个元素开始, 删除length 个元素 , 注意i从0开始 + * @param i + * @param length + */ + public void remove(int i, int length){ + if(i<0|| i>=size) { + throw new IllegalArgumentException("下标超出链表范围!"); + } + if (!(length>0|| (i+1+length)<=this.size())) { + throw new IllegalArgumentException("参数非法!"); + } + + Node tempHead = head; + head = getNode(i-1); + while(length-->0){ + this.removeFirst(); + } + head = tempHead; + } + + /** + * 获取第i个元素的引用 + */ + public Node getNode(int index) { + if(index<0|| index>=size) { + throw new IllegalArgumentException("下标超出链表范围!"); + } + Node tempHead = head; + int i = 0; + while(i++ < index) { + tempHead = tempHead.next; + } + + return tempHead.next; + } + + + /** + * 假定当前链表和listB均包含已升序排列的整数 + * 从当前链表中取出那些listB所指定的元素 + * 例如当前链表 = 11->101->201->301->401->501->601->701 + * listB = 1->3->4->6 + * 返回的结果应该是[101,301,401,601] + * @param list + */ + public Integer[] getElements(LinkedList list){ + int listSizeB = list.size(); + int i=0; + Integer res[] = new Integer[listSizeB]; + while(listSizeB-- > 0) { + res[i] = (Integer) this.get((Integer)list.get(i)); + i++; + } + return res; + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 从当前链表中中删除在listB中出现的元素 + * @param list + */ + + public void subtract(LinkedList list){ + Node tempNodePre = this.head; + Node tempNode = this.head.next; + Node tempNodeB = list.head.next; + Node temp = null; + while(null != tempNode && null != tempNodeB) { + Integer a = (Integer) tempNode.data; + Integer b = (Integer) tempNodeB.data; + if (a < b) { + tempNodePre = tempNodePre.next; + tempNode = tempNode.next; + } else if(a > b){ + tempNodeB = tempNodeB.next; + }else { + temp = tempNode; + tempNodePre.next = tempNode.next; + tempNode = tempNode.next; + temp.next = null; + temp = null; + } + } + } + + /** + * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) + */ + public void removeDuplicateValues(){ + Node tempPre = this.head; + Node tempCur = this.head.next; + Node temp = null; + while(null != tempCur) { + Integer a = (Integer) tempPre.data; + Integer b = (Integer) tempCur.data; + if(a == b) { + temp = tempCur; + tempPre.next = tempCur.next; + tempCur = tempCur.next; + temp.next = null; + temp = null; + }else { + tempPre = tempPre.next; + tempCur = tempCur.next; + } + } + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 试写一高效的算法,删除表中所有值大于min且小于max的元素(若表中存在这样的元素) + * @param min + * @param max + */ + public void removeRange(int min, int max){ + if (min<0 || max<min || this.size()<2) { + throw new IllegalArgumentException(); + } + + Node pre = this.head.next; + Node cur = this.head.next.next; + Node preMin = null; + Node preMax = null; + while(null != cur) { + + Integer a = (Integer) pre.data; + Integer b = (Integer) cur.data; + + if (a<min && b>=min) { + preMin = pre; + } + if (a<=max && b>max) { + preMax = pre; + } + pre = pre.next; + cur = cur.next; + } + preMin.next = preMax.next; + preMax = null; + } + + /** + * 假设当前链表和参数list指定的链表均以元素依值递增有序排列(同一表中的元素值各不相同) + * 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列 + * @param list + */ + public LinkedList intersection( LinkedList listB){ + Node nodeA = this.head.next; + Node nodeB = listB.head.next; + LinkedList listC = new LinkedList(); + while (null != nodeA && null != nodeB) { + Integer a = (Integer) nodeA.data; + Integer b = (Integer) nodeB.data; + if (a>b) { + nodeB = nodeB.next; + } else if(a<b){ + nodeA = nodeA.next; + }else { + listC.add(nodeA.data); + nodeA = nodeA.next; + nodeB = nodeB.next; + } + } + return listC; + } + +} diff --git a/group04/821655640/learning_projects/project_basic_001/src/test/java/com/coding/basic/TestLinkedList.java b/group04/821655640/learning_projects/project_basic_001/src/test/java/com/coding/basic/TestLinkedList.java new file mode 100644 index 0000000000..ce4446b6b6 --- /dev/null +++ b/group04/821655640/learning_projects/project_basic_001/src/test/java/com/coding/basic/TestLinkedList.java @@ -0,0 +1,110 @@ +package com.coding.basic; + + +import java.util.Arrays; + +import org.junit.Test; + +public class TestLinkedList { + + @Test + public void testReverse() { + LinkedList link = new LinkedList(); + for(int i=0;i<10;i++) { + link.add(i); + } + System.out.println(link); + link.reverse(); + System.out.println(link); + } + + @Test + public void testRemoveFirstHalf() { + LinkedList link = new LinkedList(); + for(int i=0;i<9;i++) { + link.add(i); + } + System.out.println(link); + link.removeFirstHalf(); + System.out.println(link); + } + + @Test + public void testRemove() { + LinkedList link = new LinkedList(); + for(int i=0;i<9;i++) { + link.add(i); + } + System.out.println(link); + link.remove(2,3); + System.out.println(link); + } + + @Test + public void testGetElements() { + LinkedList link = new LinkedList(); + for(int i=0;i<9;i++) { + link.add(i+ new java.util.Random().nextInt(10)); + } + LinkedList linkB = new LinkedList(); + linkB.add(2); + linkB.add(4); + linkB.add(6); + System.out.println(link); + Integer printArray[] = link.getElements(linkB); + System.out.println(Arrays.toString(printArray)); + } + + @Test + public void testSubtract() { + LinkedList link = new LinkedList(); + for(int i=0;i<9;i++) { + link.add(i); + } + LinkedList linkB = new LinkedList(); + linkB.add(2); + linkB.add(4); + linkB.add(6); + System.out.println(link); + link.subtract(linkB); + System.out.println(link); + } + + @Test + public void testRemoveDuplicateValues() { + LinkedList link = new LinkedList(); + for(int i=0;i<9;i++) { + link.add(i); + link.add(i); + } + System.out.println(link); + link.removeDuplicateValues(); + System.out.println(link); + } + @Test + public void testRemoveRange() { + LinkedList link = new LinkedList(); + for(int i=0;i<9;i++) { + link.add(i); + } + System.out.println(link); + link.removeRange(2, 5); + System.out.println(link); + } + @Test + public void testIntersection() { + LinkedList link = new LinkedList(); + for(int i=3;i<9;i++) { + link.add(i); + } + LinkedList linkB = new LinkedList(); + for(int i=0;i<7;i++) { + linkB.add(i); + } + + System.out.println(link); + System.out.println(linkB); + System.out.println(link.intersection(linkB)); + } + +} diff --git a/group04/821655640/learning_projects/project_basic_001/src/test/java/com/txp/temp/Test.java b/group04/821655640/learning_projects/project_basic_001/src/test/java/com/txp/temp/Test.java new file mode 100644 index 0000000000..1f41927e18 --- /dev/null +++ b/group04/821655640/learning_projects/project_basic_001/src/test/java/com/txp/temp/Test.java @@ -0,0 +1,9 @@ +package com.txp.temp; + +public class Test { + private int m; + + public int inc() { + return m + 1; + } +} \ No newline at end of file From 743e20deb9c6aa2617fb2271bdeb5f22ed144893 Mon Sep 17 00:00:00 2001 From: wzy <1264835468@qq.com> Date: Tue, 28 Mar 2017 13:13:54 +0800 Subject: [PATCH 059/287] addignore --- group17/1264835468/.gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/group17/1264835468/.gitignore b/group17/1264835468/.gitignore index 71f96b185c..cba8f5eb06 100644 --- a/group17/1264835468/.gitignore +++ b/group17/1264835468/.gitignore @@ -2,4 +2,6 @@ .classpath .project -.gitignore \ No newline at end of file +.gitignore +/idea/ +.iml \ No newline at end of file From 3ff26bcf3b36b900a5d9b9e7fc597ba2a5851afd Mon Sep 17 00:00:00 2001 From: wzy <1264835468@qq.com> Date: Tue, 28 Mar 2017 13:14:39 +0800 Subject: [PATCH 060/287] addignore2 --- group17/1264835468/.gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/group17/1264835468/.gitignore b/group17/1264835468/.gitignore index cba8f5eb06..37a597f996 100644 --- a/group17/1264835468/.gitignore +++ b/group17/1264835468/.gitignore @@ -1,7 +1,7 @@ -/bin/ +/bin/ .classpath .project .gitignore -/idea/ +/.idea/ .iml \ No newline at end of file From 91ab9be54390c0505da0f1b2b60971978a50d471 Mon Sep 17 00:00:00 2001 From: zj <2258659044@qq.com> Date: Tue, 28 Mar 2017 14:21:18 +0800 Subject: [PATCH 061/287] =?UTF-8?q?LRU=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coding/basic/linklist/LRUPageFrame.java | 117 ++++++++++++++++-- 1 file changed, 110 insertions(+), 7 deletions(-) diff --git a/group12/2258659044/zj-2017/src/com/coding/basic/linklist/LRUPageFrame.java b/group12/2258659044/zj-2017/src/com/coding/basic/linklist/LRUPageFrame.java index f727e48fd2..4d1c587fd3 100644 --- a/group12/2258659044/zj-2017/src/com/coding/basic/linklist/LRUPageFrame.java +++ b/group12/2258659044/zj-2017/src/com/coding/basic/linklist/LRUPageFrame.java @@ -1,8 +1,9 @@ package com.coding.basic.linklist; + /** * 用双向链表实现LRU算法 - * @author liuxin + * @author ZJ * */ public class LRUPageFrame { @@ -11,15 +12,15 @@ private static class Node { Node prev; Node next; - int pageNum; + Object obj; Node() { } } - private int capacity; - + private int capacity;//容量 + private int size;//已经存放的数量 private Node first;// 链表头 private Node last;// 链表尾 @@ -36,18 +37,120 @@ public LRUPageFrame(int capacity) { * @param key * @return */ - public void access(int pageNum) { + public void access(Object obj) { + if(obj == null){ + return; + } + Node node = getNode(obj); + if(node!=null){ + move2head(node); + }else{ + refresh(obj); + } + } + + /** + * 刷新LRU队列 + * @param obj + */ + private void refresh(Object obj) { + //添加元素 + if(size<capacity){ + add(obj); + }else{ + remove(); + add(obj); + } + } + /** + * 添加 + * @param obj + */ + private void add(Object obj){ + + Node node = new Node(); + node.obj = obj; + if(first == null){ + first = node; + last = node; + }else{ + node.next = first; + node.next.prev = node; + first = node; + } + size++; + } + + /** + * 删除 + * @return + */ + private Object remove(){ + + Object obj = last.obj; + last = last.prev; + last.next = null; + size --; + return obj; } + /** + * 是否存在缓存中 + * @param obj + * @return + */ + @SuppressWarnings("unused") + private boolean isExist(Object obj){ + + return getNode(obj)!=null?true:false; + } + + /** + * 获取包含值为obj的节点 + * @param obj + * @return + */ + private Node getNode(Object obj){ + + for (Node node = first; node != null; node = node.next) { + if(node.obj.equals(obj)){ + return node; + } + } + return null; + } + + /** + * 将节点置为头结点 + * @param obj + */ + private void move2head(Node node){ + + if(node != null){ + if(node.equals(first)){//该节点为头结点 + return; + }else if(node.equals(last)){//该节点为尾节点 + last = last.prev; + last.next = null; + }else{ + node.prev.next = node.next; + node.next.prev = node.prev; + } + //将本节点置为头结点 + first.prev = node; + node.next = first; + first = node; + } + + } - public String toString(){ StringBuilder buffer = new StringBuilder(); Node node = first; while(node != null){ - buffer.append(node.pageNum); + buffer.append(node.obj); node = node.next; if(node != null){ From a37a03f32d79b11b7a5018f9a74ad70796dc7aa7 Mon Sep 17 00:00:00 2001 From: zj <2258659044@qq.com> Date: Tue, 28 Mar 2017 16:19:36 +0800 Subject: [PATCH 062/287] =?UTF-8?q?=E7=B1=BB=E5=8A=A0=E8=BD=BD=E5=99=A8?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jvm/loader/ClassFileLoader.java | 27 +++---- .../jvm/loader/ClassFileLoaderUtil.java | 71 +++++++++++++++++++ .../jvm/loader/ClassFileloaderTest.java | 9 ++- 3 files changed, 89 insertions(+), 18 deletions(-) create mode 100644 group12/2258659044/zj-2017/src/com/coderising/jvm/loader/ClassFileLoaderUtil.java diff --git a/group12/2258659044/zj-2017/src/com/coderising/jvm/loader/ClassFileLoader.java b/group12/2258659044/zj-2017/src/com/coderising/jvm/loader/ClassFileLoader.java index c1b702238d..59d12540fc 100644 --- a/group12/2258659044/zj-2017/src/com/coderising/jvm/loader/ClassFileLoader.java +++ b/group12/2258659044/zj-2017/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -1,5 +1,6 @@ package com.coderising.jvm.loader; +import java.io.File; import java.util.ArrayList; import java.util.List; @@ -9,24 +10,24 @@ public class ClassFileLoader { public byte[] readBinaryCode(String className) { - return null; - - + File clzFile = ClassFileLoaderUtil.getClzFile(clzPaths,className); + + return ClassFileLoaderUtil.readClz(clzFile); + } - - + public void addClassPath(String path) { + this.clzPaths.add(path); } - - - + public String getClassPath(){ - return null; + + StringBuffer buff = new StringBuffer(); + for (String str : clzPaths) { + buff.append(str+";"); + } + return buff.substring(0, buff.length()-1); } - - - - } diff --git a/group12/2258659044/zj-2017/src/com/coderising/jvm/loader/ClassFileLoaderUtil.java b/group12/2258659044/zj-2017/src/com/coderising/jvm/loader/ClassFileLoaderUtil.java new file mode 100644 index 0000000000..61faafb77d --- /dev/null +++ b/group12/2258659044/zj-2017/src/com/coderising/jvm/loader/ClassFileLoaderUtil.java @@ -0,0 +1,71 @@ +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.List; + +public class ClassFileLoaderUtil { + + /** + * 根据类完整包名与classPath获取类class文件 + * @return + */ + public static File getClzFile(List<String> clzPaths ,String className){ + + File clazFile = null; + //将com.zj.className 转化为 com\\zj\\className.class; + if(className!=null){ + className = className.replace(".", "\\")+".class"; + } + //寻找文件所在目录 + for (String clzPath : clzPaths) { + clazFile = new File(clzPath+"\\"+className); + if(clazFile.exists()){ + break; + } + } + return clazFile; + } + + /** + * 读取文件并返回该文件的字节数组 + * @param clzFile + * @return + */ + public static byte[] readClz(File file){ + + byte[] data = null; + InputStream is = null; + ByteArrayOutputStream baos = null; + try { + is = new FileInputStream(file); + if(is !=null){ + baos = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int length = -1; + while ((length = is.read(buffer)) != -1) { + baos.write(buffer, 0, length); + } + baos.flush(); + data = baos.toByteArray(); + } + } catch (Exception e) { + e.printStackTrace(); + }finally{ + try { + if(baos!=null){ + baos.close(); + } + if(is!=null){ + is.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + return data; + } +} diff --git a/group12/2258659044/zj-2017/src/test/com/coderising/jvm/loader/ClassFileloaderTest.java b/group12/2258659044/zj-2017/src/test/com/coderising/jvm/loader/ClassFileloaderTest.java index 4845e8de5b..b274338091 100644 --- a/group12/2258659044/zj-2017/src/test/com/coderising/jvm/loader/ClassFileloaderTest.java +++ b/group12/2258659044/zj-2017/src/test/com/coderising/jvm/loader/ClassFileloaderTest.java @@ -8,9 +8,8 @@ import com.coderising.jvm.loader.ClassFileLoader; public class ClassFileloaderTest { - - static String path1 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\mini-jvm\\bin"; + static String path1 = "F:\\githubRes\\coding2017\\group12\\2258659044\\zj-2017\\bin"; static String path2 = "C:\temp"; @@ -42,12 +41,12 @@ public void testClassFileLength() { ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); - String className = "com.coderising.jvm.test.EmployeeV1"; + String className = "test.com.coderising.jvm.loader.EmployeeV1"; byte[] byteCodes = loader.readBinaryCode(className); // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 - Assert.assertEquals(1056, byteCodes.length); + Assert.assertEquals(1070, byteCodes.length); } @@ -56,7 +55,7 @@ public void testClassFileLength() { public void testMagicNumber(){ ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); - String className = "com.coderising.jvm.test.EmployeeV1"; + String className = "test.com.coderising.jvm.loader.EmployeeV1"; byte[] byteCodes = loader.readBinaryCode(className); byte[] codes = new byte[]{byteCodes[0],byteCodes[1],byteCodes[2],byteCodes[3]}; From b062dfb23198115ab9fd2b50767ece33b11a8e4b Mon Sep 17 00:00:00 2001 From: '1299310140' <'13437282785@163.com'> Date: Tue, 28 Mar 2017 17:46:26 +0800 Subject: [PATCH 063/287] LRU --- .../coding/basic/linklist/LRUPageFrame.java | 136 ++++++++++++++++++ .../basic/linklist/LRUPageFrameTest.java | 73 ++++++++++ 2 files changed, 209 insertions(+) create mode 100644 group04/1299310140/src/com/coding/basic/linklist/LRUPageFrame.java create mode 100644 group04/1299310140/src/com/coding/basic/linklist/LRUPageFrameTest.java diff --git a/group04/1299310140/src/com/coding/basic/linklist/LRUPageFrame.java b/group04/1299310140/src/com/coding/basic/linklist/LRUPageFrame.java new file mode 100644 index 0000000000..025327e934 --- /dev/null +++ b/group04/1299310140/src/com/coding/basic/linklist/LRUPageFrame.java @@ -0,0 +1,136 @@ +package com.coding.basic.linklist; + +/** + * 用双向链表实现LRU算法 + * @author liuxin + * + */ +public class LRUPageFrame { + + private static class Node { + + Node prev; + Node next; + int pageNum; + + Node(int pageNum) { + this.pageNum = pageNum; + } + + } + + 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) { + removeElement(pageNum); + addFirst(pageNum); + if(this.size > this.capacity){ + removeLast(); + } + } + + //删除链表的尾节点 + private void removeLast(){ + if(this.size == 0){ + return; + } + if(this.size == 1){ + this.first = null; + this.last = null; + this.size--; + } + Node curr = this.last; + this.last = curr.prev; + this.last.next = null; + curr.prev = null; + this.size--; + } + + //根据参数删除双向链表中的某个节点 + private void removeElement(int pageNum){ + if(this.size == 0){ + return; + } + Node curr = this.first; + while(curr.pageNum != pageNum){ + if(curr.next == null){ + break; + } + curr = curr.next; + } + //此时curr指向被删除节点or链表最后一个节点 + if(curr.pageNum == pageNum){ + if(this.first == this.last){//size为1,且该节点需要被删除 + this.first = null; + this.last = null; + this.size--; + return; + } + if(curr == this.first){//删除头节点 + this.first = curr.next; + this.first.prev = null; + curr.next = null; + this.size--; + return; + } + if(curr == this.last){//删除尾节点 + this.last = curr.prev; + this.last.next = null; + curr.prev = null; + this.size--; + return; + } + + //删除中间节点 + //此时size至少为3 + curr.next.prev = curr.prev; + curr.prev.next = curr.next; + curr.prev = null; + curr.next = null; + this.size--; + } + } + + //向双向链表的头部添加节点 + private void addFirst(int pageNum){ + Node curr = new Node(pageNum); + if(this.size == 0){ + this.first = curr; + this.last = curr; + this.size++; + }else{ + curr.next = this.first; + this.first.prev = curr; + this.first = curr; + this.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/group04/1299310140/src/com/coding/basic/linklist/LRUPageFrameTest.java b/group04/1299310140/src/com/coding/basic/linklist/LRUPageFrameTest.java new file mode 100644 index 0000000000..52347f721d --- /dev/null +++ b/group04/1299310140/src/com/coding/basic/linklist/LRUPageFrameTest.java @@ -0,0 +1,73 @@ +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(7); + frame.access(0); + 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()); + + LRUPageFrame frameFive = new LRUPageFrame(5); + frameFive.access(7);//7 + frameFive.access(7);//7 + frameFive.access(0);//0 7 + frameFive.access(7);//7 0 + frameFive.access(0);//0 7 + frameFive.access(1);//1 0 7 + Assert.assertEquals("1,0,7", frameFive.toString()); + frameFive.access(2);//2 1 0 7 + Assert.assertEquals("2,1,0,7", frameFive.toString()); + frameFive.access(0);//0 2 1 7 + Assert.assertEquals("0,2,1,7", frameFive.toString()); + frameFive.access(0);//0 2 1 7 + Assert.assertEquals("0,2,1,7", frameFive.toString()); + frameFive.access(3);//3 0 2 1 7 + Assert.assertEquals("3,0,2,1,7", frameFive.toString()); + frameFive.access(0);//0 3 2 1 7 + Assert.assertEquals("0,3,2,1,7", frameFive.toString()); + frameFive.access(4);//4 0 3 2 1 + Assert.assertEquals("4,0,3,2,1", frameFive.toString()); + } + +// @Test +// public void testAddFirst(){ +// LRUPageFrame frame = new LRUPageFrame(3); +// frame.addFirst(1); +// frame.addFirst(2); +// Assert.assertEquals("2,1", frame.toString()); +// frame.addFirst(3); +// Assert.assertEquals("3,2,1", frame.toString()); +// frame.addFirst(4); +// Assert.assertEquals("4,3,2,1", frame.toString()); +// frame.removeElement(3); +// Assert.assertEquals("4,2,1", frame.toString()); +// frame.removeElement(1); +// Assert.assertEquals("4,2", frame.toString()); +// frame.removeElement(4); +// Assert.assertEquals("2", frame.toString()); +// frame.removeElement(2); +// Assert.assertEquals("", frame.toString()); +// } + +} From 5b2acd4a50215357bae1a9e5111f004bc7b474fd Mon Sep 17 00:00:00 2001 From: ZhaoHongxin <zhaohongxin621@126.com> Date: Tue, 28 Mar 2017 21:42:53 +0800 Subject: [PATCH 064/287] down load work --- .../src/com/coding/basic/QueueTest.java | 50 +++++++++---------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/group05/1094051862/test01/src/com/coding/basic/QueueTest.java b/group05/1094051862/test01/src/com/coding/basic/QueueTest.java index f75beb397f..1feee8dde1 100644 --- a/group05/1094051862/test01/src/com/coding/basic/QueueTest.java +++ b/group05/1094051862/test01/src/com/coding/basic/QueueTest.java @@ -1,26 +1,24 @@ -package com.coding.basic; - -import static org.junit.Assert.*; -import junit.framework.Assert; - -import org.junit.Test; - -import sun.org.mozilla.javascript.internal.ast.NewExpression; - -public class QueueTest { - - @Test - public void test() { - Queue queue = new Queue(); - for (int i = 0; i < 100; i++) { - queue.enQueue(i); - } - Assert.assertEquals(100, queue.size()); - for (int i = 0; i < 100; i++) { - Assert.assertEquals(i, queue.deQueue()); - } - Assert.assertEquals(0, queue.size()); - - } - -} +package com.coding.basic; + +import static org.junit.Assert.*; +import junit.framework.Assert; + +import org.junit.Test; + +public class QueueTest { + + @Test + public void test() { + Queue queue = new Queue(); + for (int i = 0; i < 100; i++) { + queue.enQueue(i); + } + Assert.assertEquals(100, queue.size()); + for (int i = 0; i < 100; i++) { + Assert.assertEquals(i, queue.deQueue()); + } + Assert.assertEquals(0, queue.size()); + + } + +} From 9934fe65211d5a0b6e1b15868a43c38d76f672a3 Mon Sep 17 00:00:00 2001 From: ZhaoHongxin <zhaohongxin621@126.com> Date: Tue, 28 Mar 2017 21:47:06 +0800 Subject: [PATCH 065/287] upload work --- .../src/com/coding/lru/LRUPageFrame.java | 60 +++++++++++++++++++ .../src/com/coding/lru/LRUPageFrameTest.java | 31 ++++++++++ 2 files changed, 91 insertions(+) create mode 100644 group05/1094051862/test01/src/com/coding/lru/LRUPageFrame.java create mode 100644 group05/1094051862/test01/src/com/coding/lru/LRUPageFrameTest.java diff --git a/group05/1094051862/test01/src/com/coding/lru/LRUPageFrame.java b/group05/1094051862/test01/src/com/coding/lru/LRUPageFrame.java new file mode 100644 index 0000000000..19b17e49e5 --- /dev/null +++ b/group05/1094051862/test01/src/com/coding/lru/LRUPageFrame.java @@ -0,0 +1,60 @@ +package com.coding.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/group05/1094051862/test01/src/com/coding/lru/LRUPageFrameTest.java b/group05/1094051862/test01/src/com/coding/lru/LRUPageFrameTest.java new file mode 100644 index 0000000000..75220cc9c1 --- /dev/null +++ b/group05/1094051862/test01/src/com/coding/lru/LRUPageFrameTest.java @@ -0,0 +1,31 @@ +package com.coding.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()); + } + +} From cbf081803aa00453826dbd8b3580fff795470d77 Mon Sep 17 00:00:00 2001 From: ZhaoHongxin <zhaohongxin621@126.com> Date: Tue, 28 Mar 2017 22:33:17 +0800 Subject: [PATCH 066/287] upload work --- group05/1094051862/mini-jvm/.classpath | 8 ++ group05/1094051862/mini-jvm/.gitignore | 1 + group05/1094051862/mini-jvm/.project | 17 ++++ .../jvm/loader/ClassFileLoader.java | 34 +++++++ .../jvm/test/ClassFileloaderTest.java | 92 +++++++++++++++++++ .../com/coderising/jvm/test/EmployeeV1.java | 28 ++++++ 6 files changed, 180 insertions(+) create mode 100644 group05/1094051862/mini-jvm/.classpath create mode 100644 group05/1094051862/mini-jvm/.gitignore create mode 100644 group05/1094051862/mini-jvm/.project create mode 100644 group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java create mode 100644 group05/1094051862/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java create mode 100644 group05/1094051862/mini-jvm/src/com/coderising/jvm/test/EmployeeV1.java diff --git a/group05/1094051862/mini-jvm/.classpath b/group05/1094051862/mini-jvm/.classpath new file mode 100644 index 0000000000..9b2ed0d520 --- /dev/null +++ b/group05/1094051862/mini-jvm/.classpath @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> + <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/> + <classpathentry kind="lib" path="lib/dom4j-1.6.1.jar"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/group05/1094051862/mini-jvm/.gitignore b/group05/1094051862/mini-jvm/.gitignore new file mode 100644 index 0000000000..ae3c172604 --- /dev/null +++ b/group05/1094051862/mini-jvm/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/group05/1094051862/mini-jvm/.project b/group05/1094051862/mini-jvm/.project new file mode 100644 index 0000000000..ec3aa61015 --- /dev/null +++ b/group05/1094051862/mini-jvm/.project @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>mini-jvm</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> 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 new file mode 100644 index 0000000000..86d4619407 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,34 @@ +package com.coderising.jvm.loader; + +import java.util.ArrayList; +import java.util.List; + + + +public class ClassFileLoader { + + private List<String> clzPaths = new ArrayList<String>(); + + public byte[] readBinaryCode(String className) { + + return null; + + + } + + + public void addClassPath(String path) { + + } + + + + public String getClassPath(){ + 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 new file mode 100644 index 0000000000..a05534b210 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,92 @@ +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(); + } + +} diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/test/EmployeeV1.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..9a36573dd3 --- /dev/null +++ b/group05/1094051862/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 From 7cd1d0ba08cd2ca0e8755efdfaf57ae38529352b Mon Sep 17 00:00:00 2001 From: ZhaoHongxin <zhaohongxin621@126.com> Date: Tue, 28 Mar 2017 22:35:54 +0800 Subject: [PATCH 067/287] upload work --- group05/1094051862/test01/.classpath | 16 +- group05/1094051862/test01/.gitignore | 2 +- group05/1094051862/test01/.project | 34 ++-- .../.settings/org.eclipse.jdt.core.prefs | 24 +-- .../src/com/coding/basic/ArrayList.java | 158 +++++++++--------- .../src/com/coding/basic/BinaryTreeNode.java | 64 +++---- .../test01/src/com/coding/basic/Iterator.java | 14 +- .../test01/src/com/coding/basic/Queue.java | 50 +++--- .../test01/src/com/coding/basic/Stack.java | 56 +++---- .../src/com/coding/basic/StackTest.java | 52 +++--- 10 files changed, 235 insertions(+), 235 deletions(-) diff --git a/group05/1094051862/test01/.classpath b/group05/1094051862/test01/.classpath index 9794cd8084..6f95a0c3bd 100644 --- a/group05/1094051862/test01/.classpath +++ b/group05/1094051862/test01/.classpath @@ -1,8 +1,8 @@ -<?xml version="1.0" encoding="UTF-8"?> -<classpath> - <classpathentry kind="src" path="src"/> - <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/> - <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> - <classpathentry kind="lib" path="lib/dom4j-1.6.1.jar"/> - <classpathentry kind="output" path="bin"/> -</classpath> +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> + <classpathentry kind="lib" path="lib/dom4j-1.6.1.jar"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/group05/1094051862/test01/.gitignore b/group05/1094051862/test01/.gitignore index ae3c172604..3e2fcc7171 100644 --- a/group05/1094051862/test01/.gitignore +++ b/group05/1094051862/test01/.gitignore @@ -1 +1 @@ -/bin/ +/bin/ diff --git a/group05/1094051862/test01/.project b/group05/1094051862/test01/.project index 1dfd9165c6..6be5013dd0 100644 --- a/group05/1094051862/test01/.project +++ b/group05/1094051862/test01/.project @@ -1,17 +1,17 @@ -<?xml version="1.0" encoding="UTF-8"?> -<projectDescription> - <name>test01</name> - <comment></comment> - <projects> - </projects> - <buildSpec> - <buildCommand> - <name>org.eclipse.jdt.core.javabuilder</name> - <arguments> - </arguments> - </buildCommand> - </buildSpec> - <natures> - <nature>org.eclipse.jdt.core.javanature</nature> - </natures> -</projectDescription> +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>test01</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/group05/1094051862/test01/.settings/org.eclipse.jdt.core.prefs b/group05/1094051862/test01/.settings/org.eclipse.jdt.core.prefs index d17b6724d1..980b98c1d5 100644 --- a/group05/1094051862/test01/.settings/org.eclipse.jdt.core.prefs +++ b/group05/1094051862/test01/.settings/org.eclipse.jdt.core.prefs @@ -1,12 +1,12 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.7 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.7 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/group05/1094051862/test01/src/com/coding/basic/ArrayList.java b/group05/1094051862/test01/src/com/coding/basic/ArrayList.java index 60fe8b9150..2e837dd195 100644 --- a/group05/1094051862/test01/src/com/coding/basic/ArrayList.java +++ b/group05/1094051862/test01/src/com/coding/basic/ArrayList.java @@ -1,79 +1,79 @@ -package com.coding.basic; - -import java.util.Arrays; - -public class ArrayList implements List { - - private int size = 0; - - private Object[] elementData = new Object[10]; - - private int increaseSize = 10; - private void increaseArray() { - Object[] newData = Arrays.copyOf(elementData, elementData.length + increaseSize); - elementData = newData; - } - public void add(Object o){ - if (size == elementData.length) { - increaseArray(); - elementData[size++] = o; - } else { - elementData[size++] = o; - } - } - public void add(int index, Object o){ - if (index < 0 || index > size) { - System.out.println("错误提示:index > size || index < 0"); - return; - } - Object temp; - for (int i = index; i < size; i++) { - temp = elementData[i]; - elementData[i] = o; - o = temp; - } - elementData[size ++] = o; - } - - public Object get(int index){ - if (index < 0 || index > size ){ - return null; - } - return elementData[index]; - } - - public Object remove(int index){ - if (index < 0 || index > size ){ - return null; - } - Object result = elementData[index]; - for (int i = index; i < size-1; i++) { - elementData[i] = elementData[i + 1]; - } - elementData[size-1] = null; - size --; - return result; - } - - public int size(){ - return size; - } - - public Iterator iterator(){ - return new Iterator() { - private int cusor = 0; - @Override - public Object next() { - if (!hasNext()) { - System.out.println("next: !hasNext"); - return null; - } - return elementData[cusor ++]; - } - @Override - public boolean hasNext() { - return cusor < size; - } - }; - } -} +package com.coding.basic; + +import java.util.Arrays; + +public class ArrayList implements List { + + private int size = 0; + + private Object[] elementData = new Object[10]; + + private int increaseSize = 10; + private void increaseArray() { + Object[] newData = Arrays.copyOf(elementData, elementData.length + increaseSize); + elementData = newData; + } + public void add(Object o){ + if (size == elementData.length) { + increaseArray(); + elementData[size++] = o; + } else { + elementData[size++] = o; + } + } + public void add(int index, Object o){ + if (index < 0 || index > size) { + System.out.println("错误提示:index > size || index < 0"); + return; + } + Object temp; + for (int i = index; i < size; i++) { + temp = elementData[i]; + elementData[i] = o; + o = temp; + } + elementData[size ++] = o; + } + + public Object get(int index){ + if (index < 0 || index > size ){ + return null; + } + return elementData[index]; + } + + public Object remove(int index){ + if (index < 0 || index > size ){ + return null; + } + Object result = elementData[index]; + for (int i = index; i < size-1; i++) { + elementData[i] = elementData[i + 1]; + } + elementData[size-1] = null; + size --; + return result; + } + + public int size(){ + return size; + } + + public Iterator iterator(){ + return new Iterator() { + private int cusor = 0; + @Override + public Object next() { + if (!hasNext()) { + System.out.println("next: !hasNext"); + return null; + } + return elementData[cusor ++]; + } + @Override + public boolean hasNext() { + return cusor < size; + } + }; + } +} diff --git a/group05/1094051862/test01/src/com/coding/basic/BinaryTreeNode.java b/group05/1094051862/test01/src/com/coding/basic/BinaryTreeNode.java index d7ac820192..266eff3d56 100644 --- a/group05/1094051862/test01/src/com/coding/basic/BinaryTreeNode.java +++ b/group05/1094051862/test01/src/com/coding/basic/BinaryTreeNode.java @@ -1,32 +1,32 @@ -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; - } - - public BinaryTreeNode insert(Object o){ - return null; - } - -} +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; + } + + public BinaryTreeNode insert(Object o){ + return null; + } + +} diff --git a/group05/1094051862/test01/src/com/coding/basic/Iterator.java b/group05/1094051862/test01/src/com/coding/basic/Iterator.java index 06ef6311b2..dbe8b9afb2 100644 --- a/group05/1094051862/test01/src/com/coding/basic/Iterator.java +++ b/group05/1094051862/test01/src/com/coding/basic/Iterator.java @@ -1,7 +1,7 @@ -package com.coding.basic; - -public interface Iterator { - public boolean hasNext(); - public Object next(); - -} +package com.coding.basic; + +public interface Iterator { + public boolean hasNext(); + public Object next(); + +} diff --git a/group05/1094051862/test01/src/com/coding/basic/Queue.java b/group05/1094051862/test01/src/com/coding/basic/Queue.java index b65d01ab8e..e16a80b13c 100644 --- a/group05/1094051862/test01/src/com/coding/basic/Queue.java +++ b/group05/1094051862/test01/src/com/coding/basic/Queue.java @@ -1,25 +1,25 @@ -package com.coding.basic; - -public class Queue { - private List list = new ArrayList(); - private int size = 0; - public void enQueue(Object o){ - list.add(o); - size ++; - } - - public Object deQueue(){ - if (size == 0) - return null; - size --; - return list.remove(0); - } - - public boolean isEmpty(){ - return size == 0; - } - - public int size(){ - return size; - } -} +package com.coding.basic; + +public class Queue { + private List list = new ArrayList(); + private int size = 0; + public void enQueue(Object o){ + list.add(o); + size ++; + } + + public Object deQueue(){ + if (size == 0) + return null; + size --; + return list.remove(0); + } + + public boolean isEmpty(){ + return size == 0; + } + + public int size(){ + return size; + } +} diff --git a/group05/1094051862/test01/src/com/coding/basic/Stack.java b/group05/1094051862/test01/src/com/coding/basic/Stack.java index 7fabb3494f..57eae3d31d 100644 --- a/group05/1094051862/test01/src/com/coding/basic/Stack.java +++ b/group05/1094051862/test01/src/com/coding/basic/Stack.java @@ -1,28 +1,28 @@ -package com.coding.basic; - -public class Stack { - private List elementData = new ArrayList(); - private int size = 0; - public void push(Object o){ - elementData.add(o); - size ++; - } - - public Object pop(){ - if (size == 0) - return null; - return elementData.remove(--size); - } - - public Object peek(){ - if (size == 0) - return null; - return elementData.get(size - 1); - } - public boolean isEmpty(){ - return size == 0; - } - public int size(){ - return size; - } -} +package com.coding.basic; + +public class Stack { + private List elementData = new ArrayList(); + private int size = 0; + public void push(Object o){ + elementData.add(o); + size ++; + } + + public Object pop(){ + if (size == 0) + return null; + return elementData.remove(--size); + } + + public Object peek(){ + if (size == 0) + return null; + return elementData.get(size - 1); + } + public boolean isEmpty(){ + return size == 0; + } + public int size(){ + return size; + } +} diff --git a/group05/1094051862/test01/src/com/coding/basic/StackTest.java b/group05/1094051862/test01/src/com/coding/basic/StackTest.java index adcb2c6522..e3eabe44a1 100644 --- a/group05/1094051862/test01/src/com/coding/basic/StackTest.java +++ b/group05/1094051862/test01/src/com/coding/basic/StackTest.java @@ -1,26 +1,26 @@ -package com.coding.basic; - -import static org.junit.Assert.*; -import junit.framework.Assert; - -import org.junit.BeforeClass; -import org.junit.Test; - -public class StackTest { - - @Test - public void test() { - Stack stack = new Stack(); - for (int i = 0; i < 100; i++) { - stack.push(i); - } - Assert.assertEquals(100, stack.size()); - Assert.assertEquals(99, stack.pop()); - for (int i = 98; i >= 0; i--) { - Assert.assertEquals(i, stack.peek()); - Assert.assertEquals(i, stack.pop()); - } - Assert.assertEquals(0, stack.size()); - } - -} +package com.coding.basic; + +import static org.junit.Assert.*; +import junit.framework.Assert; + +import org.junit.BeforeClass; +import org.junit.Test; + +public class StackTest { + + @Test + public void test() { + Stack stack = new Stack(); + for (int i = 0; i < 100; i++) { + stack.push(i); + } + Assert.assertEquals(100, stack.size()); + Assert.assertEquals(99, stack.pop()); + for (int i = 98; i >= 0; i--) { + Assert.assertEquals(i, stack.peek()); + Assert.assertEquals(i, stack.pop()); + } + Assert.assertEquals(0, stack.size()); + } + +} From 0d3203dee34065a0854964e5f6cbe259feff866e Mon Sep 17 00:00:00 2001 From: ZhaoHongxin <zhaohongxin621@126.com> Date: Tue, 28 Mar 2017 23:08:22 +0800 Subject: [PATCH 068/287] step1 --- .../jvm/loader/ClassFileLoader.java | 28 +++++++++++++------ .../jvm/test/ClassFileloaderTest.java | 6 ++-- 2 files changed, 24 insertions(+), 10 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 86d4619407..67051536b5 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 @@ -12,23 +12,35 @@ public class ClassFileLoader { public byte[] readBinaryCode(String className) { return null; - - } public void addClassPath(String path) { + if (path == null) { + return; + } + + clzPaths.add(path); + } - - public String getClassPath(){ - return null; + + if (clzPaths.size() == 0) { + return ""; + } + + StringBuffer buffer = new StringBuffer(""); + + for (String str : clzPaths) { + buffer.append(str); + buffer.append(";"); + } + + return buffer.substring(0, buffer.length()-1);//去除最后一个分号 + } - - - } 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 a05534b210..d7135ca960 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 @@ -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:\\practise\\group05\\1094051862\\mini-jvm\\bin"; + static String path2 = "C:\\temp"; @@ -58,6 +58,7 @@ public void testClassFileLength() { @Test public void testMagicNumber(){ + ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); String className = "com.coderising.jvm.test.EmployeeV1"; @@ -68,6 +69,7 @@ public void testMagicNumber(){ String acctualValue = this.byteToHexString(codes); Assert.assertEquals("cafebabe", acctualValue); + } From b062454e544c60f95672dbb233fe0c3f2fc9628d Mon Sep 17 00:00:00 2001 From: maishihang <446031103@qq.com> Date: Tue, 28 Mar 2017 23:21:22 +0800 Subject: [PATCH 069/287] com 3week com 3week --- .../coderising/download/DownloadThread.java | 31 ++++++++- .../coderising/download/FileDownloader.java | 66 +++++++++++++++++-- .../download/impl/ConnectionImpl.java | 53 +++++++++++++-- .../download/impl/ConnectionManagerImpl.java | 2 +- .../download/test/ConnectionTest.java | 53 +++++++++++++++ .../{ => test}/FileDownloaderTest.java | 8 +-- 6 files changed, 196 insertions(+), 17 deletions(-) create mode 100644 group12/446031103/src/com/coderising/download/test/ConnectionTest.java rename group12/446031103/src/com/coderising/download/{ => test}/FileDownloaderTest.java (79%) diff --git a/group12/446031103/src/com/coderising/download/DownloadThread.java b/group12/446031103/src/com/coderising/download/DownloadThread.java index 900a3ad358..4daa1baf3c 100644 --- a/group12/446031103/src/com/coderising/download/DownloadThread.java +++ b/group12/446031103/src/com/coderising/download/DownloadThread.java @@ -1,5 +1,10 @@ package com.coderising.download; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; + import com.coderising.download.api.Connection; public class DownloadThread extends Thread{ @@ -7,14 +12,34 @@ public class DownloadThread extends Thread{ Connection conn; int startPos; int endPos; - - public DownloadThread( 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 { + 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 (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (BrokenBarrierException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } } diff --git a/group12/446031103/src/com/coderising/download/FileDownloader.java b/group12/446031103/src/com/coderising/download/FileDownloader.java index c3c8a3f27d..5cbb88410a 100644 --- a/group12/446031103/src/com/coderising/download/FileDownloader.java +++ b/group12/446031103/src/com/coderising/download/FileDownloader.java @@ -1,7 +1,11 @@ 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; @@ -14,9 +18,12 @@ public class FileDownloader { ConnectionManager cm; + private String localFile; + private static final int DOWNLOAD_TRHEAD_NUM = 3; - public FileDownloader(String _url) { + public FileDownloader(String _url,String _localFile) { this.url = _url; + this.localFile = _localFile; } @@ -34,16 +41,36 @@ public void execute(){ // 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); - new DownloadThread(conn,0,length-1).start(); + for(int i=0; i< DOWNLOAD_TRHEAD_NUM; i++){ - } catch (ConnectionException e) { + + 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){ @@ -56,6 +83,37 @@ public void execute(){ } + 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 fileName, int length) throws IOException { + RandomAccessFile raf = new RandomAccessFile(fileName, "rw"); + for (int i = 0; i < length; i++) { + raf.write(0); + } + raf.close(); + } + public void setListener(DownloadListener listener) { this.listener = listener; } diff --git a/group12/446031103/src/com/coderising/download/impl/ConnectionImpl.java b/group12/446031103/src/com/coderising/download/impl/ConnectionImpl.java index 36a9d2ce15..ee1fe3490f 100644 --- a/group12/446031103/src/com/coderising/download/impl/ConnectionImpl.java +++ b/group12/446031103/src/com/coderising/download/impl/ConnectionImpl.java @@ -1,20 +1,63 @@ package com.coderising.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.net.URLConnection; +import java.util.Arrays; import com.coderising.download.api.Connection; - -public class ConnectionImpl implements Connection{ + + class ConnectionImpl implements Connection{ + static final int BUFFER_SIZE = 1024; + URL url; + ConnectionImpl(String theUrl) { + try { + url=new URL(theUrl); + } catch (MalformedURLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } @Override public byte[] read(int startPos, int endPos) throws IOException { - - return null; + 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(); + 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 openConnection; + try { + openConnection = url.openConnection(); + return openConnection.getContentLength(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } return 0; } diff --git a/group12/446031103/src/com/coderising/download/impl/ConnectionManagerImpl.java b/group12/446031103/src/com/coderising/download/impl/ConnectionManagerImpl.java index 172371dd55..18836b4a28 100644 --- a/group12/446031103/src/com/coderising/download/impl/ConnectionManagerImpl.java +++ b/group12/446031103/src/com/coderising/download/impl/ConnectionManagerImpl.java @@ -9,7 +9,7 @@ public class ConnectionManagerImpl implements ConnectionManager { @Override public Connection open(String url) throws ConnectionException { - return null; + return new ConnectionImpl(url); } } diff --git a/group12/446031103/src/com/coderising/download/test/ConnectionTest.java b/group12/446031103/src/com/coderising/download/test/ConnectionTest.java new file mode 100644 index 0000000000..cda74451ca --- /dev/null +++ b/group12/446031103/src/com/coderising/download/test/ConnectionTest.java @@ -0,0 +1,53 @@ +package com.coderising.download.test; + + + +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/group12/446031103/src/com/coderising/download/FileDownloaderTest.java b/group12/446031103/src/com/coderising/download/test/FileDownloaderTest.java similarity index 79% rename from group12/446031103/src/com/coderising/download/FileDownloaderTest.java rename to group12/446031103/src/com/coderising/download/test/FileDownloaderTest.java index 4ff7f46ae0..a3e7d24429 100644 --- a/group12/446031103/src/com/coderising/download/FileDownloaderTest.java +++ b/group12/446031103/src/com/coderising/download/test/FileDownloaderTest.java @@ -1,9 +1,10 @@ -package com.coderising.download; +package com.coderising.download.test; import org.junit.After; import org.junit.Before; import org.junit.Test; +import com.coderising.download.FileDownloader; import com.coderising.download.api.ConnectionManager; import com.coderising.download.api.DownloadListener; import com.coderising.download.impl.ConnectionManagerImpl; @@ -21,9 +22,9 @@ public void tearDown() throws Exception { @Test public void testDownload() { - String url = "http://localhost:8080/test.jpg"; + String url = "http://images2015.cnblogs.com/blog/610238/201604/610238-20160421154632101-286208268.png"; - FileDownloader downloader = new FileDownloader(url); + FileDownloader downloader = new FileDownloader(url,"E:\\TEST\\test.jpg"); ConnectionManager cm = new ConnectionManagerImpl(); @@ -52,7 +53,6 @@ public void notifyFinished() { } System.out.println("下载完成!"); - } 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 070/287] 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<downloadThreadNum;i++){ if(i<downloadThreadNum-1){ new DownloadThread(cm.open(this.url),i*downloadBlock,(i+1)*downloadBlock).start(); diff --git a/group11/542194147/myDataStructure/src/com/coderising/download/impl/ConnectionImpl.java b/group11/542194147/myDataStructure/src/com/coderising/download/impl/ConnectionImpl.java index 180fd8daf8..8dcde87e68 100644 --- a/group11/542194147/myDataStructure/src/com/coderising/download/impl/ConnectionImpl.java +++ b/group11/542194147/myDataStructure/src/com/coderising/download/impl/ConnectionImpl.java @@ -1,32 +1,49 @@ package com.coderising.download.impl; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; +import java.util.Arrays; import com.coderising.download.api.Connection; public class ConnectionImpl implements Connection{ - + private static final Integer BUFFER_SIZE=1024; private static URLConnection nc; private static InputStream inputStream; - ConnectionImpl(URL url){ try { nc=url.openConnection(); - inputStream=nc.getInputStream(); } catch (IOException e) { e.printStackTrace(); } } - + + @SuppressWarnings("resource") @Override public byte[] read(int startPos, int endPos) throws IOException { + inputStream=nc.getInputStream(); inputStream.skip(startPos); - byte[] readByte=new byte[endPos-startPos]; - inputStream.read(readByte); - return readByte; + byte[] readByte=new byte[BUFFER_SIZE]; + int totalLen=endPos-startPos+1; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + while(baos.size()<totalLen){ + int len=inputStream.read(readByte); + if(len<0){ + break; + } + baos.write(readByte,0, len); + } + + if(baos.size() > totalLen){ + byte[] data = baos.toByteArray(); + return Arrays.copyOf(data, totalLen); + } + + return baos.toByteArray(); + } @Override From 59b56aaa415fe21fdce6cf448d15b9d53d699f53 Mon Sep 17 00:00:00 2001 From: sulei <sulei0205@foxmail.com> Date: Wed, 29 Mar 2017 10:31:28 +0800 Subject: [PATCH 071/287] thirdHomeWork --- .../src/com/coderising/array/ArrayUtil.java | 96 +++++ .../coderising/download/DownloadThread.java | 42 ++ .../coderising/download/FileDownloader.java | 139 +++++++ .../download/FileDownloaderTest.java | 90 +++++ .../coderising/download/api/Connection.java | 23 ++ .../download/api/ConnectionException.java | 13 + .../download/api/ConnectionManager.java | 10 + .../download/api/DownloadListener.java | 6 + .../download/impl/ConnectionImpl.java | 89 +++++ .../download/impl/ConnectionManagerImpl.java | 17 + .../coderising/litestruts/LoginAction.java | 39 ++ .../src/com/coderising/litestruts/Struts.java | 37 ++ .../com/coderising/litestruts/StrutsTest.java | 43 ++ .../src/com/coderising/litestruts/View.java | 27 ++ .../src/com/coding/basic/ArrayList.java | 32 ++ .../src/com/coding/basic/BinaryTreeNode.java | 32 ++ .../src/com/coding/basic/Iterator.java | 7 + .../src/com/coding/basic/LinkedList.java | 374 ++++++++++++++++++ .../src/com/coding/basic/List.java | 9 + .../src/com/coding/basic/Queue.java | 19 + .../src/com/coding/basic/Stack.java | 22 ++ 21 files changed, 1166 insertions(+) create mode 100644 group04/1020483199/ThirdHomeWork/src/com/coderising/array/ArrayUtil.java create mode 100644 group04/1020483199/ThirdHomeWork/src/com/coderising/download/DownloadThread.java create mode 100644 group04/1020483199/ThirdHomeWork/src/com/coderising/download/FileDownloader.java create mode 100644 group04/1020483199/ThirdHomeWork/src/com/coderising/download/FileDownloaderTest.java create mode 100644 group04/1020483199/ThirdHomeWork/src/com/coderising/download/api/Connection.java create mode 100644 group04/1020483199/ThirdHomeWork/src/com/coderising/download/api/ConnectionException.java create mode 100644 group04/1020483199/ThirdHomeWork/src/com/coderising/download/api/ConnectionManager.java create mode 100644 group04/1020483199/ThirdHomeWork/src/com/coderising/download/api/DownloadListener.java create mode 100644 group04/1020483199/ThirdHomeWork/src/com/coderising/download/impl/ConnectionImpl.java create mode 100644 group04/1020483199/ThirdHomeWork/src/com/coderising/download/impl/ConnectionManagerImpl.java create mode 100644 group04/1020483199/ThirdHomeWork/src/com/coderising/litestruts/LoginAction.java create mode 100644 group04/1020483199/ThirdHomeWork/src/com/coderising/litestruts/Struts.java create mode 100644 group04/1020483199/ThirdHomeWork/src/com/coderising/litestruts/StrutsTest.java create mode 100644 group04/1020483199/ThirdHomeWork/src/com/coderising/litestruts/View.java create mode 100644 group04/1020483199/ThirdHomeWork/src/com/coding/basic/ArrayList.java create mode 100644 group04/1020483199/ThirdHomeWork/src/com/coding/basic/BinaryTreeNode.java create mode 100644 group04/1020483199/ThirdHomeWork/src/com/coding/basic/Iterator.java create mode 100644 group04/1020483199/ThirdHomeWork/src/com/coding/basic/LinkedList.java create mode 100644 group04/1020483199/ThirdHomeWork/src/com/coding/basic/List.java create mode 100644 group04/1020483199/ThirdHomeWork/src/com/coding/basic/Queue.java create mode 100644 group04/1020483199/ThirdHomeWork/src/com/coding/basic/Stack.java diff --git a/group04/1020483199/ThirdHomeWork/src/com/coderising/array/ArrayUtil.java b/group04/1020483199/ThirdHomeWork/src/com/coderising/array/ArrayUtil.java new file mode 100644 index 0000000000..e5ddb476a6 --- /dev/null +++ b/group04/1020483199/ThirdHomeWork/src/com/coderising/array/ArrayUtil.java @@ -0,0 +1,96 @@ +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 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){ + return null; + } + + /** + * 给定两个已经排序好的整形数组, 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){ + return null; + } + /** + * 把一个已经存满数据的数组 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){ + return null; + } + + /** + * 斐波那契数列为: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){ + return null; + } + + /** + * 返回小于给定最大值max的所有素数数组 + * 例如max = 23, 返回的数组为[2,3,5,7,11,13,17,19] + * @param max + * @return + */ + public int[] getPrimes(int max){ + return null; + } + + /** + * 所谓“完数”, 是指这个数恰好等于它的因子之和,例如6=1+2+3 + * 给定一个最大值max, 返回一个数组, 数组中是小于max 的所有完数 + * @param max + * @return + */ + public int[] getPerfectNumbers(int max){ + return null; + } + + /** + * 用seperator 把数组 array给连接起来 + * 例如array= [3,8,9], seperator = "-" + * 则返回值为"3-8-9" + * @param array + * @param s + * @return + */ + public String join(int[] array, String seperator){ + return null; + } + + +} diff --git a/group04/1020483199/ThirdHomeWork/src/com/coderising/download/DownloadThread.java b/group04/1020483199/ThirdHomeWork/src/com/coderising/download/DownloadThread.java new file mode 100644 index 0000000000..d16eca2319 --- /dev/null +++ b/group04/1020483199/ThirdHomeWork/src/com/coderising/download/DownloadThread.java @@ -0,0 +1,42 @@ +package com.coderising.download; + + + +import java.io.RandomAccessFile; +import java.util.concurrent.CyclicBarrier; + +import com.coderising.download.api.Connection; + +public class DownloadThread extends Thread{ + + + private Connection conn; + private int startPos; + private int endPos; + private String filePath; + private CyclicBarrier barrier; + + public DownloadThread(Connection conn, int startPos, int endPos,String filePath,CyclicBarrier barrier){ + this.conn = conn; + this.startPos = startPos; + this.endPos = endPos; + this.filePath = filePath; + this.barrier = barrier; + } + public void run(){ + try { + System.out.println("线程" + this.getName() + "开始下载. startPos:" + startPos + "; endPos:" + endPos); + byte[] buffer = conn.read(startPos, endPos); + RandomAccessFile ra = new RandomAccessFile(filePath, "rw"); + ra.seek(startPos); + ra.write(buffer); + //关闭流 + ra.close(); + conn.close(); + barrier.await(); + System.out.println("线程" + this.getName() + "下载完成."); + }catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/group04/1020483199/ThirdHomeWork/src/com/coderising/download/FileDownloader.java b/group04/1020483199/ThirdHomeWork/src/com/coderising/download/FileDownloader.java new file mode 100644 index 0000000000..c6cdf3fc4a --- /dev/null +++ b/group04/1020483199/ThirdHomeWork/src/com/coderising/download/FileDownloader.java @@ -0,0 +1,139 @@ +package com.coderising.download; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CyclicBarrier; + +import org.junit.internal.runners.statements.RunAfters; + +import com.coderising.download.api.Connection; +import com.coderising.download.api.ConnectionException; +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 final static int thread_count = 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(thread_count, new Runnable() { + + @Override + public void run() { + listener.notifyFinished(); + } + }); + Connection conn = null; + try { + + conn = cm.open(this.url); + + int length = conn.getContentLength(); + + createPlaceHolderFile(this.localFile,length); + + int[] [] ranges = allowcateDownloadRange(thread_count,length); + + for(int i = 0; i < thread_count; i++){ + + DownloadThread thread= new DownloadThread(conn, ranges[i][0], ranges[i][1], localFile, barrier); + + thread.start(); + + } + + } catch (Exception e) { + e.printStackTrace(); + + }finally{ + if(conn != null){ + conn.close(); + } + } + + + + + } + + private int[][] allowcateDownloadRange(int threadCount, int length) { + int[][] ranges = new int[thread_count][2]; + + int eachThreadSize = length / threadCount; + + int left = length % threadCount; + + for(int i = 0 ; i < thread_count;i++){ + int startPos = i * eachThreadSize; + + int endPos = (i+1) * eachThreadSize - 1; + + if((i==thread_count -1)){ + endPos += left; + } + + ranges[i][0] = startPos; + ranges[i][1] = endPos; + } + + return ranges; + } + + private void createPlaceHolderFile(String localfile, int length) throws IOException { + RandomAccessFile file = new RandomAccessFile(localfile, "rw"); + for(int i = 0;i < length ; i++){ + file.write(0); + } + file.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/group04/1020483199/ThirdHomeWork/src/com/coderising/download/FileDownloaderTest.java b/group04/1020483199/ThirdHomeWork/src/com/coderising/download/FileDownloaderTest.java new file mode 100644 index 0000000000..7393f57040 --- /dev/null +++ b/group04/1020483199/ThirdHomeWork/src/com/coderising/download/FileDownloaderTest.java @@ -0,0 +1,90 @@ +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.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 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); + + + // 测试不充分,没有断言内容是否正确 + } + + @Test + public void testDownload() { + + String url = "http://www.hinews.cn/pic/0/13/91/26/13912621_821796.jpg"; + + FileDownloader downloader = new FileDownloader(url, "F:/picture/a.png"); + + + 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/group04/1020483199/ThirdHomeWork/src/com/coderising/download/api/Connection.java b/group04/1020483199/ThirdHomeWork/src/com/coderising/download/api/Connection.java new file mode 100644 index 0000000000..0957eaf7f4 --- /dev/null +++ b/group04/1020483199/ThirdHomeWork/src/com/coderising/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/group04/1020483199/ThirdHomeWork/src/com/coderising/download/api/ConnectionException.java b/group04/1020483199/ThirdHomeWork/src/com/coderising/download/api/ConnectionException.java new file mode 100644 index 0000000000..105f00f03a --- /dev/null +++ b/group04/1020483199/ThirdHomeWork/src/com/coderising/download/api/ConnectionException.java @@ -0,0 +1,13 @@ +package com.coderising.download.api; + +public class ConnectionException extends Exception { + + /** + * 自定义异常错误 + * @param string + */ + public ConnectionException(Exception e) { + super(e); + } + +} diff --git a/group04/1020483199/ThirdHomeWork/src/com/coderising/download/api/ConnectionManager.java b/group04/1020483199/ThirdHomeWork/src/com/coderising/download/api/ConnectionManager.java new file mode 100644 index 0000000000..ce045393b1 --- /dev/null +++ b/group04/1020483199/ThirdHomeWork/src/com/coderising/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/group04/1020483199/ThirdHomeWork/src/com/coderising/download/api/DownloadListener.java b/group04/1020483199/ThirdHomeWork/src/com/coderising/download/api/DownloadListener.java new file mode 100644 index 0000000000..7b51663ff9 --- /dev/null +++ b/group04/1020483199/ThirdHomeWork/src/com/coderising/download/api/DownloadListener.java @@ -0,0 +1,6 @@ +package com.coderising.download.api; + +public interface DownloadListener { + + public void notifyFinished(); +} diff --git a/group04/1020483199/ThirdHomeWork/src/com/coderising/download/impl/ConnectionImpl.java b/group04/1020483199/ThirdHomeWork/src/com/coderising/download/impl/ConnectionImpl.java new file mode 100644 index 0000000000..dcaf5883fa --- /dev/null +++ b/group04/1020483199/ThirdHomeWork/src/com/coderising/download/impl/ConnectionImpl.java @@ -0,0 +1,89 @@ +package com.coderising.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.net.URLConnection; +import java.util.Arrays; + +import com.coderising.download.api.Connection; +import com.coderising.download.api.ConnectionException; + +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(); + + //is.skip(startPos); + + 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() { + + + } + +} \ No newline at end of file diff --git a/group04/1020483199/ThirdHomeWork/src/com/coderising/download/impl/ConnectionManagerImpl.java b/group04/1020483199/ThirdHomeWork/src/com/coderising/download/impl/ConnectionManagerImpl.java new file mode 100644 index 0000000000..3af9b21485 --- /dev/null +++ b/group04/1020483199/ThirdHomeWork/src/com/coderising/download/impl/ConnectionManagerImpl.java @@ -0,0 +1,17 @@ +package com.coderising.download.impl; + +import java.net.MalformedURLException; +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); + } + +} diff --git a/group04/1020483199/ThirdHomeWork/src/com/coderising/litestruts/LoginAction.java b/group04/1020483199/ThirdHomeWork/src/com/coderising/litestruts/LoginAction.java new file mode 100644 index 0000000000..dcdbe226ed --- /dev/null +++ b/group04/1020483199/ThirdHomeWork/src/com/coderising/litestruts/LoginAction.java @@ -0,0 +1,39 @@ +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/group04/1020483199/ThirdHomeWork/src/com/coderising/litestruts/Struts.java b/group04/1020483199/ThirdHomeWork/src/com/coderising/litestruts/Struts.java new file mode 100644 index 0000000000..6df190d484 --- /dev/null +++ b/group04/1020483199/ThirdHomeWork/src/com/coderising/litestruts/Struts.java @@ -0,0 +1,37 @@ +package com.coderising.litestruts; + +import java.lang.reflect.Method; +import java.util.Map; + + + +public class Struts { + + + public static View runAction(String actionName, Map<String,String> 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中的 <result> 配置,以及execute的返回值, 确定哪一个jsp, + 放到View对象的jsp字段中。 + + */ + + + return null; + } + +} diff --git a/group04/1020483199/ThirdHomeWork/src/com/coderising/litestruts/StrutsTest.java b/group04/1020483199/ThirdHomeWork/src/com/coderising/litestruts/StrutsTest.java new file mode 100644 index 0000000000..b8c81faf3c --- /dev/null +++ b/group04/1020483199/ThirdHomeWork/src/com/coderising/litestruts/StrutsTest.java @@ -0,0 +1,43 @@ +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<String,String> params = new HashMap<String,String>(); + 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<String,String> params = new HashMap<String,String>(); + 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/group04/1020483199/ThirdHomeWork/src/com/coderising/litestruts/View.java b/group04/1020483199/ThirdHomeWork/src/com/coderising/litestruts/View.java new file mode 100644 index 0000000000..3fe0a702d4 --- /dev/null +++ b/group04/1020483199/ThirdHomeWork/src/com/coderising/litestruts/View.java @@ -0,0 +1,27 @@ +package com.coderising.litestruts; + +import java.util.Map; + +public class View { + private String jsp; + + private Map parameters; + + public String getJsp() { + return jsp; + } + + public void setJsp(String jsp) { + this.jsp = jsp; + } + + public Map getParameters() { + return parameters; + } + + public void setParameters(Map parameters) { + this.parameters = parameters; + } + + +} diff --git a/group04/1020483199/ThirdHomeWork/src/com/coding/basic/ArrayList.java b/group04/1020483199/ThirdHomeWork/src/com/coding/basic/ArrayList.java new file mode 100644 index 0000000000..1f185736f9 --- /dev/null +++ b/group04/1020483199/ThirdHomeWork/src/com/coding/basic/ArrayList.java @@ -0,0 +1,32 @@ +package com.coding.basic; + +public class ArrayList implements List { + + private int size = 0; + + private Object[] elementData = new Object[100]; + + 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 Iterator iterator(){ + return null; + } + +} diff --git a/group04/1020483199/ThirdHomeWork/src/com/coding/basic/BinaryTreeNode.java b/group04/1020483199/ThirdHomeWork/src/com/coding/basic/BinaryTreeNode.java new file mode 100644 index 0000000000..d7ac820192 --- /dev/null +++ b/group04/1020483199/ThirdHomeWork/src/com/coding/basic/BinaryTreeNode.java @@ -0,0 +1,32 @@ +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; + } + + public BinaryTreeNode insert(Object o){ + return null; + } + +} diff --git a/group04/1020483199/ThirdHomeWork/src/com/coding/basic/Iterator.java b/group04/1020483199/ThirdHomeWork/src/com/coding/basic/Iterator.java new file mode 100644 index 0000000000..06ef6311b2 --- /dev/null +++ b/group04/1020483199/ThirdHomeWork/src/com/coding/basic/Iterator.java @@ -0,0 +1,7 @@ +package com.coding.basic; + +public interface Iterator { + public boolean hasNext(); + public Object next(); + +} diff --git a/group04/1020483199/ThirdHomeWork/src/com/coding/basic/LinkedList.java b/group04/1020483199/ThirdHomeWork/src/com/coding/basic/LinkedList.java new file mode 100644 index 0000000000..7b10ffb8b6 --- /dev/null +++ b/group04/1020483199/ThirdHomeWork/src/com/coding/basic/LinkedList.java @@ -0,0 +1,374 @@ +package com.coding.basic; + +import java.util.Stack; + +public class LinkedList implements List { + private int size; + + private Node head; + + public LinkedList(){ + size = 0; + + head = null; + } + + public void add(Object o){ + Node nd = new Node(o); + if(head == null){ + head = nd; + }else{ + Node p = head; + while(p.next != null){ + p = p.next; + } + p.next = nd; + } + size ++; + + } + //3 > 2 > 1 > 5 > 4 > 5改变之前 + //0 1 2 3 4 5index + //3 > 2 > 1 > x > 5 > 4 > 5插入之后 + public void add(int index , Object o){ + if(head != null){ + int k = 0; + Node p = head; + while(k < index - 1 && p.next != null){ + k++; + p = p.next;//当前p为要插入位置的前一个节点 + } + + if(p != null){ + Node nd = new Node(o); + nd.next = p.next; + p.next = nd; + } + + size++; + + } + } + public Object get(int index){ + if(index < 0 || index >= size){ + throw new IndexOutOfBoundsException(); + } + Node p = head; + int k = 0; + while(k < index && p.next !=null){ + k++; + p = p.next; + } + return p.data; + } + //3 > 2 > 1 > 5 > 4 > 5改变之前 + //0 1 2 3 4 5index + //3 > 2 > 1 > 4 > 5插入之后 + public Object remove(int index){ + if(index < 0 || index >= size){ + throw new IndexOutOfBoundsException(); + } + if(head == null){ + return null; + } + if(index == 0){ + head = head.next; + size--; + return head.data; + }else{ + if(head != null){ + int k = 0; + Node p = head; + while(k < index - 1 && p != null){ + k++; + p = p.next; + } + Node pn = p.next; + if(pn != null){ + p.next = pn.next; + size--; + return pn.data; + } + + } + } + return null; + } + + public int size(){ + + return size; + } + + public void addFirst(Object o){ + if(head != null){ + Node nd = new Node(o); + Node first = head; + head = nd; + first = nd.next; + } + } + public void addLast(Object o){ + if(head != null){ + int k = 0; + Node p = head; + while(p.next != null && k < size - 1){ + p = p.next; + k++; + } + Node newNode = new Node(o); + p.next = newNode; + } + } + public Object removeFirst(){ + Node node = head; + if(head != null){ + head = head.next; + } + return node.data; + } + public Object removeLast(){ + Node p = head; + int k = 0; + while(p.next != null && k < size - 2){ + k++; + p = p.next; + } + + p.next = null; + return p.next; + } + public Iterator iterator(){ + return null; + } + + + private static class Node{ + Object data; + Node next; + + private Node(Object o){ + this.data = o; + this.next = null; + } + } + + /** + * 把该链表逆置 + * head head + * 例如链表为 3->7->10 , 逆置后变为 10->7->3 + */ + public void reverse(){ + /** + * 长度超过1的单链表需要逆转 + */ + if(head == null || head.next == null){ + return; + } + Stack<Node> st = new Stack<Node>(); + Node currentNode = head; + while(currentNode != null){ + st.push(currentNode); + Node nextNode = currentNode.next; + currentNode.next = null;//断开连接 + currentNode = nextNode; + } + + head = (Node) st.pop(); + currentNode = head; + while(!st.isEmpty()){ + Node nextNode = (Node) st.pop(); + currentNode.next = nextNode; + currentNode = nextNode; + } + } + + + /** + * 删除一个单链表的前半部分 + * 例如:list = 2->5->7->8 , 删除以后的值为 7->8 + * 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10 + + */ + public void removeFirstHalf(){ + int num = size / 2; + for(int i = 0; i < num; i++){ + removeFirst(); + } + } + + /** + * 从第i个元素开始,删除length个元素 ,注意i从0开始 + * @param i + * @param length + */ + public void remove(int i, int length){ + if(i < 0 || i >= size){ + throw new IndexOutOfBoundsException(); + } + int len = size - i >= length ? length : size - i; + int k = 0; + while(k < len){ + remove(i); + k++; + } + + } + /** + * 假定当前链表和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[] newList = new int[list.size()]; + for(int i = 0;i < list.size(); i++){ + newList[i] = Integer.parseInt(this.get(Integer.parseInt(list.get(i).toString())).toString()); + } + return newList; + + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 从当前链表中中删除在listB中出现的元素 + + * @param list + */ + + public void subtract(LinkedList list){ + for(int j = 0;j < list.size();j++){ + this.remove(list.get(j)); + } + + } + + /** + * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) + */ + public void removeDuplicateValues(){ + if(head == null){ + throw new RuntimeException("LinkedList is null"); + + } + Node currentNode = head; + Node preNode = head; + while(currentNode.next != null){ + currentNode = currentNode.next; + Object data = preNode.data; + while(currentNode.data == data){ + if(currentNode.next == null){ + preNode.next = null; + break; + } + preNode.next = currentNode.next; + size--; + currentNode = currentNode.next; + if(currentNode == null){ + break; + } + } + preNode = preNode.next; + } + } + /** + * 传入删除数据节点 + */ + public void remove(Object obj){ + if(head == null){ + throw new RuntimeException("linkedlist is nuull"); + + } + if(head.data.equals(obj)){ + head = head.next; + size--; + }else{ + Node pre = head; + Node currentNode = head.next; + while(currentNode != null){ + if(currentNode.data.equals(obj)){ + pre.next = currentNode.next; + size--; + } + pre = pre.next; + currentNode = currentNode.next; + } + } + } + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 试写一高效的算法,删除表中所有值大于min且小于max的元素(若表中存在这样的元素) + * @param min + * @param max + */ + public void removeRange(int min, int max){ + Node node = head; + int start = -1; + int end = -1; + int i = 0; + while(node != null){ + if((Integer)node.data <= min){ + start = i; + } + if((Integer)node.data >= max){ + end = i; + break; + } + node = node.next; + i++; + } + if(start == -1){ + start = 0; + } + if(end == -1){ + end = size; + } + this.remove(start+1, end-start-1); + } + + /** + * 假设当前链表和参数list指定的链表均以元素依值递增有序排列(同一表中的元素值各不相同) + * 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列 + * @param list + */ + public LinkedList intersection(LinkedList list){ + if(list == null){ + return null; + } + + LinkedList newList = new LinkedList(); + int fi = 0; + int se = 0; + while(fi < this.size && se < list.size()){ + int val1 = (Integer) this.get(fi); + int val2 = (Integer) list.get(se); + if(val1 == val2){ + newList.add(val1); + fi++; + se++; + }else if(val1 < val2){ + fi++; + }else{ + se++; + } + + } + return newList; + } + + public static void main(String[] args) { + LinkedList linkedList = new LinkedList(); + linkedList.add(11); + linkedList.add(22); + linkedList.add(33); + linkedList.add(44); + linkedList.add(55); + linkedList.reverse(); + for(int i = 0; i < linkedList.size; i++){ + System.out.println(linkedList.get(i)); + } + } +} diff --git a/group04/1020483199/ThirdHomeWork/src/com/coding/basic/List.java b/group04/1020483199/ThirdHomeWork/src/com/coding/basic/List.java new file mode 100644 index 0000000000..10d13b5832 --- /dev/null +++ b/group04/1020483199/ThirdHomeWork/src/com/coding/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/group04/1020483199/ThirdHomeWork/src/com/coding/basic/Queue.java b/group04/1020483199/ThirdHomeWork/src/com/coding/basic/Queue.java new file mode 100644 index 0000000000..36e516e266 --- /dev/null +++ b/group04/1020483199/ThirdHomeWork/src/com/coding/basic/Queue.java @@ -0,0 +1,19 @@ +package com.coding.basic; + +public class Queue { + + public void enQueue(Object o){ + } + + public Object deQueue(){ + return null; + } + + public boolean isEmpty(){ + return false; + } + + public int size(){ + return -1; + } +} diff --git a/group04/1020483199/ThirdHomeWork/src/com/coding/basic/Stack.java b/group04/1020483199/ThirdHomeWork/src/com/coding/basic/Stack.java new file mode 100644 index 0000000000..a25d5b8024 --- /dev/null +++ b/group04/1020483199/ThirdHomeWork/src/com/coding/basic/Stack.java @@ -0,0 +1,22 @@ +package com.coding.basic; + +public class Stack<T> { + 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; + } +} From 19d33c7e787baaee70997b9ba672eeedc0fbc1df Mon Sep 17 00:00:00 2001 From: Alvin <conf1102@163.com> Date: Wed, 29 Mar 2017 00:22:16 -0800 Subject: [PATCH 072/287] 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<String> clzPaths = new ArrayList<String>(); + + 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 9caa1040c4a657627866537971382eae11311643 Mon Sep 17 00:00:00 2001 From: wzy <1264835468@qq.com> Date: Wed, 29 Mar 2017 18:35:00 +0800 Subject: [PATCH 073/287] lru --- group17/1264835468/.gitignore | 2 +- .../ArrayUtil.java | 367 +++++++++--------- .../ArrayUtilTest.java | 200 +++++----- .../LoginAction.java | 84 ++-- .../Struts.java | 198 +++++----- .../StrutsTest.java | 76 ++-- .../View.java | 52 +-- .../XmlParser.java | 144 +++---- .../src/assignment0326/lru/Clock.java | 50 +++ .../src/assignment0326/lru/EmployeeV1.java | 31 ++ .../src/assignment0326/lru/LRUPageFrame.java | 128 ++++++ .../assignment0326/lru/LRUPageFrameTest.java | 34 ++ group17/1264835468/src/struts.xml | 2 +- 13 files changed, 806 insertions(+), 562 deletions(-) rename group17/1264835468/src/{assignment2_26 => assignment0226}/ArrayUtil.java (95%) rename group17/1264835468/src/{assignment2_26 => assignment0226}/ArrayUtilTest.java (95%) rename group17/1264835468/src/{assignment2_26 => assignment0226}/LoginAction.java (91%) rename group17/1264835468/src/{assignment2_26 => assignment0226}/Struts.java (96%) rename group17/1264835468/src/{assignment2_26 => assignment0226}/StrutsTest.java (94%) rename group17/1264835468/src/{assignment2_26 => assignment0226}/View.java (87%) rename group17/1264835468/src/{assignment2_26 => assignment0226}/XmlParser.java (95%) create mode 100644 group17/1264835468/src/assignment0326/lru/Clock.java create mode 100644 group17/1264835468/src/assignment0326/lru/EmployeeV1.java create mode 100644 group17/1264835468/src/assignment0326/lru/LRUPageFrame.java create mode 100644 group17/1264835468/src/assignment0326/lru/LRUPageFrameTest.java diff --git a/group17/1264835468/.gitignore b/group17/1264835468/.gitignore index 37a597f996..1517b9e684 100644 --- a/group17/1264835468/.gitignore +++ b/group17/1264835468/.gitignore @@ -4,4 +4,4 @@ .project .gitignore /.idea/ -.iml \ No newline at end of file +.iml diff --git a/group17/1264835468/src/assignment2_26/ArrayUtil.java b/group17/1264835468/src/assignment0226/ArrayUtil.java similarity index 95% rename from group17/1264835468/src/assignment2_26/ArrayUtil.java rename to group17/1264835468/src/assignment0226/ArrayUtil.java index 89d2a0db29..8b279dca28 100644 --- a/group17/1264835468/src/assignment2_26/ArrayUtil.java +++ b/group17/1264835468/src/assignment0226/ArrayUtil.java @@ -1,183 +1,184 @@ -package assignment2_26; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.TreeSet; - -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) { - int mid = origin.length / 2; - for (int i = 0; i < mid; i++) { - int temp = origin[i]; - int reversePosition = origin.length - 1; - origin[i] = origin[reversePosition]; - origin[reversePosition] = 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 static int[] removeZero(int[] oldArray) { - int count = 0; - for (int i : oldArray) { - if (i != 0) - count++; - } - int[] newArray = new int[count]; - int currentPos = 0; - for (int i = 0; i < oldArray.length; i++) { - if (oldArray[i] != 0) - newArray[currentPos++] = oldArray[i]; - } - 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) { - TreeSet<Integer> set = new TreeSet<>(); - for (Integer integer : array1) { - set.add(integer); - } - for (Integer integer : array2) { - set.add(integer); - } - int[] result = new int[set.size()]; - for (int i = 0; i < result.length; i++) { - result[i] = set.pollFirst(); - } - return result; - } - - /** - * 把一个已经存满数据的数组 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) { - return Arrays.copyOf(oldArray, size); - } - - /** - * 斐波那契数列为: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]; - List<Integer> fList = new ArrayList<>(); - fList.add(1); - fList.add(1); - int last = fList.size() - 1; - while (fList.get(last) < max) { - fList.add(fList.get(last) + fList.get(last - 1)); - last++; - } - int[] result = new int[fList.size() - 1]; - for (int i = 0; i < result.length; i++) { - result[i] = fList.get(i); - } - return result; - } - - /** - * 返回小于给定最大值max的所有素数数组 例如max = 23, 返回的数组为[2,3,5,7,11,13,17,19] - * - * @param max - * @return - */ - public static int[] getPrimes(int max) { - boolean[] isPrime = new boolean[max]; - List<Integer> primes = new ArrayList<>(); - for (int i = 0; i < isPrime.length; i++) { - isPrime[i] = true; - } - for (int i = 2; i * i < max; i++) { - for (int j = i; i * j < max; j++) - isPrime[i * j] = false; - } - for (int i = 2; i < isPrime.length; i++) { - if (isPrime[i]) - primes.add(i); - } - int[] result = new int[primes.size()]; - for (int i = 0; i < result.length; i++) { - result[i] = primes.get(i); - } - return result; - } - - /** - * 所谓“完数”, 是指这个数恰好等于它的因子之和,例如6=1+2+3 给定一个最大值max, 返回一个数组, 数组中是小于max 的所有完数 - * - * @param max - * @return - */ - public static int[] getPerfectNumbers(int max) { - int sum = 0; - ArrayList<Integer> perfectNumbers = new ArrayList<>(); - for (int i = 1; i < max; i++) { - for (int j = 1; j < i; j++) { - if (i % j == 0) { - sum += j; - } - } - if (sum == i) - perfectNumbers.add(i); - sum = 0; - } - - int[] result = new int[perfectNumbers.size()]; - for (int i = 0; i < result.length; i++) { - result[i] = perfectNumbers.get(i); - } - return result; - } - - /** - * 用seperator 把数组 array给连接起来 例如array= [3,8,9], seperator = "-" 则返回值为"3-8-9" - * - * @param array - * @param s - * @return - */ - public static String join(int[] array, String seperator) { - StringBuilder stringBuilder = new StringBuilder(); - for (int i : array) { - stringBuilder.append(i + seperator); - } - stringBuilder.delete(stringBuilder.length() - seperator.length(), stringBuilder.length()); - - return stringBuilder.toString(); - } - -} +package assignment0226; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.TreeSet; + +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) { + int mid = origin.length / 2; + for (int i = 0; i < mid; i++) { + int temp = origin[i]; + int reversePosition = origin.length - 1; + origin[i] = origin[reversePosition]; + origin[reversePosition] = 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 static int[] removeZero(int[] oldArray) { + int count = 0; + + for (int i : oldArray) { + if (i != 0) + count++; + } + int[] newArray = new int[count]; + int currentPos = 0; + for (int i = 0; i < oldArray.length; i++) { + if (oldArray[i] != 0) + newArray[currentPos++] = oldArray[i]; + } + 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) { + TreeSet<Integer> set = new TreeSet<>(); + for (Integer integer : array1) { + set.add(integer); + } + for (Integer integer : array2) { + set.add(integer); + } + int[] result = new int[set.size()]; + for (int i = 0; i < result.length; i++) { + result[i] = set.pollFirst(); + } + return result; + } + + /** + * 把一个已经存满数据的数组 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) { + return Arrays.copyOf(oldArray, size); + } + + /** + * 斐波那契数列为: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]; + List<Integer> fList = new ArrayList<>(); + fList.add(1); + fList.add(1); + int last = fList.size() - 1; + while (fList.get(last) < max) { + fList.add(fList.get(last) + fList.get(last - 1)); + last++; + } + int[] result = new int[fList.size() - 1]; + for (int i = 0; i < result.length; i++) { + result[i] = fList.get(i); + } + return result; + } + + /** + * 返回小于给定最大值max的所有素数数组 例如max = 23, 返回的数组为[2,3,5,7,11,13,17,19] + * + * @param max + * @return + */ + public static int[] getPrimes(int max) { + boolean[] isPrime = new boolean[max]; + List<Integer> primes = new ArrayList<>(); + for (int i = 0; i < isPrime.length; i++) { + isPrime[i] = true; + } + for (int i = 2; i * i < max; i++) { + for (int j = i; i * j < max; j++) + isPrime[i * j] = false; + } + for (int i = 2; i < isPrime.length; i++) { + if (isPrime[i]) + primes.add(i); + } + int[] result = new int[primes.size()]; + for (int i = 0; i < result.length; i++) { + result[i] = primes.get(i); + } + return result; + } + + /** + * 所谓“完数”, 是指这个数恰好等于它的因子之和,例如6=1+2+3 给定一个最大值max, 返回一个数组, 数组中是小于max 的所有完数 + * + * @param max + * @return + */ + public static int[] getPerfectNumbers(int max) { + int sum = 0; + ArrayList<Integer> perfectNumbers = new ArrayList<>(); + for (int i = 1; i < max; i++) { + for (int j = 1; j < i; j++) { + if (i % j == 0) { + sum += j; + } + } + if (sum == i) + perfectNumbers.add(i); + sum = 0; + } + + int[] result = new int[perfectNumbers.size()]; + for (int i = 0; i < result.length; i++) { + result[i] = perfectNumbers.get(i); + } + return result; + } + + /** + * 用seperator 把数组 array给连接起来 例如array= [3,8,9], seperator = "-" 则返回值为"3-8-9" + * + * @param array + * @param seperator + * @return + */ + public static String join(int[] array, String seperator) { + StringBuilder stringBuilder = new StringBuilder(); + for (int i : array) { + stringBuilder.append(i + seperator); + } + stringBuilder.delete(stringBuilder.length() - seperator.length(), stringBuilder.length()); + + return stringBuilder.toString(); + } + +} diff --git a/group17/1264835468/src/assignment2_26/ArrayUtilTest.java b/group17/1264835468/src/assignment0226/ArrayUtilTest.java similarity index 95% rename from group17/1264835468/src/assignment2_26/ArrayUtilTest.java rename to group17/1264835468/src/assignment0226/ArrayUtilTest.java index 753c026796..1ccd845e1c 100644 --- a/group17/1264835468/src/assignment2_26/ArrayUtilTest.java +++ b/group17/1264835468/src/assignment0226/ArrayUtilTest.java @@ -1,100 +1,100 @@ -package assignment2_26; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; - -import org.junit.Test; - -public class ArrayUtilTest { - - @Test - public void testReverseArray() { - int[] array = new int[] {}; - ArrayUtil.reverseArray(array); - assertArrayEquals(new int[] {}, array); - - array = new int[] { 1 }; - ArrayUtil.reverseArray(array); - assertArrayEquals(new int[] { 1 }, array); - - array = new int[] { 1, 2, 3 }; - ArrayUtil.reverseArray(array); - assertArrayEquals(new int[] { 3, 2, 1 }, array); - } - - @Test - public void testRemoveZero() { - int[] array = new int[] {}; - assertArrayEquals(new int[] {}, ArrayUtil.removeZero(array)); - - array = new int[] { 0 }; - assertArrayEquals(new int[] {}, ArrayUtil.removeZero(array)); - - array = new int[] { 1 }; - assertArrayEquals(new int[] { 1 }, ArrayUtil.removeZero(array)); - - array = new int[] { 1, 2, 0, 0, 3 }; - assertArrayEquals(new int[] { 1, 2, 3 }, ArrayUtil.removeZero(array)); - - array = new int[] { 1, 2, 3 }; - assertArrayEquals(new int[] { 1, 2, 3 }, ArrayUtil.removeZero(array)); - } - - @Test - public void testMerge() { - int[] array1 = { 3, 5, 7, 8 }; - int[] array2 = { 4, 5, 6, 7 }; - assertArrayEquals(new int[] { 3, 4, 5, 6, 7, 8 }, ArrayUtil.merge(array1, array2)); - } - - @Test - public void testGrow() { - int[] array = { 3, 5, 7 }; - assertArrayEquals(new int[] { 3, 5, 7, 0, 0 }, ArrayUtil.grow(array, 5)); - assertArrayEquals(new int[] { 3, 5, 7 }, ArrayUtil.grow(array, 3)); - } - - @Test - public void testFibonacci() { - assertArrayEquals(new int[] {}, ArrayUtil.fibonacci(1)); - - assertArrayEquals(new int[] { 1, 1 }, ArrayUtil.fibonacci(2)); - - assertArrayEquals(new int[] { 1, 1, 2, 3, 5, 8, 13 }, ArrayUtil.fibonacci(15)); - } - - @Test - public void testGetPrimes() { - assertArrayEquals(new int[] {}, ArrayUtil.getPrimes(1)); - - assertArrayEquals(new int[] {}, ArrayUtil.getPrimes(2)); - - assertArrayEquals(new int[] { 2 }, ArrayUtil.getPrimes(3)); - - assertArrayEquals(new int[] { 2, 3, 5, 7, 11, 13, 17, 19 }, ArrayUtil.getPrimes(20)); - } - - @Test - public void testGetPerfectNumbers() { - assertArrayEquals(new int[] { 6 }, ArrayUtil.getPerfectNumbers(10)); - - assertArrayEquals(new int[] { 6, 28 }, ArrayUtil.getPerfectNumbers(100)); - - assertArrayEquals(new int[] { 6, 28, 496 }, ArrayUtil.getPerfectNumbers(1000)); - - assertArrayEquals(new int[] { 6, 28, 496, 8128 }, ArrayUtil.getPerfectNumbers(10000)); - - } - - @Test - public void testJoin() { - assertEquals("3-4-5", ArrayUtil.join(new int[] { 3, 4, 5 }, "-")); - - assertEquals("345", ArrayUtil.join(new int[] { 3, 4, 5 }, "")); - - assertEquals("3", ArrayUtil.join(new int[] { 3 }, "")); - - assertEquals("3--4--5", ArrayUtil.join(new int[] { 3, 4, 5 }, "--")); - } - -} +package assignment0226; + +import org.junit.Test; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +public class ArrayUtilTest { + + @Test + public void testReverseArray() { + int[] array = new int[] {}; + ArrayUtil.reverseArray(array); + assertArrayEquals(new int[] {}, array); + + array = new int[] { 1 }; + ArrayUtil.reverseArray(array); + assertArrayEquals(new int[] { 1 }, array); + + array = new int[] { 1, 2, 3 }; + ArrayUtil.reverseArray(array); + assertArrayEquals(new int[] { 3, 2, 1 }, array); + } + + @Test + public void testRemoveZero() { + int[] array = new int[] {}; + assertArrayEquals(new int[] {}, ArrayUtil.removeZero(array)); + + array = new int[] { 0 }; + assertArrayEquals(new int[] {}, ArrayUtil.removeZero(array)); + + array = new int[] { 1 }; + assertArrayEquals(new int[] { 1 }, ArrayUtil.removeZero(array)); + + array = new int[] { 1, 2, 0, 0, 3 }; + assertArrayEquals(new int[] { 1, 2, 3 }, ArrayUtil.removeZero(array)); + + array = new int[] { 1, 2, 3 }; + assertArrayEquals(new int[] { 1, 2, 3 }, ArrayUtil.removeZero(array)); + } + + @Test + public void testMerge() { + int[] array1 = { 3, 5, 7, 8 }; + int[] array2 = { 4, 5, 6, 7 }; + assertArrayEquals(new int[] { 3, 4, 5, 6, 7, 8 }, ArrayUtil.merge(array1, array2)); + } + + @Test + public void testGrow() { + int[] array = { 3, 5, 7 }; + assertArrayEquals(new int[] { 3, 5, 7, 0, 0 }, ArrayUtil.grow(array, 5)); + assertArrayEquals(new int[] { 3, 5, 7 }, ArrayUtil.grow(array, 3)); + } + + @Test + public void testFibonacci() { + assertArrayEquals(new int[] {}, ArrayUtil.fibonacci(1)); + + assertArrayEquals(new int[] { 1, 1 }, ArrayUtil.fibonacci(2)); + + assertArrayEquals(new int[] { 1, 1, 2, 3, 5, 8, 13 }, ArrayUtil.fibonacci(15)); + } + + @Test + public void testGetPrimes() { + assertArrayEquals(new int[] {}, ArrayUtil.getPrimes(1)); + + assertArrayEquals(new int[] {}, ArrayUtil.getPrimes(2)); + + assertArrayEquals(new int[] { 2 }, ArrayUtil.getPrimes(3)); + + assertArrayEquals(new int[] { 2, 3, 5, 7, 11, 13, 17, 19 }, ArrayUtil.getPrimes(20)); + } + + @Test + public void testGetPerfectNumbers() { + assertArrayEquals(new int[] { 6 }, ArrayUtil.getPerfectNumbers(10)); + + assertArrayEquals(new int[] { 6, 28 }, ArrayUtil.getPerfectNumbers(100)); + + assertArrayEquals(new int[] { 6, 28, 496 }, ArrayUtil.getPerfectNumbers(1000)); + + assertArrayEquals(new int[] { 6, 28, 496, 8128 }, ArrayUtil.getPerfectNumbers(10000)); + + } + + @Test + public void testJoin() { + assertEquals("3-4-5", ArrayUtil.join(new int[] { 3, 4, 5 }, "-")); + + assertEquals("345", ArrayUtil.join(new int[] { 3, 4, 5 }, "")); + + assertEquals("3", ArrayUtil.join(new int[] { 3 }, "")); + + assertEquals("3--4--5", ArrayUtil.join(new int[] { 3, 4, 5 }, "--")); + } + +} diff --git a/group17/1264835468/src/assignment2_26/LoginAction.java b/group17/1264835468/src/assignment0226/LoginAction.java similarity index 91% rename from group17/1264835468/src/assignment2_26/LoginAction.java rename to group17/1264835468/src/assignment0226/LoginAction.java index 3101d322b8..652b5359ac 100644 --- a/group17/1264835468/src/assignment2_26/LoginAction.java +++ b/group17/1264835468/src/assignment0226/LoginAction.java @@ -1,42 +1,42 @@ -package assignment2_26; - -/** - * 这是一个用来展示登录的业务类, 其中的用户名和密码都是硬编码的。 - * - * @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; - } -} +package assignment0226; + +/** + * 这是一个用来展示登录的业务类, 其中的用户名和密码都是硬编码的。 + * + * @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/group17/1264835468/src/assignment2_26/Struts.java b/group17/1264835468/src/assignment0226/Struts.java similarity index 96% rename from group17/1264835468/src/assignment2_26/Struts.java rename to group17/1264835468/src/assignment0226/Struts.java index ad704e0433..457b6ad953 100644 --- a/group17/1264835468/src/assignment2_26/Struts.java +++ b/group17/1264835468/src/assignment0226/Struts.java @@ -1,99 +1,99 @@ -package assignment2_26; - -import java.io.File; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; - -public class Struts { - - private static File configFile = new File("./src/struts.xml");; - - public static View runAction(String actionName, Map<String, String> 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中的 <result> 配置,以及execute的返回值, 确定哪一个jsp, - 放到View对象的jsp字段中。 - - */ - // 0 - XmlParser phraser = new XmlParser(configFile); - String className = phraser.getClassNameByActionName(actionName); - View view = new View(); - try { - // 1 - Class<?> actionClass = Class.forName(className); - Constructor<?> constructor = actionClass.getConstructor(); - Object instance = constructor.newInstance(); - invokeSetters(actionClass, instance, parameters); - - // 2 - String result = invokeExecute(actionClass, instance); - - // 3 - Map<String, String> getterResult = invokeGetters(actionClass, instance); - view.setParameters(getterResult); - - // 4 - String resultJsp = phraser.getResultJsp(actionName, result); - view.setJsp(resultJsp); - - } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException - | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - e.printStackTrace(); - } - - return view; - } - - private static Map<String, String> invokeGetters(Class<?> actionClass, Object instance) - throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { - Map<String, String> result = new HashMap<>(); - for (Method method : actionClass.getDeclaredMethods()) { - if (method.getName().matches("get.*")) { - String fieldName = method.getName().substring(3).toLowerCase(); - String value = (String) (method.invoke(instance)); - result.put(fieldName, value); - } - } - return result; - } - - private static String invokeExecute(Class<?> actionClass, Object instance) throws NoSuchMethodException, - SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { - Method method = actionClass.getDeclaredMethod("execute"); - return (String) method.invoke(instance); - } - - private static void invokeSetters(Class<?> actionClass, Object instance, Map<String, String> parameters) - throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, - InvocationTargetException { - for (String fieldName : parameters.keySet()) { - invokeSetter(actionClass, instance, fieldName, parameters.get(fieldName)); - } - } - - private static void invokeSetter(Class<?> actionClass, Object instance, String fieldName, String value) - throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, - InvocationTargetException { - String setterName = "set" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1); - Method setter = actionClass.getDeclaredMethod(setterName, String.class); - setter.invoke(instance, value); - } -} +package assignment0226; + +import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +public class Struts { + + private static File configFile = new File("./src/struts.xml");; + + public static View runAction(String actionName, Map<String, String> 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中的 <result> 配置,以及execute的返回值, 确定哪一个jsp, + 放到View对象的jsp字段中。 + + */ + // 0 + XmlParser phraser = new XmlParser(configFile); + String className = phraser.getClassNameByActionName(actionName); + View view = new View(); + try { + // 1 + Class<?> actionClass = Class.forName(className); + Constructor<?> constructor = actionClass.getConstructor(); + Object instance = constructor.newInstance(); + invokeSetters(actionClass, instance, parameters); + + // 2 + String result = invokeExecute(actionClass, instance); + + // 3 + Map<String, String> getterResult = invokeGetters(actionClass, instance); + view.setParameters(getterResult); + + // 4 + String resultJsp = phraser.getResultJsp(actionName, result); + view.setJsp(resultJsp); + + } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException + | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + e.printStackTrace(); + } + + return view; + } + + private static Map<String, String> invokeGetters(Class<?> actionClass, Object instance) + throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { + Map<String, String> result = new HashMap<>(); + for (Method method : actionClass.getDeclaredMethods()) { + if (method.getName().matches("get.*")) { + String fieldName = method.getName().substring(3).toLowerCase(); + String value = (String) (method.invoke(instance)); + result.put(fieldName, value); + } + } + return result; + } + + private static String invokeExecute(Class<?> actionClass, Object instance) throws NoSuchMethodException, + SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + Method method = actionClass.getDeclaredMethod("execute"); + return (String) method.invoke(instance); + } + + private static void invokeSetters(Class<?> actionClass, Object instance, Map<String, String> parameters) + throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, + InvocationTargetException { + for (String fieldName : parameters.keySet()) { + invokeSetter(actionClass, instance, fieldName, parameters.get(fieldName)); + } + } + + private static void invokeSetter(Class<?> actionClass, Object instance, String fieldName, String value) + throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, + InvocationTargetException { + String setterName = "set" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1); + Method setter = actionClass.getDeclaredMethod(setterName, String.class); + setter.invoke(instance, value); + } +} diff --git a/group17/1264835468/src/assignment2_26/StrutsTest.java b/group17/1264835468/src/assignment0226/StrutsTest.java similarity index 94% rename from group17/1264835468/src/assignment2_26/StrutsTest.java rename to group17/1264835468/src/assignment0226/StrutsTest.java index f47410209b..1e677c38b3 100644 --- a/group17/1264835468/src/assignment2_26/StrutsTest.java +++ b/group17/1264835468/src/assignment0226/StrutsTest.java @@ -1,38 +1,38 @@ -package assignment2_26; - -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<String, String> params = new HashMap<String, String>(); - 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<String, String> params = new HashMap<String, String>(); - 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 assignment0226; + +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<String, String> params = new HashMap<String, String>(); + 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<String, String> params = new HashMap<String, String>(); + 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/group17/1264835468/src/assignment2_26/View.java b/group17/1264835468/src/assignment0226/View.java similarity index 87% rename from group17/1264835468/src/assignment2_26/View.java rename to group17/1264835468/src/assignment0226/View.java index e96197fad6..3bd518e451 100644 --- a/group17/1264835468/src/assignment2_26/View.java +++ b/group17/1264835468/src/assignment0226/View.java @@ -1,26 +1,26 @@ -package assignment2_26; - -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 assignment0226; + +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/group17/1264835468/src/assignment2_26/XmlParser.java b/group17/1264835468/src/assignment0226/XmlParser.java similarity index 95% rename from group17/1264835468/src/assignment2_26/XmlParser.java rename to group17/1264835468/src/assignment0226/XmlParser.java index aa34335cb6..4969951082 100644 --- a/group17/1264835468/src/assignment2_26/XmlParser.java +++ b/group17/1264835468/src/assignment0226/XmlParser.java @@ -1,72 +1,72 @@ -package assignment2_26; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; - -public class XmlParser { - private File file; - List<Element> actionElements; - - public XmlParser(File file) { - this.file = file; - actionElements = new ArrayList<>(); - getActionsFromFile(); - } - - public String getClassNameByActionName(String actionName) { - Element action = getElementByActionName(actionName); - return action.getAttribute("class"); - } - - public String getResultJsp(String actionName, String resultName) { - Element action = getElementByActionName(actionName); - NodeList results = action.getChildNodes(); - for (int i = 0; i < results.getLength(); i++) { - Node child = results.item(i); - if (child instanceof Element) { - Element result = (Element) child; - if (result.getAttribute("name").equals(resultName)) - return result.getTextContent(); - } - } - throw new RuntimeException("not found result named:" + resultName); - } - - private Element getElementByActionName(String actionName) { - for (Element element : actionElements) { - if (element.getAttribute("name").equals(actionName)) { - return element; - } - } - throw new RuntimeException("no such element named " + actionName); - } - - private void getActionsFromFile() { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - try { - DocumentBuilder builder = factory.newDocumentBuilder(); - Document document = builder.parse(file); - Element root = document.getDocumentElement(); - NodeList children = root.getChildNodes(); - for (int i = 0; i < children.getLength(); i++) { - Node child = children.item(i); - if (child instanceof Element) - actionElements.add((Element) child); - } - } catch (ParserConfigurationException | SAXException | IOException e) { - e.printStackTrace(); - } - } -} +package assignment0226; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +public class XmlParser { + private File file; + List<Element> actionElements; + + public XmlParser(File file) { + this.file = file; + actionElements = new ArrayList<>(); + getActionsFromFile(); + } + + public String getClassNameByActionName(String actionName) { + Element action = getElementByActionName(actionName); + return action.getAttribute("class"); + } + + public String getResultJsp(String actionName, String resultName) { + Element action = getElementByActionName(actionName); + NodeList results = action.getChildNodes(); + for (int i = 0; i < results.getLength(); i++) { + Node child = results.item(i); + if (child instanceof Element) { + Element result = (Element) child; + if (result.getAttribute("name").equals(resultName)) + return result.getTextContent(); + } + } + throw new RuntimeException("not found result named:" + resultName); + } + + private Element getElementByActionName(String actionName) { + for (Element element : actionElements) { + if (element.getAttribute("name").equals(actionName)) { + return element; + } + } + throw new RuntimeException("no such element named " + actionName); + } + + private void getActionsFromFile() { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + try { + DocumentBuilder builder = factory.newDocumentBuilder(); + Document document = builder.parse(file); + Element root = document.getDocumentElement(); + NodeList children = root.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + if (child instanceof Element) + actionElements.add((Element) child); + } + } catch (ParserConfigurationException | SAXException | IOException e) { + e.printStackTrace(); + } + } +} diff --git a/group17/1264835468/src/assignment0326/lru/Clock.java b/group17/1264835468/src/assignment0326/lru/Clock.java new file mode 100644 index 0000000000..23198886fe --- /dev/null +++ b/group17/1264835468/src/assignment0326/lru/Clock.java @@ -0,0 +1,50 @@ +package assignment0326.lru; + +/** + * Created by Administrator on 2017/3/29. + */ +public class Clock { + private PageFrame[] pages; + private int capacity; + private int accessPtr; + public Clock(int capacity) { + this.capacity = capacity; + pages = new PageFrame[capacity]; + accessPtr=0; + } + + private void access(int pageNum){ + if (pages[accessPtr] == null) { + pages[accessPtr] = new PageFrame(pageNum); + }else{ + int indexToReplace=findLRUIndex(); + pages[indexToReplace].pageNum=pageNum; + } + accessPtr = (accessPtr + 1) % capacity; + } + + private int findLRUIndex() { + while(pages[accessPtr].shouldGiveAnotherChance()){ + accessPtr = (accessPtr + 1) % capacity; + } + return accessPtr; + } + + private static class PageFrame{ + int pageNum; + boolean accessFlag; + + public PageFrame(int pageNum) { + this.pageNum = pageNum; + accessFlag=true; + } + + public boolean shouldGiveAnotherChance() { + if(accessFlag){ + accessFlag=false; + return true; + } + return false; + } + } +} diff --git a/group17/1264835468/src/assignment0326/lru/EmployeeV1.java b/group17/1264835468/src/assignment0326/lru/EmployeeV1.java new file mode 100644 index 0000000000..bad73de115 --- /dev/null +++ b/group17/1264835468/src/assignment0326/lru/EmployeeV1.java @@ -0,0 +1,31 @@ +package assignment0326.lru; + +/** + * Created by Administrator on 2017/3/29. + */ +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/group17/1264835468/src/assignment0326/lru/LRUPageFrame.java b/group17/1264835468/src/assignment0326/lru/LRUPageFrame.java new file mode 100644 index 0000000000..542075129f --- /dev/null +++ b/group17/1264835468/src/assignment0326/lru/LRUPageFrame.java @@ -0,0 +1,128 @@ +package assignment0326.lru; + +/** + * 用双向链表实现LRU算法 + * @author liuxin + * + */ +public class LRUPageFrame { + + private static class Node { + + Node prev; + Node next; + int pageNum; + Node() { + } + public Node(int pageNum) { + this.pageNum = pageNum; + } + + } + + private int capacity; + + + private Node first;// 链表头 + private Node last;// 链表尾 + + private int size; + public LRUPageFrame(int capacity) { + if(capacity<=0) + throw new IllegalArgumentException("capacity:"+capacity+" < 0"); + this.capacity = capacity; + first=null; + last=null; + size=0; + + } + + /** + * 获取缓存中对象 + * + * @param pageNum + * @return + */ + public void access(int pageNum) { + Node target=search(pageNum); + if (target == null) { + target=new Node(pageNum); + linkFirst(target); + }else{ + moveToFirst(target); + } + if(size>capacity){ + removeLast(); + } + } + + private Node search(int pageNum) { + Node f=first; + while (f!=null){ + if (f.pageNum == pageNum) { + return f; + } + f=f.next; + } + return null; + } + + private void linkFirst(Node target) { + if(first==null){ + first=last=target; + }else { + target.next = first; + first.prev = target; + first = target; + } + size++; + } + + private void moveToFirst(Node target) { + if(target==first){ + return; + } + Node prevOfTarget=target.prev; + prevOfTarget.next=target.next; + + if(target==last) { + last=prevOfTarget; + }else { + target.next.prev = prevOfTarget; + } + + target.next=first; + first.prev=target; + first=target; + + } + + private void removeLast() { + Node prevOfLast=last.prev; + last.prev=null; + last=prevOfLast; + + if(last==null){ + first=null; + }else { + 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(); + } + +} \ No newline at end of file diff --git a/group17/1264835468/src/assignment0326/lru/LRUPageFrameTest.java b/group17/1264835468/src/assignment0326/lru/LRUPageFrameTest.java new file mode 100644 index 0000000000..7a54f54c8d --- /dev/null +++ b/group17/1264835468/src/assignment0326/lru/LRUPageFrameTest.java @@ -0,0 +1,34 @@ +package assignment0326.lru; + +import org.junit.Assert; +import org.junit.Test; + +/** + * Created by Administrator on 2017/3/29. + */ + + +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()); + } + +} \ No newline at end of file diff --git a/group17/1264835468/src/struts.xml b/group17/1264835468/src/struts.xml index ad43b47967..9ba23d1e24 100644 --- a/group17/1264835468/src/struts.xml +++ b/group17/1264835468/src/struts.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <struts> - <action name="login" class="assignment2_26.LoginAction"> + <action name="login" class="assignment0226.LoginAction"> <result name="success">/jsp/homepage.jsp</result> <result name="fail">/jsp/showLogin.jsp</result> </action> From 33c65451f4ed91480bf4d79981947d0d68ee16e6 Mon Sep 17 00:00:00 2001 From: maishihang <446031103@qq.com> Date: Wed, 29 Mar 2017 21:52:55 +0800 Subject: [PATCH 074/287] =?UTF-8?q?=E5=88=86=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../array/ArrayUtil.java | 2 +- .../array/ArrayUtilTest.java | 2 +- .../{coding => datastructure}/basic/ArrayList.java | 12 ++++++------ .../basic/BinaryTreeNode.java | 2 +- .../{coding => datastructure}/basic/Iterator.java | 2 +- .../{coding => datastructure}/basic/LinkedList.java | 12 ++++++------ .../com/{coding => datastructure}/basic/List.java | 2 +- .../com/{coding => datastructure}/basic/Queue.java | 2 +- .../com/{coding => datastructure}/basic/Stack.java | 2 +- 9 files changed, 19 insertions(+), 19 deletions(-) rename group12/446031103/src/com/{coderising => datastructure}/array/ArrayUtil.java (99%) rename group12/446031103/src/com/{coderising => datastructure}/array/ArrayUtilTest.java (98%) rename group12/446031103/src/com/{coding => datastructure}/basic/ArrayList.java (89%) rename group12/446031103/src/com/{coding => datastructure}/basic/BinaryTreeNode.java (96%) rename group12/446031103/src/com/{coding => datastructure}/basic/Iterator.java (71%) rename group12/446031103/src/com/{coding => datastructure}/basic/LinkedList.java (96%) rename group12/446031103/src/com/{coding => datastructure}/basic/List.java (84%) rename group12/446031103/src/com/{coding => datastructure}/basic/Queue.java (97%) rename group12/446031103/src/com/{coding => datastructure}/basic/Stack.java (97%) diff --git a/group12/446031103/src/com/coderising/array/ArrayUtil.java b/group12/446031103/src/com/datastructure/array/ArrayUtil.java similarity index 99% rename from group12/446031103/src/com/coderising/array/ArrayUtil.java rename to group12/446031103/src/com/datastructure/array/ArrayUtil.java index 30506ef87a..a5b62040bc 100644 --- a/group12/446031103/src/com/coderising/array/ArrayUtil.java +++ b/group12/446031103/src/com/datastructure/array/ArrayUtil.java @@ -1,4 +1,4 @@ -package com.coderising.array; +package com.datastructure.array; import java.util.ArrayList; import java.util.Arrays; diff --git a/group12/446031103/src/com/coderising/array/ArrayUtilTest.java b/group12/446031103/src/com/datastructure/array/ArrayUtilTest.java similarity index 98% rename from group12/446031103/src/com/coderising/array/ArrayUtilTest.java rename to group12/446031103/src/com/datastructure/array/ArrayUtilTest.java index a22ac30c9b..295a463754 100644 --- a/group12/446031103/src/com/coderising/array/ArrayUtilTest.java +++ b/group12/446031103/src/com/datastructure/array/ArrayUtilTest.java @@ -1,4 +1,4 @@ -package com.coderising.array; +package com.datastructure.array; import static org.junit.Assert.*; diff --git a/group12/446031103/src/com/coding/basic/ArrayList.java b/group12/446031103/src/com/datastructure/basic/ArrayList.java similarity index 89% rename from group12/446031103/src/com/coding/basic/ArrayList.java rename to group12/446031103/src/com/datastructure/basic/ArrayList.java index bc3d75c3f6..fdfa891a64 100644 --- a/group12/446031103/src/com/coding/basic/ArrayList.java +++ b/group12/446031103/src/com/datastructure/basic/ArrayList.java @@ -1,4 +1,4 @@ -package com.coding.basic; +package com.datastructure.basic; import java.util.Arrays; @@ -21,7 +21,7 @@ public class ArrayList implements List { * * @Method add 添加 * @param o 元素 - * @see com.coding.basic.List#add(java.lang.Object) + * @see com.datastructure.basic.List#add(java.lang.Object) */ public void add(Object o){ ensureCapacity(size + 1); @@ -35,7 +35,7 @@ public void add(Object o){ * @Method add 添加 * @param index 下标 * @param o 元素 - * @see com.coding.basic.List#add(int, java.lang.Object) + * @see com.datastructure.basic.List#add(int, java.lang.Object) */ public void add(int index, Object o){ validate(index); @@ -51,7 +51,7 @@ public void add(int index, Object o){ * @Method get 取得 * @param index 下标 * @return - * @see com.coding.basic.List#get(int) + * @see com.datastructure.basic.List#get(int) */ public Object get(int index){ validate(index); @@ -64,7 +64,7 @@ public Object get(int index){ * @Method remove 删除 * @param index 下标 * @return 删除的元素 - * @see com.coding.basic.List#remove(int) + * @see com.datastructure.basic.List#remove(int) */ public Object remove(int index){ validate(index); @@ -80,7 +80,7 @@ public Object remove(int index){ * * @Method size 集合大小 * @return 集合大小 - * @see com.coding.basic.List#size() + * @see com.datastructure.basic.List#size() */ public int size(){ return this.size; diff --git a/group12/446031103/src/com/coding/basic/BinaryTreeNode.java b/group12/446031103/src/com/datastructure/basic/BinaryTreeNode.java similarity index 96% rename from group12/446031103/src/com/coding/basic/BinaryTreeNode.java rename to group12/446031103/src/com/datastructure/basic/BinaryTreeNode.java index ed26d946bb..73be06fad2 100644 --- a/group12/446031103/src/com/coding/basic/BinaryTreeNode.java +++ b/group12/446031103/src/com/datastructure/basic/BinaryTreeNode.java @@ -1,4 +1,4 @@ -package com.coding.basic; +package com.datastructure.basic; public class BinaryTreeNode { diff --git a/group12/446031103/src/com/coding/basic/Iterator.java b/group12/446031103/src/com/datastructure/basic/Iterator.java similarity index 71% rename from group12/446031103/src/com/coding/basic/Iterator.java rename to group12/446031103/src/com/datastructure/basic/Iterator.java index 06ef6311b2..bee5d797c9 100644 --- a/group12/446031103/src/com/coding/basic/Iterator.java +++ b/group12/446031103/src/com/datastructure/basic/Iterator.java @@ -1,4 +1,4 @@ -package com.coding.basic; +package com.datastructure.basic; public interface Iterator { public boolean hasNext(); diff --git a/group12/446031103/src/com/coding/basic/LinkedList.java b/group12/446031103/src/com/datastructure/basic/LinkedList.java similarity index 96% rename from group12/446031103/src/com/coding/basic/LinkedList.java rename to group12/446031103/src/com/datastructure/basic/LinkedList.java index d60f4a2dee..164e804f8a 100644 --- a/group12/446031103/src/com/coding/basic/LinkedList.java +++ b/group12/446031103/src/com/datastructure/basic/LinkedList.java @@ -1,4 +1,4 @@ -package com.coding.basic; +package com.datastructure.basic; import java.util.Stack; /** @@ -20,7 +20,7 @@ public class LinkedList implements List { * * @Method add 添加 * @param o 元素 - * @see com.coding.basic.List#add(java.lang.Object) + * @see com.datastructure.basic.List#add(java.lang.Object) */ public void add(Object o){ Node newNode = new Node(o, null); @@ -42,7 +42,7 @@ public void add(Object o){ * @Method add 增加 * @param index 下标 * @param o 元素 - * @see com.coding.basic.List#add(int, java.lang.Object) + * @see com.datastructure.basic.List#add(int, java.lang.Object) */ public void add(int index , Object o){ validate(index); @@ -79,7 +79,7 @@ public void add(int index , Object o){ * @Method get 取得 * @param index 下标 * @return - * @see com.coding.basic.List#get(int) + * @see com.datastructure.basic.List#get(int) */ public Object get(int index){ validate(index); @@ -96,7 +96,7 @@ public Object get(int index){ * @Method remove 删除 * @param index 下标 * @return - * @see com.coding.basic.List#remove(int) + * @see com.datastructure.basic.List#remove(int) */ public Object remove(int index){ Node removeNode = (Node) get(index); @@ -122,7 +122,7 @@ public Object remove(int index){ * * @Method size 集合大小 * @return 集合大小 - * @see com.coding.basic.List#size() + * @see com.datastructure.basic.List#size() */ public int size(){ return size; diff --git a/group12/446031103/src/com/coding/basic/List.java b/group12/446031103/src/com/datastructure/basic/List.java similarity index 84% rename from group12/446031103/src/com/coding/basic/List.java rename to group12/446031103/src/com/datastructure/basic/List.java index 10d13b5832..633f1f73e2 100644 --- a/group12/446031103/src/com/coding/basic/List.java +++ b/group12/446031103/src/com/datastructure/basic/List.java @@ -1,4 +1,4 @@ -package com.coding.basic; +package com.datastructure.basic; public interface List { public void add(Object o); diff --git a/group12/446031103/src/com/coding/basic/Queue.java b/group12/446031103/src/com/datastructure/basic/Queue.java similarity index 97% rename from group12/446031103/src/com/coding/basic/Queue.java rename to group12/446031103/src/com/datastructure/basic/Queue.java index 3844d9dd24..d0d64c2b50 100644 --- a/group12/446031103/src/com/coding/basic/Queue.java +++ b/group12/446031103/src/com/datastructure/basic/Queue.java @@ -1,4 +1,4 @@ -package com.coding.basic; +package com.datastructure.basic; /** * diff --git a/group12/446031103/src/com/coding/basic/Stack.java b/group12/446031103/src/com/datastructure/basic/Stack.java similarity index 97% rename from group12/446031103/src/com/coding/basic/Stack.java rename to group12/446031103/src/com/datastructure/basic/Stack.java index 4d1c58b671..398dc667bd 100644 --- a/group12/446031103/src/com/coding/basic/Stack.java +++ b/group12/446031103/src/com/datastructure/basic/Stack.java @@ -1,4 +1,4 @@ -package com.coding.basic; +package com.datastructure.basic; /** * From 1a023178eccce4b4f1b647c4a576eb23d78719d6 Mon Sep 17 00:00:00 2001 From: maishihang <446031103@qq.com> Date: Wed, 29 Mar 2017 22:00:26 +0800 Subject: [PATCH 075/287] =?UTF-8?q?=E5=88=86=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{basic => array}/ArrayList.java | 5 +- .../src/com/datastructure/basic/Queue.java | 2 + .../src/com/datastructure/basic/Stack.java | 2 + .../datastructure/linklist/LRUPageFrame.java | 60 +++++++++++++++++++ .../linklist/LRUPageFrameTest.java | 31 ++++++++++ .../{basic => linklist}/LinkedList.java | 5 +- 6 files changed, 103 insertions(+), 2 deletions(-) rename group12/446031103/src/com/datastructure/{basic => array}/ArrayList.java (96%) create mode 100644 group12/446031103/src/com/datastructure/linklist/LRUPageFrame.java create mode 100644 group12/446031103/src/com/datastructure/linklist/LRUPageFrameTest.java rename group12/446031103/src/com/datastructure/{basic => linklist}/LinkedList.java (98%) diff --git a/group12/446031103/src/com/datastructure/basic/ArrayList.java b/group12/446031103/src/com/datastructure/array/ArrayList.java similarity index 96% rename from group12/446031103/src/com/datastructure/basic/ArrayList.java rename to group12/446031103/src/com/datastructure/array/ArrayList.java index fdfa891a64..9731daec06 100644 --- a/group12/446031103/src/com/datastructure/basic/ArrayList.java +++ b/group12/446031103/src/com/datastructure/array/ArrayList.java @@ -1,7 +1,10 @@ -package com.datastructure.basic; +package com.datastructure.array; import java.util.Arrays; +import com.datastructure.basic.Iterator; +import com.datastructure.basic.List; + /** diff --git a/group12/446031103/src/com/datastructure/basic/Queue.java b/group12/446031103/src/com/datastructure/basic/Queue.java index d0d64c2b50..b82627d59f 100644 --- a/group12/446031103/src/com/datastructure/basic/Queue.java +++ b/group12/446031103/src/com/datastructure/basic/Queue.java @@ -1,5 +1,7 @@ package com.datastructure.basic; +import com.datastructure.linklist.LinkedList; + /** * * 队列-先进先出 diff --git a/group12/446031103/src/com/datastructure/basic/Stack.java b/group12/446031103/src/com/datastructure/basic/Stack.java index 398dc667bd..3088b0a000 100644 --- a/group12/446031103/src/com/datastructure/basic/Stack.java +++ b/group12/446031103/src/com/datastructure/basic/Stack.java @@ -1,5 +1,7 @@ package com.datastructure.basic; +import com.datastructure.array.ArrayList; + /** * * 栈-先进后出 diff --git a/group12/446031103/src/com/datastructure/linklist/LRUPageFrame.java b/group12/446031103/src/com/datastructure/linklist/LRUPageFrame.java new file mode 100644 index 0000000000..bce6b36a64 --- /dev/null +++ b/group12/446031103/src/com/datastructure/linklist/LRUPageFrame.java @@ -0,0 +1,60 @@ +package com.datastructure.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/group12/446031103/src/com/datastructure/linklist/LRUPageFrameTest.java b/group12/446031103/src/com/datastructure/linklist/LRUPageFrameTest.java new file mode 100644 index 0000000000..2d265f0bd3 --- /dev/null +++ b/group12/446031103/src/com/datastructure/linklist/LRUPageFrameTest.java @@ -0,0 +1,31 @@ +package com.datastructure.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/group12/446031103/src/com/datastructure/basic/LinkedList.java b/group12/446031103/src/com/datastructure/linklist/LinkedList.java similarity index 98% rename from group12/446031103/src/com/datastructure/basic/LinkedList.java rename to group12/446031103/src/com/datastructure/linklist/LinkedList.java index 164e804f8a..1236734423 100644 --- a/group12/446031103/src/com/datastructure/basic/LinkedList.java +++ b/group12/446031103/src/com/datastructure/linklist/LinkedList.java @@ -1,6 +1,9 @@ -package com.datastructure.basic; +package com.datastructure.linklist; import java.util.Stack; +import com.datastructure.basic.Iterator; +import com.datastructure.basic.List; + /** * * LinkedList集合-链 From ee74cda695eb7092a9030b0fe358c2d1891e46f2 Mon Sep 17 00:00:00 2001 From: maishihang <446031103@qq.com> Date: Wed, 29 Mar 2017 22:06:44 +0800 Subject: [PATCH 076/287] =?UTF-8?q?=E6=B7=BB=E5=8A=A0JVM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jvm/loader/ClassFileLoader.java | 43 +++++++++ .../jvm/test/ClassFileloaderTest.java | 92 +++++++++++++++++++ .../com/coderising/jvm/test/EmployeeV1.java | 28 ++++++ 3 files changed, 163 insertions(+) create mode 100644 group12/446031103/src/com/coderising/jvm/loader/ClassFileLoader.java create mode 100644 group12/446031103/src/com/coderising/jvm/test/ClassFileloaderTest.java create mode 100644 group12/446031103/src/com/coderising/jvm/test/EmployeeV1.java diff --git a/group12/446031103/src/com/coderising/jvm/loader/ClassFileLoader.java b/group12/446031103/src/com/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..e021b94d38 --- /dev/null +++ b/group12/446031103/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,43 @@ +package com.coderising.jvm.loader; + +import java.util.ArrayList; +import java.util.List; + + + +public class ClassFileLoader { + + private List<String> clzPaths = new ArrayList<String>(); + + public byte[] readBinaryCode(String className) { + + return null; + + + } + + private byte[] loadClassFile(String clzFileName) { + + return null; + } + + + + public void addClassPath(String path) { + + } + + public String getClassPath_V1(){ + + return null; + } + + public String getClassPath(){ + return null; + } + + + + + +} diff --git a/group12/446031103/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group12/446031103/src/com/coderising/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..50eb1be6fa --- /dev/null +++ b/group12/446031103/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,92 @@ +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(); + } + +} diff --git a/group12/446031103/src/com/coderising/jvm/test/EmployeeV1.java b/group12/446031103/src/com/coderising/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..5e2bd8668f --- /dev/null +++ b/group12/446031103/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(); + + } +} From e8a369ece137c9e74436804aefe6395c5017a9b7 Mon Sep 17 00:00:00 2001 From: Cary <gkqforever@hotmail.com> Date: Thu, 30 Mar 2017 08:26:04 +0800 Subject: [PATCH 077/287] [#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<Integer> list = new ArrayList<Integer>(); + 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<Integer> 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<Integer> list = new ArrayList<Integer>(); + 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<Integer> list = new ArrayList<Integer>(); + 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<String, ActionConfig> 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<String, String> 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<Method> getSetterMethods(Class<?> clz) { + List<Method> methods = new ArrayList<>(); + for (Method m : clz.getDeclaredMethods()) { + if (m.getName().startsWith("set")) { + methods.add(m); + } + } + return methods; + } + + public static List<Method> getGetterMethods(Class<?> clz) { + List<Method> methods = new ArrayList<Method>(); + for (Method m : clz.getDeclaredMethods()) { + if (m.getName().startsWith("get")) { + methods.add(m); + } + } + return methods; + } + + public static List<Method> getMethods(Class<?> clz, String startWithName) { + List<Method> 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<String, String> params) { + List<Method> 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<String, Object> getParamterMap(Object o) { + Map<String, Object> params = new HashMap<>(); + List<Method> 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<Method> methods = ReflectionUtil.getSetterMethods(clz); + + Assert.assertEquals(2, methods.size()); + + List<String> expectNames = new ArrayList<>(); + expectNames.add("setName"); + expectNames.add("setPassword"); + + Set<String> 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<String,String> params = new HashMap<String,String>(); + 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<Method> methods = ReflectionUtil.getGetterMethods(clz); + + Assert.assertEquals(3, methods.size()); + List<String> expectNames = new ArrayList<>(); + expectNames.add("getName"); + expectNames.add("getPassword"); + expectNames.add("getMessage"); + + Set<String> 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<Method> methods = ReflectionUtil.getMethods(clz, "get"); + + Assert.assertEquals(3, methods.size()); + List<String> expectNames = new ArrayList<>(); + expectNames.add("getName"); + expectNames.add("getPassword"); + expectNames.add("getMessage"); + + Set<String> 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<String, Object> 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<String,String> 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中的 <result> 配置,以及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<String, Object> 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<String,String> params = new HashMap<String,String>(); + 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<String,String> params = new HashMap<String,String>(); + 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 534e035d0392ad8961b513010e9053b551909c31 Mon Sep 17 00:00:00 2001 From: vegetableDogBai <bdl1994@163.com> Date: Thu, 30 Mar 2017 09:11:14 +0800 Subject: [PATCH 078/287] =?UTF-8?q?=E6=95=B0=E6=8D=AE=E7=BB=93=E6=9E=84?= =?UTF-8?q?=E4=BD=9C=E4=B8=9A=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../563253496/week4_lru/src/LRUPageFrame.java | 135 ++++++++++++++++++ .../week4_lru/src/LRUPageFrameTest.java | 34 +++++ 2 files changed, 169 insertions(+) create mode 100644 group12/563253496/week4_lru/src/LRUPageFrame.java create mode 100644 group12/563253496/week4_lru/src/LRUPageFrameTest.java diff --git a/group12/563253496/week4_lru/src/LRUPageFrame.java b/group12/563253496/week4_lru/src/LRUPageFrame.java new file mode 100644 index 0000000000..80c23f5cfd --- /dev/null +++ b/group12/563253496/week4_lru/src/LRUPageFrame.java @@ -0,0 +1,135 @@ +/** + * Created by bdl19 on 2017/3/29. + */ +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; + initialize(); + //count = 0; + } + + /** + * 获取缓存中对象 + * + * @param + * @return + */ + public void access(int pageNum) { + int index = checkPageNum(pageNum); + if (index < 0) { + addNewNode(pageNum); + } else { + moveNode(index); + } + + } + + private void moveNode(int index) { + Node temp = first; + if (index == capacity - 1) { + Node node = last; + last = last.prev; + node.prev.next=null; + + node.prev = null; + node.next=first; + + + first.prev=node; + first = node; + return; + } + + if(index==0){ + return; + } + + for (int i = 0; i < index; i++) { + temp = temp.next; + } + + temp.prev.next = temp.next; + temp.next.prev = temp.prev; + temp.next = first; + temp.prev = null; + first.prev = temp; + first = temp; + } + + private void addNewNode(int pageNum) { + Node node = new Node(); + first.prev = node; + node.next = first; + first.prev = node; + node.pageNum = pageNum; + first = node; + last = last.prev; + last.next = null; + } + + + private int checkPageNum(int num) { + Node node = first; + int index = 0; + while (node != null) { + if (node.pageNum == num) { + return index; + } + index++; + node = node.next; + } + return -1; + } + + + private void initialize() { + if (capacity <= 0) { + throw new IndexOutOfBoundsException(); + } + Node node = new Node(); + first = node; + last = node; + for (int i = 0; i < capacity - 1; i++) { + Node n = new Node(); + Node temp = last; + last.next = n; + last = n; + last.prev = temp; + } + } + + + 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/563253496/week4_lru/src/LRUPageFrameTest.java b/group12/563253496/week4_lru/src/LRUPageFrameTest.java new file mode 100644 index 0000000000..41e3727e34 --- /dev/null +++ b/group12/563253496/week4_lru/src/LRUPageFrameTest.java @@ -0,0 +1,34 @@ +import org.junit.Test; +import org.junit.Before; +import org.junit.After; +import org.junit.Assert; +/** +* LRUPageFrame Tester. +* +* @author <Authors name> +* @since <pre> 29, 2017</pre> +* @version 1.0 +*/ 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 861b04b18094772681770057f344d9b81264a889 Mon Sep 17 00:00:00 2001 From: vegetableDogBai <bdl1994@163.com> Date: Thu, 30 Mar 2017 11:03:36 +0800 Subject: [PATCH 079/287] =?UTF-8?q?jvm=E7=AC=AC=E4=B8=80=E5=91=A8=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jvm/loader/ClassFileLoader.java | 81 ++++++++++++++++ .../jvm/test/ClassFileloaderTest.java | 92 +++++++++++++++++++ .../com/coderising/jvm/test/EmployeeV1.java | 28 ++++++ 3 files changed, 201 insertions(+) create mode 100644 group12/563253496/week4_jvm1/src/com/coderising/jvm/loader/ClassFileLoader.java create mode 100644 group12/563253496/week4_jvm1/src/com/coderising/jvm/test/ClassFileloaderTest.java create mode 100644 group12/563253496/week4_jvm1/src/com/coderising/jvm/test/EmployeeV1.java diff --git a/group12/563253496/week4_jvm1/src/com/coderising/jvm/loader/ClassFileLoader.java b/group12/563253496/week4_jvm1/src/com/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..5f56b80bff --- /dev/null +++ b/group12/563253496/week4_jvm1/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,81 @@ +package com.coderising.jvm.loader; + +import java.io.*; +import java.util.ArrayList; +import java.util.List; + + +public class ClassFileLoader { + + private List<String> clzPaths = new ArrayList<String>(); + + public byte[] readBinaryCode(String className) { + String path = getClassFilePath(className); + if (path != null) { + try { + BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path)); + int count = bis.available(); + byte[] content = new byte[count]; + int len = bis.read(content,0,count); + return content; + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return null; + + + } + + private byte[] loadClassFile(String clzFileName) { + + return null; + } + + + public void addClassPath(String path) { + clzPaths.add(path); + } + + public String getClassPath_V1() { + + return null; + } + + public String getClassPath() { + StringBuilder sb = new StringBuilder(); + for (String s : clzPaths) { + sb.append(s); + sb.append(";"); + } + sb.deleteCharAt(sb.length() - 1); + return sb.toString(); + } + + private String getClassFilePath(String className) { + StringBuilder sb = new StringBuilder(); + for (String path : clzPaths + ) { + sb.append(path); + sb.append("\\"); + char[] classname = className.toCharArray(); + for (int i = 0; i < classname.length; i++) { + if (classname[i] == '.') { + sb.append("\\"); + + } else { + sb.append(classname[i]); + } + } + sb.append(".class"); + String classpath = sb.toString(); + File file = new File(classpath); + if (file.exists()) { + return classpath; + } + } + return null; + } +} diff --git a/group12/563253496/week4_jvm1/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group12/563253496/week4_jvm1/src/com/coderising/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..4127673b7e --- /dev/null +++ b/group12/563253496/week4_jvm1/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,92 @@ +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 = "D:\\mygit\\coding2017\\group12\\563253496\\week4_jvm1\\out\\production\\week4_jvm1"; + 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/group12/563253496/week4_jvm1/src/com/coderising/jvm/test/EmployeeV1.java b/group12/563253496/week4_jvm1/src/com/coderising/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..12e3d7efdd --- /dev/null +++ b/group12/563253496/week4_jvm1/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 From 7698e1e4a3eb6eaa79ab22fa9ba54b51cf184468 Mon Sep 17 00:00:00 2001 From: GordenChow <513274874@qq.com> Date: Thu, 30 Mar 2017 11:37:21 +0800 Subject: [PATCH 080/287] =?UTF-8?q?=E7=AC=AC=E5=9B=9B=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 第四周作业提交 --- .../coding/basic/linklist/LRUPageFrame.java | 202 +++++++++++++----- .../basic/linklist/LRUPageFrameTest.java | 23 +- .../jvm/loader/ClassFileLoader.java | 75 ++++--- .../jvm/test/ClassFileloaderTest.java | 15 +- 4 files changed, 228 insertions(+), 87 deletions(-) diff --git a/group27/513274874/data-structure/src/com/coding/basic/linklist/LRUPageFrame.java b/group27/513274874/data-structure/src/com/coding/basic/linklist/LRUPageFrame.java index a4f2c14606..4414a8eb6f 100755 --- a/group27/513274874/data-structure/src/com/coding/basic/linklist/LRUPageFrame.java +++ b/group27/513274874/data-structure/src/com/coding/basic/linklist/LRUPageFrame.java @@ -1,60 +1,158 @@ package com.coding.basic.linklist; +import java.util.Objects; + /** * 用双向链表实现LRU算法 - * @author liuxin * + * @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(); - } - + + private static class Node { + + Node prev; + Node next; + int pageNum; + + Node() { + } + + public boolean hasNext() { + return next != null; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Node)) return false; + Node node = (Node) o; + return Objects.equals(pageNum, node.pageNum); + } + + @Override + public int hashCode() { + return Objects.hash(pageNum); + } + } + + private int capacity;//最大存储个数 + private int cur;//当前存储个数 + + + private Node first;// 链表头 + private Node last;// 链表尾 + + + public LRUPageFrame(int capacity) { + this.capacity = capacity; + } + + /** + * 获取缓存中对象 + * + * @param pageNum + * @return + */ + public void access(int pageNum) { + if(this.cur == 0 ) { + Node node = new Node(); + node.pageNum = pageNum; + addFirst(node); + return; + } + + if (get(pageNum) != null) { + pop(pageNum); + } else { + Node node = new Node(); + node.pageNum = pageNum; + add(node); + } + } + + private void add(Node node) { + addFirst(node); + } + + private Node get(int pageNum) { + Node val = this.first; + while (val.hasNext()) { + if (val.pageNum == pageNum) { + return val; + } + val = val.next; + } + return null; + } + + private void addFirst(Node node) { + if(cur == 0){ + this.first = node; + this.last = node; + }else { + Node oldFirst = this.first; + this.first = node; + node.prev = null; + node.next = oldFirst; + + oldFirst.prev = node; + } + this.cur++; + + if (cur > capacity) { + removeLast(); + } + } + private void removeLast(){ + Node oldLast = this.last; + this.last = oldLast.prev; + oldLast.prev.next = null; + + oldLast = null; + } + + /** + * 将节点变成first + * + * @param pageNum + */ + private void pop(int pageNum) { + Node node = this.get(pageNum); + + //根据node的位置确定如何位移 + if (node.equals(this.first)) { + return; + } else { + Node oldPre = node.prev; + Node oldNext = node.next; + Node oldFirst = this.first; + + this.first = node; + node.prev = null; + node.next = oldFirst; + + oldPre.next = oldNext; + oldNext.prev = oldPre; + + + } + + } + + + 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/group27/513274874/data-structure/src/com/coding/basic/linklist/LRUPageFrameTest.java b/group27/513274874/data-structure/src/com/coding/basic/linklist/LRUPageFrameTest.java index 67cf36067b..374cfafecf 100755 --- a/group27/513274874/data-structure/src/com/coding/basic/linklist/LRUPageFrameTest.java +++ b/group27/513274874/data-structure/src/com/coding/basic/linklist/LRUPageFrameTest.java @@ -8,7 +8,7 @@ public class LRUPageFrameTest { @Test - public void testAccess() { + public void testAccess3() { LRUPageFrame frame = new LRUPageFrame(3); frame.access(7); frame.access(0); @@ -28,4 +28,25 @@ public void testAccess() { Assert.assertEquals("4,0,3", frame.toString()); } + @Test + public void testAccess5() { + LRUPageFrame frame = new LRUPageFrame(5); + frame.access(7); + frame.access(0); + frame.access(1); + Assert.assertEquals("1,0,7", frame.toString()); + frame.access(2); + Assert.assertEquals("2,1,0,7", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1,7", frame.toString()); + frame.access(0); + Assert.assertEquals("0,2,1,7", frame.toString()); + frame.access(3); + Assert.assertEquals("3,0,2,1,7", frame.toString()); + frame.access(0); + Assert.assertEquals("0,3,2,1,7", frame.toString()); + frame.access(4); + Assert.assertEquals("4,0,3,2,1", frame.toString()); + } + } 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 86d4619407..4b5d12b49f 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,34 +1,57 @@ package com.coderising.jvm.loader; +import java.io.*; import java.util.ArrayList; import java.util.List; - public class ClassFileLoader { - private List<String> clzPaths = new ArrayList<String>(); - - public byte[] readBinaryCode(String className) { - - return null; - - - } - - - public void addClassPath(String path) { - - } - - - - public String getClassPath(){ - return null; - } - - - - - -} + private List<String> clzPaths = new ArrayList<String>(); + private static final String CLASS_SUFFIX = ".class"; + private static final String PATH_SEPARATOR = System.getProperty("file.separator"); + + public byte[] readBinaryCode(String className) { + + if (className == null || className.trim().equals("")) { + throw new IllegalArgumentException("package and file name can't be blank!"); + } + //扫描classpath,找到文件即停止扫描,找不到就报错 + String packageName = className.replace(".", PATH_SEPARATOR); + String clazzURL = packageName + CLASS_SUFFIX; + File file = null; + for (String path : clzPaths) { + file = new File(path + clazzURL); + if (file.isDirectory() && file.length() > 0) break; + } + byte[] clazzByte = new byte[0]; + try { + FileInputStream fis = new FileInputStream(file); + DataInputStream data_in = new DataInputStream(fis); + clazzByte = new byte[(int) file.length()]; + data_in.read(clazzByte, 0, (int) file.length()); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + + return clazzByte; + } + + + public void addClassPath(String path) { + if (null == path || path.trim().equals("")) return; + clzPaths.add(path); + } + + + public String getClassPath() { + String clazzPaths = ""; + for (String clazzPath : clzPaths) { + clazzPaths += clazzPath + ";"; + } + return clazzPaths; + } + + } 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 a05534b210..e5d2bd89c5 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,12 +1,11 @@ package com.coderising.jvm.test; +import com.coderising.jvm.loader.ClassFileLoader; import org.junit.After; -import org.junit.Assert; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import com.coderising.jvm.loader.ClassFileLoader; - @@ -14,8 +13,8 @@ public class ClassFileloaderTest { - static String path1 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\mini-jvm\\bin"; - static String path2 = "C:\temp"; + static String path1 = "/Users/guodongchow/Desktop/coding2017/projects/mini-jvm/bin/"; + static String path2 = "/Users/guodongchow/bin"; @@ -36,7 +35,7 @@ public void testClassPath(){ String clzPath = loader.getClassPath(); - Assert.assertEquals(path1+";"+path2,clzPath); + Assert.assertEquals(path1+";"+path2+";",clzPath); } @@ -47,9 +46,9 @@ public void testClassFileLength() { loader.addClassPath(path1); String className = "com.coderising.jvm.test.EmployeeV1"; - + byte[] byteCodes = loader.readBinaryCode(className); - + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 Assert.assertEquals(1056, byteCodes.length); From f60cf2a56843fc80be5eca5b2abffe6dcda599de Mon Sep 17 00:00:00 2001 From: Alvin <conf1102@163.com> Date: Wed, 29 Mar 2017 23:13:28 -0800 Subject: [PATCH 081/287] 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<String> clzPaths = new ArrayList<String>(); 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 e772308943814368d5b7c9fe9a943c872dd5e1ca Mon Sep 17 00:00:00 2001 From: gongxun <gongxun@wesai.com> Date: Thu, 30 Mar 2017 17:12:08 +0800 Subject: [PATCH 082/287] finish half --- group17/785396327/3.12/link/LinkedList.java | 41 ++++++++++++++++++- .../785396327/3.12/link/LinkedListTest.java | 14 +++++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/group17/785396327/3.12/link/LinkedList.java b/group17/785396327/3.12/link/LinkedList.java index f9fc09bfef..3c3b987f41 100644 --- a/group17/785396327/3.12/link/LinkedList.java +++ b/group17/785396327/3.12/link/LinkedList.java @@ -274,7 +274,44 @@ public void removeRange(int min, int max) { * * @param list */ - public LinkedList intersection(LinkedList<T> list) { - return null; + public LinkedList intersection(LinkedList<Integer> list) { + LinkedList<Integer> newList = new LinkedList<Integer>(); + merge(newList, (Node<Integer>) this.head, list.head); + return newList; + } + + private void merge(LinkedList<Integer> newList, Node<Integer> thisHead, Node<Integer> mergeHead) { + if (thisHead == null && mergeHead == null) + return; + if (thisHead == null) { + //无论是否包含,有元素的链表必须指向next + if (!newList.contains(mergeHead.data)) + newList.add(mergeHead.data); + mergeHead = mergeHead.next; + merge(newList, null, mergeHead); + } + if (mergeHead == null) { + if (!newList.contains(thisHead.data)) + newList.add(thisHead.data); + thisHead = thisHead.next; + merge(newList, thisHead, null); + } + //要再进行一次判断是因为递归到最底层return之后,返回上一层时某个链表已经为null了,但是上一层还是会将剩下的执行完 + if (thisHead != null && mergeHead != null) { + if (thisHead.data < mergeHead.data && !newList.contains(thisHead.data)) { + newList.add(thisHead.data); + thisHead = thisHead.next; + merge(newList, thisHead, mergeHead); + } else if (!newList.contains(mergeHead.data)) { + newList.add(mergeHead.data); + mergeHead = mergeHead.next; + merge(newList, thisHead, mergeHead); + } + } + } + + private boolean contains(Integer data) { + int index = this.getIndexByData((T) data); + return index != -1; } } diff --git a/group17/785396327/3.12/link/LinkedListTest.java b/group17/785396327/3.12/link/LinkedListTest.java index 057844b0c8..87edc35e99 100644 --- a/group17/785396327/3.12/link/LinkedListTest.java +++ b/group17/785396327/3.12/link/LinkedListTest.java @@ -128,4 +128,18 @@ public void removeRange() { System.out.println(list); } + @Test + public void intersection() { + LinkedList<Integer> list1 = new LinkedList<Integer>(); + list1.add(2); + list1.add(3); + list1.add(7); + LinkedList<Integer> list2 = new LinkedList<Integer>(); + list2.add(2); + list2.add(3); + list2.add(7); + LinkedList newList = list1.intersection(list2); + System.out.println(newList); + } + } From d710110962d2d84e47d8163ecafc1e9ac59c8c39 Mon Sep 17 00:00:00 2001 From: sulei <sulei0205@foxmail.com> Date: Thu, 30 Mar 2017 18:14:50 +0800 Subject: [PATCH 083/287] fourthHomework --- .../jvm/loader/ClassFileLoader.java | 92 +++++ .../jvm/test/ClassFileloaderTest.java | 91 +++++ .../com/coderising/jvm/test/EmployeeV1.java | 28 ++ .../com/coding/basic/linkedList/Iterator.java | 7 + .../coding/basic/linkedList/LRUPageFrame.java | 141 +++++++ .../basic/linkedList/LRUPageFrameTest.java | 32 ++ .../coding/basic/linkedList/LinkedList.java | 374 ++++++++++++++++++ .../src/com/coding/basic/linkedList/List.java | 9 + 8 files changed, 774 insertions(+) create mode 100644 group04/1020483199/FourthHomeWork/src/com/coderising/jvm/loader/ClassFileLoader.java create mode 100644 group04/1020483199/FourthHomeWork/src/com/coderising/jvm/test/ClassFileloaderTest.java create mode 100644 group04/1020483199/FourthHomeWork/src/com/coderising/jvm/test/EmployeeV1.java create mode 100644 group04/1020483199/FourthHomeWork/src/com/coding/basic/linkedList/Iterator.java create mode 100644 group04/1020483199/FourthHomeWork/src/com/coding/basic/linkedList/LRUPageFrame.java create mode 100644 group04/1020483199/FourthHomeWork/src/com/coding/basic/linkedList/LRUPageFrameTest.java create mode 100644 group04/1020483199/FourthHomeWork/src/com/coding/basic/linkedList/LinkedList.java create mode 100644 group04/1020483199/FourthHomeWork/src/com/coding/basic/linkedList/List.java diff --git a/group04/1020483199/FourthHomeWork/src/com/coderising/jvm/loader/ClassFileLoader.java b/group04/1020483199/FourthHomeWork/src/com/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..ba70c84329 --- /dev/null +++ b/group04/1020483199/FourthHomeWork/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,92 @@ +package com.coderising.jvm.loader; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + + + +public class ClassFileLoader { + + private List<String> clzPaths = new ArrayList<String>(); + + public byte[] readBinaryCode(String className) { + /** + * class文件存储位置 + */ + String location = clzPaths.get(0); + File file = new File(location); + File[] files = file.listFiles(); + InputStream in = null; + byte[] bt = null; + + int size = 0; + for(File fileSon:files){ + /** + * 判断出为class文件时 + */ + if(fileSon.isFile() && fileSon.getName().endsWith("EmployeeV1.class")){ + try { + long length = fileSon.length(); + bt = new byte[(int) length]; + byte[] context = new byte[1024]; + in = new FileInputStream(fileSon); + int tempbyte; + while((tempbyte = in.read(context)) != -1){ + for(int i = 0;i < context.length;i++){ + System.arraycopy(context, 0, bt, size, tempbyte); + } + size = tempbyte; + } + + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + }finally{ + if(in != null){ + try { + in.close(); + } catch (IOException e) { + } + } + } + + } + } + return bt; + } + + + public void addClassPath(String path) { + + clzPaths.add(path); + + } + + + + public String getClassPath(){ + StringBuilder sb = new StringBuilder(); + for(int i = 0;i < clzPaths.size();i++){ + if(i == clzPaths.size() - 1){ + sb.append(clzPaths.get(i)); + break; + } + sb.append(clzPaths.get(i)).append(";"); + + } + return sb.toString(); + } + + + + + +} diff --git a/group04/1020483199/FourthHomeWork/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group04/1020483199/FourthHomeWork/src/com/coderising/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..7c7d1bb15a --- /dev/null +++ b/group04/1020483199/FourthHomeWork/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,91 @@ +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:/myGithub/coding2017/group04/1020483199/FourthHomeWork/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<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/group04/1020483199/FourthHomeWork/src/com/coderising/jvm/test/EmployeeV1.java b/group04/1020483199/FourthHomeWork/src/com/coderising/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..12e3d7efdd --- /dev/null +++ b/group04/1020483199/FourthHomeWork/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/group04/1020483199/FourthHomeWork/src/com/coding/basic/linkedList/Iterator.java b/group04/1020483199/FourthHomeWork/src/com/coding/basic/linkedList/Iterator.java new file mode 100644 index 0000000000..7a7b2aa313 --- /dev/null +++ b/group04/1020483199/FourthHomeWork/src/com/coding/basic/linkedList/Iterator.java @@ -0,0 +1,7 @@ +package com.coding.basic.linkedList; + +public interface Iterator { + public boolean hasNext(); + public Object next(); + +} diff --git a/group04/1020483199/FourthHomeWork/src/com/coding/basic/linkedList/LRUPageFrame.java b/group04/1020483199/FourthHomeWork/src/com/coding/basic/linkedList/LRUPageFrame.java new file mode 100644 index 0000000000..72e222ad69 --- /dev/null +++ b/group04/1020483199/FourthHomeWork/src/com/coding/basic/linkedList/LRUPageFrame.java @@ -0,0 +1,141 @@ +package com.coding.basic.linkedList; + +/** + * 用双向链表实现LRU算法 + * @author liuxin + * + */ +public class LRUPageFrame { + + private static int stateAtHead = 0; + private static int stateAtLast = 1; + private static int stateAtMid = 2; + + 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; + + } + + /** + * 获取缓存中对象 + * + * @param key + * @return + */ + public void access(int pageNum) { + /** + * 空链表 + */ + size ++; + Node newNode = new Node(); + newNode.pageNum = pageNum; + if(size <= capacity){ + if(last == null){ + last= newNode; + first = newNode; + }else{ + Node preHead = first;//记录原来的头节点 + first = newNode; + first.next = preHead; + preHead.prev = first; + } + }else{ + Node currentNode = first; + int judgeNum = currentNode.pageNum; + Node preHead = first;//记录原来的头节点 + Node preLast = last;//记录原来的尾节点 + int state = -1;//记录当前状态 + /** + * 当前插入的值为等于链表头的位置 + */ + + int k = 0; + if(judgeNum == pageNum){ + state = stateAtHead; + }else if(preLast.pageNum == pageNum){ + state = stateAtLast; + } + while(currentNode != null && k < capacity - 1){ + k++; + currentNode = currentNode.next; + judgeNum = currentNode.pageNum; + if(judgeNum == pageNum && judgeNum != preLast.pageNum){ + state = stateAtMid; + break; + } + } + + switch (state) { + case -1: + first = newNode; + last = preLast.prev; + first.next = preHead; + first.prev = null; + preHead.next = last; + preHead.prev = first; + last.next = null; + break; + case 0: + + break; + + case 1: + last = preLast.prev; + last.next = null;//原来尾节点的上一个节点变成了尾节点 + first = newNode; + first.prev = null; + first.next = preHead; + break; + case 2: + first = newNode; + first.next = preHead; + first.prev = null; + preHead.next = last; + preHead.prev = first; + last.prev = preHead; + break; + } + + } + + + + + } + + + + 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/group04/1020483199/FourthHomeWork/src/com/coding/basic/linkedList/LRUPageFrameTest.java b/group04/1020483199/FourthHomeWork/src/com/coding/basic/linkedList/LRUPageFrameTest.java new file mode 100644 index 0000000000..f2ffcabf16 --- /dev/null +++ b/group04/1020483199/FourthHomeWork/src/com/coding/basic/linkedList/LRUPageFrameTest.java @@ -0,0 +1,32 @@ +package com.coding.basic.linkedList; + +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/group04/1020483199/FourthHomeWork/src/com/coding/basic/linkedList/LinkedList.java b/group04/1020483199/FourthHomeWork/src/com/coding/basic/linkedList/LinkedList.java new file mode 100644 index 0000000000..52ecedc5be --- /dev/null +++ b/group04/1020483199/FourthHomeWork/src/com/coding/basic/linkedList/LinkedList.java @@ -0,0 +1,374 @@ +package com.coding.basic.linkedList; + +import java.util.Stack; + +public class LinkedList implements List { + private int size; + + private Node head; + + public LinkedList(){ + size = 0; + + head = null; + } + + public void add(Object o){ + Node nd = new Node(o); + if(head == null){ + head = nd; + }else{ + Node p = head; + while(p.next != null){ + p = p.next; + } + p.next = nd; + } + size ++; + + } + //3 > 2 > 1 > 5 > 4 > 5改变之前 + //0 1 2 3 4 5index + //3 > 2 > 1 > x > 5 > 4 > 5插入之后 + public void add(int index , Object o){ + if(head != null){ + int k = 0; + Node p = head; + while(k < index - 1 && p.next != null){ + k++; + p = p.next;//当前p为要插入位置的前一个节点 + } + + if(p != null){ + Node nd = new Node(o); + nd.next = p.next; + p.next = nd; + } + + size++; + + } + } + public Object get(int index){ + if(index < 0 || index >= size){ + throw new IndexOutOfBoundsException(); + } + Node p = head; + int k = 0; + while(k < index && p.next !=null){ + k++; + p = p.next; + } + return p.data; + } + //3 > 2 > 1 > 5 > 4 > 5改变之前 + //0 1 2 3 4 5index + //3 > 2 > 1 > 4 > 5插入之后 + public Object remove(int index){ + if(index < 0 || index >= size){ + throw new IndexOutOfBoundsException(); + } + if(head == null){ + return null; + } + if(index == 0){ + head = head.next; + size--; + return head.data; + }else{ + if(head != null){ + int k = 0; + Node p = head; + while(k < index - 1 && p != null){ + k++; + p = p.next; + } + Node pn = p.next; + if(pn != null){ + p.next = pn.next; + size--; + return pn.data; + } + + } + } + return null; + } + + public int size(){ + + return size; + } + + public void addFirst(Object o){ + if(head != null){ + Node nd = new Node(o); + Node first = head; + head = nd; + first = nd.next; + } + } + public void addLast(Object o){ + if(head != null){ + int k = 0; + Node p = head; + while(p.next != null && k < size - 1){ + p = p.next; + k++; + } + Node newNode = new Node(o); + p.next = newNode; + } + } + public Object removeFirst(){ + Node node = head; + if(head != null){ + head = head.next; + } + return node.data; + } + public Object removeLast(){ + Node p = head; + int k = 0; + while(p.next != null && k < size - 2){ + k++; + p = p.next; + } + + p.next = null; + return p.next; + } + public Iterator iterator(){ + return null; + } + + + private static class Node{ + Object data; + Node next; + + private Node(Object o){ + this.data = o; + this.next = null; + } + } + + /** + * 把该链表逆置 + * head head + * 例如链表为 3->7->10 , 逆置后变为 10->7->3 + */ + public void reverse(){ + /** + * 长度超过1的单链表需要逆转 + */ + if(head == null || head.next == null){ + return; + } + Stack<Node> st = new Stack<Node>(); + Node currentNode = head; + while(currentNode != null){ + st.push(currentNode); + Node nextNode = currentNode.next; + currentNode.next = null;//断开连接 + currentNode = nextNode; + } + + head = (Node) st.pop(); + currentNode = head; + while(!st.isEmpty()){ + Node nextNode = (Node) st.pop(); + currentNode.next = nextNode; + currentNode = nextNode; + } + } + + + /** + * 删除一个单链表的前半部分 + * 例如:list = 2->5->7->8 , 删除以后的值为 7->8 + * 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10 + + */ + public void removeFirstHalf(){ + int num = size / 2; + for(int i = 0; i < num; i++){ + removeFirst(); + } + } + + /** + * 从第i个元素开始,删除length个元素 ,注意i从0开始 + * @param i + * @param length + */ + public void remove(int i, int length){ + if(i < 0 || i >= size){ + throw new IndexOutOfBoundsException(); + } + int len = size - i >= length ? length : size - i; + int k = 0; + while(k < len){ + remove(i); + k++; + } + + } + /** + * 假定当前链表和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[] newList = new int[list.size()]; + for(int i = 0;i < list.size(); i++){ + newList[i] = Integer.parseInt(this.get(Integer.parseInt(list.get(i).toString())).toString()); + } + return newList; + + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 从当前链表中中删除在listB中出现的元素 + + * @param list + */ + + public void subtract(LinkedList list){ + for(int j = 0;j < list.size();j++){ + this.remove(list.get(j)); + } + + } + + /** + * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) + */ + public void removeDuplicateValues(){ + if(head == null){ + throw new RuntimeException("LinkedList is null"); + + } + Node currentNode = head; + Node preNode = head; + while(currentNode.next != null){ + currentNode = currentNode.next; + Object data = preNode.data; + while(currentNode.data == data){ + if(currentNode.next == null){ + preNode.next = null; + break; + } + preNode.next = currentNode.next; + size--; + currentNode = currentNode.next; + if(currentNode == null){ + break; + } + } + preNode = preNode.next; + } + } + /** + * 传入删除数据节点 + */ + public void remove(Object obj){ + if(head == null){ + throw new RuntimeException("linkedlist is nuull"); + + } + if(head.data.equals(obj)){ + head = head.next; + size--; + }else{ + Node pre = head; + Node currentNode = head.next; + while(currentNode != null){ + if(currentNode.data.equals(obj)){ + pre.next = currentNode.next; + size--; + } + pre = pre.next; + currentNode = currentNode.next; + } + } + } + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 试写一高效的算法,删除表中所有值大于min且小于max的元素(若表中存在这样的元素) + * @param min + * @param max + */ + public void removeRange(int min, int max){ + Node node = head; + int start = -1; + int end = -1; + int i = 0; + while(node != null){ + if((Integer)node.data <= min){ + start = i; + } + if((Integer)node.data >= max){ + end = i; + break; + } + node = node.next; + i++; + } + if(start == -1){ + start = 0; + } + if(end == -1){ + end = size; + } + this.remove(start+1, end-start-1); + } + + /** + * 假设当前链表和参数list指定的链表均以元素依值递增有序排列(同一表中的元素值各不相同) + * 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列 + * @param list + */ + public LinkedList intersection(LinkedList list){ + if(list == null){ + return null; + } + + LinkedList newList = new LinkedList(); + int fi = 0; + int se = 0; + while(fi < this.size && se < list.size()){ + int val1 = (Integer) this.get(fi); + int val2 = (Integer) list.get(se); + if(val1 == val2){ + newList.add(val1); + fi++; + se++; + }else if(val1 < val2){ + fi++; + }else{ + se++; + } + + } + return newList; + } + + public static void main(String[] args) { + LinkedList linkedList = new LinkedList(); + linkedList.add(11); + linkedList.add(22); + linkedList.add(33); + linkedList.add(44); + linkedList.add(55); + linkedList.reverse(); + for(int i = 0; i < linkedList.size; i++){ + System.out.println(linkedList.get(i)); + } + } +} diff --git a/group04/1020483199/FourthHomeWork/src/com/coding/basic/linkedList/List.java b/group04/1020483199/FourthHomeWork/src/com/coding/basic/linkedList/List.java new file mode 100644 index 0000000000..55ff205b5d --- /dev/null +++ b/group04/1020483199/FourthHomeWork/src/com/coding/basic/linkedList/List.java @@ -0,0 +1,9 @@ +package com.coding.basic.linkedList; + +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(); +} From 7fcbdd05319efceba4ac424aa2df3a39e870ac7f Mon Sep 17 00:00:00 2001 From: ZhaoHongxin <zhaohongxin621@126.com> Date: Thu, 30 Mar 2017 20:15:41 +0800 Subject: [PATCH 084/287] =?UTF-8?q?=E5=AE=8C=E6=88=90=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=E9=AD=94=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jvm/loader/ClassFileLoader.java | 80 ++++++++++++++----- .../jvm/test/ClassFileloaderTest.java | 17 ++-- 2 files changed, 70 insertions(+), 27 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 67051536b5..86f1100e6c 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 @@ -1,46 +1,88 @@ 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.io.InputStream; import java.util.ArrayList; import java.util.List; - - public class ClassFileLoader { private List<String> clzPaths = new ArrayList<String>(); - - public byte[] readBinaryCode(String className) { + + public byte[] readBinaryCode(String className) throws ClassNotFoundException, IOException { + if (clzPaths.size() == 0) { + return new byte[0]; + } + String actualPath = getActualPath(className); + + File f = new File(actualPath); - return null; + if (!f.exists()) { + throw new ClassNotFoundException(actualPath); + } + + ByteArrayOutputStream bos = new ByteArrayOutputStream((int) f.length()); + BufferedInputStream is = null; + try { + is = new BufferedInputStream(new FileInputStream(f)); + + byte[] buffer = new byte[1024]; + int len = 0; + + while (-1 != (len = is.read(buffer))) { + bos.write(buffer, 0, len); + } + + return bos.toByteArray(); + + } catch (IOException e) { + e.printStackTrace(); + throw e; + } finally { + is.close(); + bos.close(); + } } - - - public void addClassPath(String path) { + + 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) { return; } - + clzPaths.add(path); - + } - - public String getClassPath(){ - + + public String getClassPath() { + if (clzPaths.size() == 0) { return ""; } - + StringBuffer buffer = new StringBuffer(""); - + for (String str : clzPaths) { buffer.append(str); buffer.append(";"); } - - return buffer.substring(0, buffer.length()-1);//去除最后一个分号 - - } + return buffer.substring(0, buffer.length() - 1);// 去除最后一个分号 + + } } 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 d7135ca960..b15eb7e99d 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 @@ -1,5 +1,7 @@ package com.coderising.jvm.test; +import java.io.IOException; + import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -41,7 +43,7 @@ public void testClassPath(){ } @Test - public void testClassFileLength() { + public void testClassFileLength() throws ClassNotFoundException, IOException { ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); @@ -57,7 +59,7 @@ public void testClassFileLength() { @Test - public void testMagicNumber(){ + public void testMagicNumber() throws ClassNotFoundException, IOException{ ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); @@ -65,18 +67,17 @@ public void testMagicNumber(){ 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); } - - - - - + /** + * 二进制数组转换成16进制 + * @param codes + * @return + */ private String byteToHexString(byte[] codes ){ StringBuffer buffer = new StringBuffer(); for(int i=0;i<codes.length;i++){ 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 085/287] =?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<contentLen ;i++){ + file.write(0); + } + + file.close(); + } public void execute(){ // 在这里实现你的代码, 注意: 需要用多线程实现下载 // 这个类依赖于其他几个接口, 你需要写这几个接口的实现代码 @@ -54,14 +63,19 @@ public void execute(){ conn = cm.open(this.url); int length = conn.getContentLength(); + File desc=new File(OUT_FILE_NAME); + if(desc.exists()){ + desc.delete(); + } + String filename=url.substring(url.lastIndexOf("/")); String descFilePath="E://testfile//"+filename; + createPlaceHolderFile(OUT_FILE_NAME, length); CyclicBarrier barrier=new CyclicBarrier(THREAD_NUM,new Runnable() { @Override public void run() { listener.notifyFinished(); - } }); /*int every=length/3; @@ -91,20 +105,21 @@ public void run() { // 最后一个线程下载指定numPerThred+left个字节 start=(int) (i * numPerThred); end=(int) ((i + 1) * numPerThred - + left); + + left-1); } else { // 每个线程负责下载一定的numPerThred个字节 start=(int) (i * numPerThred); - end=(int) ((i + 1) * numPerThred); + end=(int) ((i + 1) * numPerThred)-1; } new DownloadThread(conn, start, end,OUT_FILE_NAME,barrier).start(); + //Thread.sleep(1000); } } catch (Exception e) { e.printStackTrace(); }finally{ - + conn.close(); } diff --git a/group14/1091149131/2017JavaPro/src/com/m0312/download/FileDownloaderTest.java b/group14/1091149131/2017JavaPro/src/com/m0312/download/FileDownloaderTest.java index 3c3957f933..311c20e9d2 100644 --- a/group14/1091149131/2017JavaPro/src/com/m0312/download/FileDownloaderTest.java +++ b/group14/1091149131/2017JavaPro/src/com/m0312/download/FileDownloaderTest.java @@ -54,7 +54,13 @@ public void notifyFinished() { } } System.out.println("下载完成!"); - + /** + * 网络资源的大小4812 + 开始读[0,1603] + 开始读[1604,3207] + 开始读[3208,4811] + 下载完成! + */ } diff --git a/group14/1091149131/2017JavaPro/src/com/m0312/download/LinkedListTest.java b/group14/1091149131/2017JavaPro/src/com/m0312/download/LinkedListTest.java index b9796b2321..aa142b6163 100644 --- a/group14/1091149131/2017JavaPro/src/com/m0312/download/LinkedListTest.java +++ b/group14/1091149131/2017JavaPro/src/com/m0312/download/LinkedListTest.java @@ -110,7 +110,7 @@ public void testSubtract() { @Test public void testRemoveDuplicateValues() { - list.add(0); + list.add(3); list.add(1); list.add(22); list.add(22); diff --git a/group14/1091149131/2017JavaPro/src/com/m0312/download/impl/ConnectionImpl.java b/group14/1091149131/2017JavaPro/src/com/m0312/download/impl/ConnectionImpl.java index a3228c80b9..c8e240d355 100644 --- a/group14/1091149131/2017JavaPro/src/com/m0312/download/impl/ConnectionImpl.java +++ b/group14/1091149131/2017JavaPro/src/com/m0312/download/impl/ConnectionImpl.java @@ -2,20 +2,84 @@ import java.io.IOException; import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; import java.net.URLConnection; import com.m0312.download.api.Connection; public class ConnectionImpl implements Connection{ URLConnection urlCon; + URL url; + static final int BUFFER_SIZE = 1024; + ConnectionImpl(String _url){ + try { + url=new URL(_url); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + } @Override public byte[] read(int startPos, int endPos) throws IOException { - byte[] buffer=new byte[endPos-startPos]; - InputStream is=urlCon.getInputStream(); - is.skip(startPos); - is.read(buffer, 0, endPos-startPos); + //只能写出第一部分 + byte[] buffer=new byte[endPos-startPos+1]; + HttpURLConnection urlCon2 = (HttpURLConnection)url.openConnection(); + urlCon2.setRequestProperty("Range", "bytes=" + startPos + "-" + + endPos); + InputStream is=urlCon2.getInputStream(); + //is.skip(startPos); + is.read(buffer, 0, endPos-startPos+1);//因为没有+1,一直是只有三分之一部分 is.close(); return buffer; + + /*HttpURLConnection httpConn = (HttpURLConnection)url.openConnection(); + + httpConn.setRequestProperty("Range", "bytes=" + startPos + "-" + + endPos); + + InputStream is = httpConn.getInputStream(); + + //is.skip(startPos); + + 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); + System.out.println("is read length: "+len); + System.out.println("baos.size: "+baos.size()); + } + if(baos.size() > 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<N;i++) + new Writer(barrier).start(); + } + static class Writer extends Thread{ + private CyclicBarrier cyclicBarrier; + public Writer(CyclicBarrier cyclicBarrier) { + this.cyclicBarrier = cyclicBarrier; + } + + @Override + public void run() { + System.out.println("线程"+Thread.currentThread().getName()+"正在写入数据..."); + try { + Thread.sleep(5000); //以睡眠来模拟写入数据操作 + System.out.println("线程"+Thread.currentThread().getName()+"写入数据完毕,等待其他线程写入完毕"); + cyclicBarrier.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + }catch(BrokenBarrierException e){ + e.printStackTrace(); + } + System.out.println("所有线程写入完毕,继续处理其他任务..."); + } + } +} \ No newline at end of file diff --git a/group14/1091149131/2017JavaPro/src/com/test/TestThread2.java b/group14/1091149131/2017JavaPro/src/com/test/TestThread2.java new file mode 100644 index 0000000000..996260fca4 --- /dev/null +++ b/group14/1091149131/2017JavaPro/src/com/test/TestThread2.java @@ -0,0 +1,65 @@ +package com.test; + +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +/** + * 在TestThread的基础上,为CyclicBarrier 加入runnable + * 在写完前,可以做其他事 + * @author Joy + */ +public class TestThread2 { + public static void main(String[] args) { + int N = 4; + CyclicBarrier barrier = new CyclicBarrier(N,new Runnable() { + @Override + public void run() { + System.out.println("当前线程"+Thread.currentThread().getName()); + } + }); + + for(int i=0;i<N;i++) + new Writer(barrier).start(); + /*for(int i=0;i<N;i++) { + if(i<N-1) + new Writer(barrier).start(); + else { + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + new Writer(barrier).start(); + } + }*/ + + } + static class Writer extends Thread{ + private CyclicBarrier cyclicBarrier; + public Writer(CyclicBarrier cyclicBarrier) { + this.cyclicBarrier = cyclicBarrier; + } + + @Override + public void run() { + System.out.println("线程"+Thread.currentThread().getName()+"正在写入数据..."); + try { + Thread.sleep(5000); //以睡眠来模拟写入数据操作 + System.out.println("线程"+Thread.currentThread().getName()+"写入数据完毕,等待其他线程写入完毕"); + cyclicBarrier.await(); + System.out.println("线程"+Thread.currentThread().getName()+"在await后面"); + //cyclicBarrier.await(2000, TimeUnit.MILLISECONDS);//await指定时间,故意让其中一个线程拖延时间 + + } catch (InterruptedException e) { + e.printStackTrace(); + }catch(BrokenBarrierException e){ + e.printStackTrace(); + } /*catch (TimeoutException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + }*/ + System.out.println("所有线程写入完毕,继续处理其他任务..."); + } + } +} diff --git a/group14/1091149131/2017JavaPro/src/com/test/downfile/DownThread.java b/group14/1091149131/2017JavaPro/src/com/test/downfile/DownThread.java new file mode 100644 index 0000000000..28bdb23aea --- /dev/null +++ b/group14/1091149131/2017JavaPro/src/com/test/downfile/DownThread.java @@ -0,0 +1,71 @@ +package com.test.downfile; + +import java.io.InputStream; +import java.io.RandomAccessFile; + +public class DownThread extends Thread { + + // 定义字节数组(取水的竹筒)的长度 + private final int BUFF_LEN = 32; + + // 定义下载的起始点 + private long start; + + // 定义下载的结束点 + private long end; + + // 下载资源对应的输入流 + private InputStream is; + + // 将下载到的字节输出到raf中 + private RandomAccessFile raf; + + + // 构造器,传入输入流,输出流和下载起始点、结束点 + public DownThread(long start, long end, InputStream is, RandomAccessFile raf) { + // 输出该线程负责下载的字节位置 + System.out.println(start + "---->" + 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 02df22aa6c24a40da197d6db85afa180cfd7f5e5 Mon Sep 17 00:00:00 2001 From: GUK0 <1685605435@qq.com> Date: Fri, 31 Mar 2017 11:22:52 +0800 Subject: [PATCH 086/287] download finish afterall MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit now can download any kinds of file,next will support stop/continue。 --- group12/247565311/week3/DownloadThread.java | 38 +++++++----- group12/247565311/week3/FileDownloader.java | 29 +++++----- .../247565311/week3/FileDownloaderTest.java | 19 +++--- .../247565311/week3/impl/ConnectionImpl.java | 58 +++++++++++++------ .../week3/impl/ConnectionManagerImpl.java | 12 +--- 5 files changed, 92 insertions(+), 64 deletions(-) diff --git a/group12/247565311/week3/DownloadThread.java b/group12/247565311/week3/DownloadThread.java index 3271ba2e99..2670bef00b 100644 --- a/group12/247565311/week3/DownloadThread.java +++ b/group12/247565311/week3/DownloadThread.java @@ -1,24 +1,31 @@ package week3; +import java.io.FileNotFoundException; import java.io.IOException; +import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; import week3.api.Connection; public class DownloadThread extends Thread{ Connection conn; + CyclicBarrier barrier; int startPos; int endPos; String path = ""; - public DownloadThread( Connection conn, int startPos, int endPos,String filepath){ + int step = 1024*200; // ÿ200kдһļ + public DownloadThread(CyclicBarrier _barrier, Connection conn, int startPos, int endPos,String filepath){ this.conn = conn; this.startPos = startPos; this.endPos = endPos; this.path = filepath; + this.barrier = _barrier; } public void run(){ // ȡصֽ飬дļעһ̳߳ @@ -27,27 +34,28 @@ public void run(){ // connectȡֽ飬ûֽˣͱʾⲿ // filepathдļ if(conn == null) return; - ByteBuffer buffer = ByteBuffer.allocate(endPos-startPos); - Path filepath = Paths.get(path); - - if(filepath == null) return; int curEndPos = startPos; - // while(curEndPos<endPos){ + while(curEndPos<endPos){ startPos = curEndPos; - curEndPos += 4096; - //if (curEndPos > endPos) + curEndPos += step; + if (curEndPos > endPos) curEndPos = endPos; try { byte[] data = conn.read(startPos, curEndPos); - FileChannel channel = FileChannel.open(filepath,StandardOpenOption.WRITE); - // System.out.println("startPos"+startPos + ", length:"+data.length); - buffer.put(data); - channel.write(buffer); + RandomAccessFile files = new RandomAccessFile(path,"rw"); + files.seek(startPos); + files.write(data); + files.close(); + System.out.println("startPos"+startPos + ", length:"+data.length); } catch (IOException e) { - //e.printStackTrace(); - System.out.println("дļ"); + e.printStackTrace(); } - // } + } conn.close(); + try { + barrier.await(); + } catch (InterruptedException | BrokenBarrierException e) { + e.printStackTrace(); + } } } diff --git a/group12/247565311/week3/FileDownloader.java b/group12/247565311/week3/FileDownloader.java index c5ab5fb5d0..1a426c3682 100644 --- a/group12/247565311/week3/FileDownloader.java +++ b/group12/247565311/week3/FileDownloader.java @@ -1,6 +1,5 @@ package week3; - -import java.io.FileNotFoundException; +import java.util.concurrent.CyclicBarrier; import java.io.IOException; import java.io.RandomAccessFile; @@ -11,6 +10,7 @@ import week3.impl.ConnectionManagerImpl; public class FileDownloader { + private int MaxThreadNum = 4; private String url = null,path=null; DownloadListener listener = null; private ConnectionManager cm = new ConnectionManagerImpl(); @@ -20,7 +20,7 @@ public FileDownloader(String weburl,String localpath) { this.path = localpath; } - public void execute(){ + public void execute() throws InterruptedException{ // 在这里实现你的代码, 注意: 需要用多线程实现下载 // 这个类依赖于其他几个接口, 你需要写这几个接口的实现代码 // (1) ConnectionManager , 可以打开一个连接,通过Connection可以读取其中的一段(用startPos, endPos来指定) @@ -35,6 +35,11 @@ public void execute(){ // 下面的代码是示例代码, 也就是说只有一个线程, 你需要改造成多线程的。 Connection conn = null; + CyclicBarrier barr= new CyclicBarrier(MaxThreadNum,new Runnable(){ + public void run(){ + listener.notifyFinished(); + } + }); try { conn = cm.open(this.url); int length = conn.getContentLength(); @@ -43,18 +48,13 @@ public void execute(){ tarfile.setLength(length); tarfile.close(); Thread[] threads = new Thread[4]; - threads[0] = new DownloadThread(cm.open(this.url),0,length/4,path); - threads[1] = new DownloadThread(cm.open(this.url),length/4,length/2,path); - threads[2] = new DownloadThread(cm.open(this.url),length/2,3*length/4,path); - threads[3] = new DownloadThread(cm.open(this.url),3*length/4,length,path); + threads[0] = new DownloadThread(barr,cm.open(this.url),0,length/4,path); + threads[1] = new DownloadThread(barr,cm.open(this.url),length/4,length/2,path); + threads[2] = new DownloadThread(barr,cm.open(this.url),length/2,3*length/4,path); + threads[3] = new DownloadThread(barr,cm.open(this.url),3*length/4,length,path); for(int i=0;i<4;i++) threads[i].start(); - threads[0].join(); - threads[1].join(); - threads[2].join(); - threads[3].join(); - this.getListener().notifyFinished(); - } catch (ConnectionException | IOException | InterruptedException e) { + } catch (ConnectionException | IOException e) { e.printStackTrace(); }finally{ if(conn != null){ @@ -71,4 +71,7 @@ public void setConnectionManager(ConnectionManager ucm){ public DownloadListener getListener(){ return this.listener; } + public double getDownPercent(){ + return 0.0; + } } diff --git a/group12/247565311/week3/FileDownloaderTest.java b/group12/247565311/week3/FileDownloaderTest.java index 96893b71e9..3c729218d3 100644 --- a/group12/247565311/week3/FileDownloaderTest.java +++ b/group12/247565311/week3/FileDownloaderTest.java @@ -19,8 +19,8 @@ public void tearDown() throws Exception { @Test public void testDownload() { - String url = "https://edmullen.net/test/rc.jpg"; - String path = "D:\\hellp.jpg"; + String url = "http://music.163.com/api/pc/download/latest"; + String path = "D:\\hellp.exe"; FileDownloader downloader = new FileDownloader(url,path); ConnectionManager cm = new ConnectionManagerImpl(); downloader.setConnectionManager(cm); @@ -30,16 +30,21 @@ public void notifyFinished() { downloadFinished = true; } }); - downloader.execute(); - // 等待多线程下载程序执行完毕 + double time = 0; + try { + downloader.execute(); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } while (!downloadFinished) { try { - System.out.println("还没有下载完成,休眠五秒"); - Thread.sleep(5000);//休眠5秒 + Thread.sleep(100);//休眠0.1秒 + + time += 1; } catch (InterruptedException e) { e.printStackTrace(); } } - System.out.println("下载完成!"); + System.out.println("下载完成!耗时:"+time/10.0+" 秒。"); } } diff --git a/group12/247565311/week3/impl/ConnectionImpl.java b/group12/247565311/week3/impl/ConnectionImpl.java index bdd28aa4ec..7173caf56d 100644 --- a/group12/247565311/week3/impl/ConnectionImpl.java +++ b/group12/247565311/week3/impl/ConnectionImpl.java @@ -1,43 +1,65 @@ package week3.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.net.URLConnection; +import java.util.Arrays; import week3.api.Connection; public class ConnectionImpl implements Connection{ - HttpURLConnection conn = null; + URL url = null; + public ConnectionImpl(String str){ + try { + url = new URL(str); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + } // Ҫִأȡֽ // ฺ򿪡ر @Override - public byte[] read(int startPos, int endPos) throws IOException { - if(conn == null || startPos>=endPos) return null; + public byte[] read(int startPos, int endPos) { + HttpURLConnection conn = null; byte[]res = null; - conn.setRequestProperty("Range","bytes="+startPos+"-"+endPos); - int responcode = conn.getResponseCode(); - if(200 < responcode && responcode < 300){ - InputStream input = conn.getInputStream(); - res = new byte[endPos-startPos]; - input.read(res); - input.close(); + try { + conn = (HttpURLConnection) url.openConnection(); + conn.setRequestProperty("Range","bytes="+startPos+"-"+endPos); + int responcode = conn.getResponseCode(); + if(200 < responcode && responcode < 300){ + InputStream input = conn.getInputStream(); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + res = new byte[2048]; + while(output.size()<endPos - startPos){ + int len = input.read(res); + if(len>0)output.write(res,0,len); + else break; + } + return Arrays.copyOf(output.toByteArray(), endPos-startPos); + } + } catch (IOException e) { + e.printStackTrace(); } - conn.disconnect(); + if(conn!=null) conn.disconnect(); return res; } @Override public int getContentLength() { - if(conn == null) return 0; - return conn.getContentLength(); + try{ + URLConnection con = url.openConnection(); + return con.getContentLength(); + }catch(Exception e){ + e.printStackTrace(); + } + return -1; } @Override public void close() { - if(conn == null) return; - conn.disconnect(); - } - public void setConn(HttpURLConnection urlconn) { - conn = urlconn; } } diff --git a/group12/247565311/week3/impl/ConnectionManagerImpl.java b/group12/247565311/week3/impl/ConnectionManagerImpl.java index 68e458b1ca..b4a7cf381f 100644 --- a/group12/247565311/week3/impl/ConnectionManagerImpl.java +++ b/group12/247565311/week3/impl/ConnectionManagerImpl.java @@ -13,16 +13,6 @@ public class ConnectionManagerImpl implements ConnectionManager { ConnectionImpl conImpl = null; @Override public Connection open(String url) throws ConnectionException { - try { - URL urllink = new URL(url); - conImpl = new ConnectionImpl(); - HttpURLConnection httpconn = (HttpURLConnection)urllink.openConnection(); - httpconn.setConnectTimeout(5*1000); - httpconn.setRequestProperty("User-Agent","Mozilla/4.0 (compatiable; MSIE 5.0; Windows NT; DigExt)"); // ģ - conImpl.setConn(httpconn); - } catch (Exception e) { - throw (ConnectionException)e; - } - return conImpl; + return new ConnectionImpl(url); } } From 66419dab30370ce76e813d9656ffb63558715e0b Mon Sep 17 00:00:00 2001 From: Alvin <conf1102@163.com> Date: Fri, 31 Mar 2017 00:42:20 -0800 Subject: [PATCH 087/287] 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 5a761d65678db024db5e9da555365c68437fe008 Mon Sep 17 00:00:00 2001 From: zhanglifeng <284422826@qq.com> Date: Fri, 31 Mar 2017 17:30:45 +0800 Subject: [PATCH 088/287] =?UTF-8?q?JVM=E7=AC=AC=E4=B8=80=E5=91=A8=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jvm/loader/ClassFileLoader.java | 46 +++++++ .../jvm/test/ClassFileloaderTest.java | 74 ++++++++++++ .../com/coderising/jvm/test/EmployeeV1.java | 28 +++++ .../src/com/coding2017/basic/Queue.java | 2 + .../basic/{ => array}/ArrayList.java | 0 .../basic}/array/ArrayUtil.java | 0 .../basic}/array/ArrayUtilTest.java | 0 .../basic/linklist/LRUPageFrame.java | 113 ++++++++++++++++++ .../basic/linklist/LRUPageFrameTest.java | 31 +++++ .../basic/{ => linklist}/LinkedList.java | 5 +- 10 files changed, 298 insertions(+), 1 deletion(-) create mode 100644 group05/284422826/src/com/coderising/jvm/loader/ClassFileLoader.java create mode 100644 group05/284422826/src/com/coderising/jvm/test/ClassFileloaderTest.java create mode 100644 group05/284422826/src/com/coderising/jvm/test/EmployeeV1.java rename group05/284422826/src/com/coding2017/basic/{ => array}/ArrayList.java (100%) rename group05/284422826/src/com/{coderising => coding2017/basic}/array/ArrayUtil.java (100%) rename group05/284422826/src/com/{coderising => coding2017/basic}/array/ArrayUtilTest.java (100%) create mode 100644 group05/284422826/src/com/coding2017/basic/linklist/LRUPageFrame.java create mode 100644 group05/284422826/src/com/coding2017/basic/linklist/LRUPageFrameTest.java rename group05/284422826/src/com/coding2017/basic/{ => linklist}/LinkedList.java (98%) diff --git a/group05/284422826/src/com/coderising/jvm/loader/ClassFileLoader.java b/group05/284422826/src/com/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..a15237f0cb --- /dev/null +++ b/group05/284422826/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,46 @@ +package com.coderising.jvm.loader; + +import java.io.BufferedInputStream; +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<String> clzPaths = new ArrayList<>(); + + public byte[] readBinaryCode(String className) { + String name = this.getClassPath() + File.separatorChar + className.replace('.', File.separatorChar) + ".class"; + File file = new File(name); + byte[] bytes = new byte[(int)file.length()]; + try { + BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); + while (bis.read(bytes) != -1) { + System.out.println(Arrays.toString(bytes)); + } + } catch (IOException e) { + e.printStackTrace(); + } + return bytes; + } + + + public void addClassPath(String path) { + clzPaths.add(path); + } + + + public String getClassPath() { + StringBuilder path = new StringBuilder(); + for (String str : clzPaths) { + path.append(str).append(";"); + } + return path.substring(0, path.length() - 1); + } + + +} diff --git a/group05/284422826/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group05/284422826/src/com/coderising/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..ca669de57a --- /dev/null +++ b/group05/284422826/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 = "D:\\git\\coding2017\\group05\\284422826\\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 ){ + StringBuilder buffer = new StringBuilder(); + for (byte b : codes) { + 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/group05/284422826/src/com/coderising/jvm/test/EmployeeV1.java b/group05/284422826/src/com/coderising/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..12e3d7efdd --- /dev/null +++ b/group05/284422826/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/group05/284422826/src/com/coding2017/basic/Queue.java b/group05/284422826/src/com/coding2017/basic/Queue.java index 57d63f43bf..0148cc7c38 100644 --- a/group05/284422826/src/com/coding2017/basic/Queue.java +++ b/group05/284422826/src/com/coding2017/basic/Queue.java @@ -1,5 +1,7 @@ package com.coding2017.basic; +import com.coding2017.basic.linklist.LinkedList; + import java.util.EmptyStackException; public class Queue { diff --git a/group05/284422826/src/com/coding2017/basic/ArrayList.java b/group05/284422826/src/com/coding2017/basic/array/ArrayList.java similarity index 100% rename from group05/284422826/src/com/coding2017/basic/ArrayList.java rename to group05/284422826/src/com/coding2017/basic/array/ArrayList.java diff --git a/group05/284422826/src/com/coderising/array/ArrayUtil.java b/group05/284422826/src/com/coding2017/basic/array/ArrayUtil.java similarity index 100% rename from group05/284422826/src/com/coderising/array/ArrayUtil.java rename to group05/284422826/src/com/coding2017/basic/array/ArrayUtil.java diff --git a/group05/284422826/src/com/coderising/array/ArrayUtilTest.java b/group05/284422826/src/com/coding2017/basic/array/ArrayUtilTest.java similarity index 100% rename from group05/284422826/src/com/coderising/array/ArrayUtilTest.java rename to group05/284422826/src/com/coding2017/basic/array/ArrayUtilTest.java diff --git a/group05/284422826/src/com/coding2017/basic/linklist/LRUPageFrame.java b/group05/284422826/src/com/coding2017/basic/linklist/LRUPageFrame.java new file mode 100644 index 0000000000..d43bbc13d7 --- /dev/null +++ b/group05/284422826/src/com/coding2017/basic/linklist/LRUPageFrame.java @@ -0,0 +1,113 @@ +package com.coding2017.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;// 链表尾 + + private int size = 0; + + public LRUPageFrame(int capacity) { + this.capacity = capacity; + } + + /** + * 获取缓存中对象 + * + * @param pageNum + * @return + */ + public void access(int pageNum) { + if (size < capacity) { + Node node = new Node(); + node.pageNum = pageNum; + if (first == null && last == null) { + node.prev = null; + node.next = null; + first = node; + last = node; + } else { + if (last.prev == null) { + last.prev = node; + node.next = last; + } else { + assert first != null; + first.prev = node; + node.next = first; + } + node.prev = null; + first = node; + } + size++; + } else { + Node node = last; + while (node != null) { + if (pageNum == node.pageNum) { + Node temp = node; + if(node == last){ + last = last.prev; + last.prev = temp.prev.prev; + last.next = null; + }else if(node == first){ + first = temp.next; + first.prev = null; + first.next = temp.next.next; + }else{ + node.next.prev = temp.prev; + node.prev.next = temp.next; + } + temp = null; + break; + } + node = node.prev; + } + + if(node == null){ + Node temp = last; + last = last.prev; + last.prev = temp.prev.prev; + last.next = null; + temp = null; + } + + Node newNode = new Node(); + newNode.pageNum = pageNum; + first.prev = newNode; + newNode.prev = null; + newNode.next = first; + first = newNode; + + } + + } + + 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/284422826/src/com/coding2017/basic/linklist/LRUPageFrameTest.java b/group05/284422826/src/com/coding2017/basic/linklist/LRUPageFrameTest.java new file mode 100644 index 0000000000..7e0e79767c --- /dev/null +++ b/group05/284422826/src/com/coding2017/basic/linklist/LRUPageFrameTest.java @@ -0,0 +1,31 @@ +package com.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/group05/284422826/src/com/coding2017/basic/LinkedList.java b/group05/284422826/src/com/coding2017/basic/linklist/LinkedList.java similarity index 98% rename from group05/284422826/src/com/coding2017/basic/LinkedList.java rename to group05/284422826/src/com/coding2017/basic/linklist/LinkedList.java index fbc92ff474..e1dce5568c 100644 --- a/group05/284422826/src/com/coding2017/basic/LinkedList.java +++ b/group05/284422826/src/com/coding2017/basic/linklist/LinkedList.java @@ -1,4 +1,7 @@ -package com.coding2017.basic; +package com.coding2017.basic.linklist; + +import com.coding2017.basic.Iterator; +import com.coding2017.basic.List; import java.util.Arrays; import java.util.NoSuchElementException; From 39e466276d4b15beedcfb1acbe398b9c931b905a Mon Sep 17 00:00:00 2001 From: gongxun <gongxun@wesai.com> Date: Fri, 31 Mar 2017 17:50:55 +0800 Subject: [PATCH 089/287] finish lru --- group17/785396327/3.26/LRUPageFrame.java | 129 +++++++++++++++++++ group17/785396327/3.26/LRUPageFrameTest.java | 45 +++++++ 2 files changed, 174 insertions(+) create mode 100644 group17/785396327/3.26/LRUPageFrame.java create mode 100644 group17/785396327/3.26/LRUPageFrameTest.java diff --git a/group17/785396327/3.26/LRUPageFrame.java b/group17/785396327/3.26/LRUPageFrame.java new file mode 100644 index 0000000000..35a7f1e8ca --- /dev/null +++ b/group17/785396327/3.26/LRUPageFrame.java @@ -0,0 +1,129 @@ +/** + * Created by william on 2017/3/31. + * 1. 新数据插入到链表头部; + * 2. 每当缓存命中(即缓存数据被访问),则将数据移到链表头部; + * 3. 当链表满的时候,将链表尾部的数据丢弃。 + */ +public class LRUPageFrame { + private static class Node { + + Node prev; + Node next; + int pageNum; + + Node() { + } + + @Override + public String toString() { + return pageNum + ""; + } + } + + private int capacity; + + + private Node first;// 链表头 + private Node last;// 链表尾 + private int size; + + private void removeLast() { + if (last != null) { + if (size == 1) { + first = last = null; + size = 0; + } else { + last = last.prev; + last.next = null; + size--; + } + } + } + + private void remove(Integer pageNum) { + for (Node temp = first; temp != null; temp = temp.next) { + if (temp.pageNum == pageNum) { + unlink(temp); + } + } + } + + private void unlink(Node node) { + final Node prev = node.prev; + final Node next = node.next; + if (prev == null) { + first = next; + size--; + } else if (next == null) + removeLast(); + else { + node.next.prev = prev; + node.prev.next = next; + size--; + } + } + + private void addFirst(Integer pageNum) { + Node newNode = new Node(); + newNode.pageNum = pageNum; + if (first == null) { + first = last = newNode; + } else { + newNode.next = first; + first.prev = newNode; + first = newNode; + //在插入第二个元素时设置last元素的前项 + if (size == 1) last.prev = first; + } + size++; + } + + private boolean contains(Integer pageNum) { + Node temp = first; + while (temp != null) { + if (temp.pageNum == pageNum) + return true; + temp = temp.next; + } + return false; + } + + + public LRUPageFrame(int capacity) { + this.capacity = capacity; + } + + /** + * 获取缓存中对象 + * + * @param pageNum + * @return + */ + public void access(int pageNum) { + //存在链表元素 + if (this.contains(pageNum)) { + remove(pageNum); + addFirst(pageNum); + } else { + //不存在 + if (size == capacity) + removeLast(); + 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(","); + } + } + return buffer.toString(); + } +} diff --git a/group17/785396327/3.26/LRUPageFrameTest.java b/group17/785396327/3.26/LRUPageFrameTest.java new file mode 100644 index 0000000000..7b13e17815 --- /dev/null +++ b/group17/785396327/3.26/LRUPageFrameTest.java @@ -0,0 +1,45 @@ +import org.junit.Assert; +import org.junit.Test; + +/** + * Created by william on 2017/3/31. + */ +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()); + } + + @Test + public void testInnerMethod() { +// LRUPageFrame lruPageFrame = new LRUPageFrame(3); +// lruPageFrame.access(1); +// lruPageFrame.access(2); +// lruPageFrame.access(3); +// lruPageFrame.access(4); +// System.out.println(lruPageFrame); +// System.out.println(lruPageFrame.last); +// lruPageFrame.removeLast(); +// System.out.println(lruPageFrame); +// lruPageFrame.addFirst(0); +// System.out.println(lruPageFrame); +// lruPageFrame.remove(2); +// System.out.println(lruPageFrame); + } +} From 983e4a849b6f3e6e1a2010da5cf44559154b7ab9 Mon Sep 17 00:00:00 2001 From: mengxz <82427129@qq.com> Date: Fri, 31 Mar 2017 18:07:52 +0800 Subject: [PATCH 090/287] homework of 17/3/26 finished ,first jvm homework and LRU --- .../jvm/loader/ClassFileLoader.java | 104 +++++++++++++ .../com/coderising/jvm/test/EmployeeV1.java | 29 ++++ .../com/coding/basic/LRU/LRUPageFrame.java | 147 ++++++++++++++++++ .../jvm/loader/ClassFileLoaderTest.java | 73 +++++++++ .../coding/basic/LRU/LRUPageFrameTest.java | 29 ++++ 5 files changed, 382 insertions(+) create mode 100644 group17/82427129/JavaUtil/src/main/java/com/coderising/jvm/loader/ClassFileLoader.java create mode 100644 group17/82427129/JavaUtil/src/main/java/com/coderising/jvm/test/EmployeeV1.java create mode 100644 group17/82427129/JavaUtil/src/main/java/com/coding/basic/LRU/LRUPageFrame.java create mode 100644 group17/82427129/JavaUtil/src/test/java/com/coderising/jvm/loader/ClassFileLoaderTest.java create mode 100644 group17/82427129/JavaUtil/src/test/java/com/coding/basic/LRU/LRUPageFrameTest.java diff --git a/group17/82427129/JavaUtil/src/main/java/com/coderising/jvm/loader/ClassFileLoader.java b/group17/82427129/JavaUtil/src/main/java/com/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..fafac43407 --- /dev/null +++ b/group17/82427129/JavaUtil/src/main/java/com/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,104 @@ +package com.coderising.jvm.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 static final int BUFFERSIZE = 1024; + private List<String> clzPaths = new ArrayList<String>(); + + public byte[] readBinaryCode(String className) { + if (clzPaths.size()<=0){ + return null; + } + for (int i = 0; i < clzPaths.size(); i++) { + String path = clzPaths.get(i) + convertName(className); + File f = new File(path); + if(f.exists()){ + try { + return readFile(f); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + }else{ + f = null; + continue; + } + } + System.err.println("classpath:" +getClassPath()+ "class:" + convertName(className)+" not found."); + return null; + } + /** + * 文件读取二进制字节流 + * @param f + * @return + * @throws FileNotFoundException + */ + private byte[] readFile(File f) throws FileNotFoundException { + FileInputStream fis = new FileInputStream(f); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] b = new byte[BUFFERSIZE]; + try { + int len = 0; + while((len = fis.read(b))!=-1){ + baos.write(b,0,len); + } + } catch (IOException e) { + e.printStackTrace(); + } finally{ + try { + fis.close(); + baos.flush(); + baos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + } + return baos.toByteArray(); + } + + public void addClassPath(String path) { + clzPaths.add(path); + } + + public String getClassPath() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < clzPaths.size(); i++) { + sb.append(clzPaths.get(i)).append(";"); + } + int len = sb.length(); + if(len!=0){ + sb.deleteCharAt(len-1); + } + return sb.toString(); + } + + /** + * convert className to FilePath style className <br/> + * For example:com.sun.lang to \com\sun\lang + * + * @param className + * @return FilePath style className + */ + private String convertName(String className) { + StringBuilder sb = new StringBuilder(); + String[] pack = className.split("\\."); + for (int i = 0; i < pack.length; i++) { + sb.append("\\").append(pack[i]); + } + sb.append(".class"); + return sb.toString(); + } + + public static void main(String[] args) { + String d = "com.taiji.array.Load"; + ClassFileLoader cc = new ClassFileLoader(); + System.out.print(cc.convertName(d)); + } +} diff --git a/group17/82427129/JavaUtil/src/main/java/com/coderising/jvm/test/EmployeeV1.java b/group17/82427129/JavaUtil/src/main/java/com/coderising/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..70ec469ee6 --- /dev/null +++ b/group17/82427129/JavaUtil/src/main/java/com/coderising/jvm/test/EmployeeV1.java @@ -0,0 +1,29 @@ +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/group17/82427129/JavaUtil/src/main/java/com/coding/basic/LRU/LRUPageFrame.java b/group17/82427129/JavaUtil/src/main/java/com/coding/basic/LRU/LRUPageFrame.java new file mode 100644 index 0000000000..45638bd851 --- /dev/null +++ b/group17/82427129/JavaUtil/src/main/java/com/coding/basic/LRU/LRUPageFrame.java @@ -0,0 +1,147 @@ +package com.coding.basic.LRU; + +public class LRUPageFrame { + private int capacity; + private Node first;// 链表头 + private Node last;// 链表尾 + private int length = 0; + + public LRUPageFrame(int capacity) { + this.capacity = capacity; + } + + /** + * 获取缓存中对象 + * + * @param key + * @return + */ + public void access(int pageNum) { + // this loop select for pageNum,grow it first when 'found'. + for (Node n = first; n != null; n = n.next) { + if (n.pageNum == pageNum) { + growFirst(n); + return; + } + } + // if didn't found it + if (ensureFull()) { + removeLast(); + } + add(pageNum); + } + + private void add(int pageNum) { + if (isEmpty()) { + Node newNode = new Node(null, null, pageNum); + first = newNode; + last = newNode; + length++; + } else { + addToFirst(pageNum); + } + } + + private void addToFirst(int pageNum) { + Node newNode = new Node(null, null, pageNum); + newNode.next = first; + first.prev = newNode; + first = newNode; + length++; + } + + /** + * ensure the LRUPageFrame is full or Not + * + * @return if full return true,else false + */ + private boolean ensureFull() { + if (length < capacity) { + return false; + } else { + return true; + } + } + + /** + * grow the Node'position to first + * + * @param n + */ + private void growFirst(Node n) { + // if the node is already first ,return. + if (first.pageNum == n.pageNum) { + return; + } + remove(n); + addToFirst(n.pageNum); + } + + private void remove(Node n) { + if (isEmpty()) { + return; + } + if (n.next == null) { + removeLast(); + return; + } + if (n.prev == null) { + removeFirst(); + return; + } + Node prev = n.prev; + Node next = n.next; + n.next = null; + n.prev = null; + prev.next = next; + next.prev = prev; + length--; + } + + private void removeFirst() { + Node next = first.next; + first.next = null; + first = next; + } + + private void removeLast() { + Node prev = last.prev; + prev.next = null; + last.prev = null; + last = prev; + length--; + } + /** + * ensure the LRUPageFrame is empty or Not. + * @return + */ + public boolean isEmpty() { + return length < 1; + } + + 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(Node prev, Node next, int pageNum) { + this.prev = prev; + this.next = next; + this.pageNum = pageNum; + } + } +} diff --git a/group17/82427129/JavaUtil/src/test/java/com/coderising/jvm/loader/ClassFileLoaderTest.java b/group17/82427129/JavaUtil/src/test/java/com/coderising/jvm/loader/ClassFileLoaderTest.java new file mode 100644 index 0000000000..e2ed056cc3 --- /dev/null +++ b/group17/82427129/JavaUtil/src/test/java/com/coderising/jvm/loader/ClassFileLoaderTest.java @@ -0,0 +1,73 @@ +package 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 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\mini-jvm\\bin"; + static String path2 = "D:\\workProgram\\GitRepo\\coding2017\\group17\\82427129\\JavaUtil\\target\\classes"; + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testClassFileLength() { + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path2); + + String className = "com.coderising.jvm.test.EmployeeV1"; + + byte[] byteCodes = loader.readBinaryCode(className); + + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + Assert.assertEquals(1056, byteCodes.length); + + } + + @Test + public void testGetClassPath() { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + loader.addClassPath(path2); + + String clzPath = loader.getClassPath(); + + Assert.assertEquals(path1+";"+path2,clzPath); + } + + @Test + public void testMagicNumber(){ + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path2); + 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/group17/82427129/JavaUtil/src/test/java/com/coding/basic/LRU/LRUPageFrameTest.java b/group17/82427129/JavaUtil/src/test/java/com/coding/basic/LRU/LRUPageFrameTest.java new file mode 100644 index 0000000000..e05d4b750e --- /dev/null +++ b/group17/82427129/JavaUtil/src/test/java/com/coding/basic/LRU/LRUPageFrameTest.java @@ -0,0 +1,29 @@ +package com.coding.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()); + } + +} From cd09dee1223dfe3bcea55b7935abde64c7b67950 Mon Sep 17 00:00:00 2001 From: JayXu <xuweijay@163.com> Date: Fri, 31 Mar 2017 21:24:04 +0800 Subject: [PATCH 091/287] 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 @@ <project version="4"> <component name="ChangeListManager"> <list default="true" id="d338ed3a-e900-486a-89a5-3e8b0a3835ed" name="Default" comment=""> + <change type="MODIFICATION" beforePath="$PROJECT_DIR$/out/production/1511_714512544/com/coderising/download/FileDownloader.class" afterPath="$PROJECT_DIR$/out/production/1511_714512544/com/coderising/download/FileDownloader.class" /> + <change type="MODIFICATION" beforePath="$PROJECT_DIR$/out/production/1511_714512544/com/coderising/download/FileDownloaderTest.class" afterPath="$PROJECT_DIR$/out/production/1511_714512544/com/coderising/download/FileDownloaderTest.class" /> <change type="MODIFICATION" beforePath="$PROJECT_DIR$/.idea/workspace.xml" afterPath="$PROJECT_DIR$/.idea/workspace.xml" /> - <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/com/coding/basic/BinarySearchTree.java" afterPath="$PROJECT_DIR$/src/com/coding/basic/BinarySearchTree.java" /> - <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/com/coding/basic/ReConstructBST.java" afterPath="$PROJECT_DIR$/src/com/coding/basic/ReConstructBST.java" /> + <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/com/coderising/download/FileDownloader.java" afterPath="$PROJECT_DIR$/src/com/coderising/download/FileDownloader.java" /> + <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/com/coderising/download/FileDownloaderTest.java" afterPath="$PROJECT_DIR$/src/com/coderising/download/FileDownloaderTest.java" /> + <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/com/coderising/download/impl/ConnectionImpl.java" afterPath="$PROJECT_DIR$/src/com/coderising/download/impl/ConnectionImpl.java" /> </list> <ignored path="$PROJECT_DIR$/out/" /> <option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" /> @@ -30,7 +33,7 @@ <favorites_list name="1511_714512544" /> </component> <component name="FileEditorManager"> - <leaf SIDE_TABS_SIZE_LIMIT_KEY="375" /> + <leaf /> </component> <component name="FileTemplateManagerImpl"> <option name="RECENT_TEMPLATES"> @@ -63,13 +66,13 @@ <option value="$PROJECT_DIR$/src/com/coding/basic/ReConstructBSTTest.groovy" /> <option value="$PROJECT_DIR$/src/com/coderising/download/impl/ConnectionManagerImpl.java" /> <option value="$PROJECT_DIR$/src/com/coderising/download/ConnectionTest.java" /> - <option value="$PROJECT_DIR$/src/com/coderising/download/impl/ConnectionImpl.java" /> - <option value="$PROJECT_DIR$/src/com/coderising/download/FileDownloader.java" /> <option value="$PROJECT_DIR$/src/com/coderising/download/DownloadThread.java" /> - <option value="$PROJECT_DIR$/src/com/coderising/download/FileDownloaderTest.java" /> <option value="$PROJECT_DIR$/src/com/coding/basic/ReConstructBSTTest.java" /> <option value="$PROJECT_DIR$/src/com/coding/basic/BinarySearchTree.java" /> <option value="$PROJECT_DIR$/src/com/coding/basic/ReConstructBST.java" /> + <option value="$PROJECT_DIR$/src/com/coderising/download/impl/ConnectionImpl.java" /> + <option value="$PROJECT_DIR$/src/com/coderising/download/FileDownloaderTest.java" /> + <option value="$PROJECT_DIR$/src/com/coderising/download/FileDownloader.java" /> </list> </option> </component> @@ -87,7 +90,7 @@ </component> <component name="ProjectView"> <navigator currentView="ProjectPane" proportions="" version="1"> - <flattenPackages /> + <flattenPackages ProjectPane="true" /> <showMembers /> <showModules /> <showLibraryContents /> @@ -100,6 +103,7 @@ <foldersAlwaysOnTop value="true" /> </navigator> <panes> + <pane id="Scratches" /> <pane id="ProjectPane"> <subPane> <PATH> @@ -139,42 +143,15 @@ <option name="myItemId" value="src" /> <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="com" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> <PATH_ELEMENT> <option name="myItemId" value="basic" /> <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> </PATH_ELEMENT> </PATH> - <PATH> - <PATH_ELEMENT> - <option name="myItemId" value="1511_714512544" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="1511_714512544" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="src" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="com" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="coderising" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - </PATH> </subPane> </pane> - <pane id="Scratches" /> - <pane id="PackagesPane" /> <pane id="Scope" /> + <pane id="PackagesPane" /> </panes> </component> <component name="PropertiesComponent"> @@ -199,7 +176,7 @@ <recent name="D:\AlgorithmsIDEA\coding2017\group15\1511_714512544\src\com\coderising\download" /> </key> </component> - <component name="RunManager" selected="JUnit.ReConstructBSTTest.construct"> + <component name="RunManager" selected="JUnit.FileDownloaderTest.testDownload"> <configuration default="false" name="FileDownloaderTest.testDownload" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true"> <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea"> <pattern> @@ -226,39 +203,45 @@ <patterns /> <method /> </configuration> - <configuration default="false" name="Demo" type="Application" factoryName="Application" temporary="true" nameIsGenerated="true"> + <configuration default="false" name="BinarySearchTreeTest.postOrderGetHeight" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true"> <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea"> <pattern> - <option name="PATTERN" value="com.coderising.download.*" /> + <option name="PATTERN" value="test.com.coding.basic.*" /> <option name="ENABLED" value="true" /> </pattern> </extension> - <option name="MAIN_CLASS_NAME" value="com.coderising.download.Demo" /> - <option name="VM_PARAMETERS" /> - <option name="PROGRAM_PARAMETERS" /> - <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" /> + <module name="1511_714512544" /> <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> <option name="ALTERNATIVE_JRE_PATH" /> - <option name="ENABLE_SWING_INSPECTOR" value="false" /> + <option name="PACKAGE_NAME" value="test.com.coding.basic" /> + <option name="MAIN_CLASS_NAME" value="test.com.coding.basic.BinarySearchTreeTest" /> + <option name="METHOD_NAME" value="postOrderGetHeight" /> + <option name="TEST_OBJECT" value="method" /> + <option name="VM_PARAMETERS" value="-ea" /> + <option name="PARAMETERS" /> + <option name="WORKING_DIRECTORY" value="$MODULE_DIR$" /> <option name="ENV_VARIABLES" /> <option name="PASS_PARENT_ENVS" value="true" /> - <module name="1511_714512544" /> + <option name="TEST_SEARCH_SCOPE"> + <value defaultName="singleModule" /> + </option> <envs /> + <patterns /> <method /> </configuration> - <configuration default="false" name="BinarySearchTreeTest.traveralByLevel" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true"> + <configuration default="false" name="ReConstructBSTTest.construct" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true"> <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea"> <pattern> - <option name="PATTERN" value="test.com.coding.basic.*" /> + <option name="PATTERN" value="com.coding.basic.*" /> <option name="ENABLED" value="true" /> </pattern> </extension> <module name="1511_714512544" /> <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> <option name="ALTERNATIVE_JRE_PATH" /> - <option name="PACKAGE_NAME" value="test.com.coding.basic" /> - <option name="MAIN_CLASS_NAME" value="test.com.coding.basic.BinarySearchTreeTest" /> - <option name="METHOD_NAME" value="traveralByLevel" /> + <option name="PACKAGE_NAME" value="com.coding.basic" /> + <option name="MAIN_CLASS_NAME" value="com.coding.basic.ReConstructBSTTest" /> + <option name="METHOD_NAME" value="construct" /> <option name="TEST_OBJECT" value="method" /> <option name="VM_PARAMETERS" value="-ea" /> <option name="PARAMETERS" /> @@ -272,19 +255,19 @@ <patterns /> <method /> </configuration> - <configuration default="false" name="BinarySearchTreeTest.postOrderGetHeight" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true"> + <configuration default="false" name="ConnectionTest.testContentLength" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true"> <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea"> <pattern> - <option name="PATTERN" value="test.com.coding.basic.*" /> + <option name="PATTERN" value="com.coderising.download.*" /> <option name="ENABLED" value="true" /> </pattern> </extension> <module name="1511_714512544" /> <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> <option name="ALTERNATIVE_JRE_PATH" /> - <option name="PACKAGE_NAME" value="test.com.coding.basic" /> - <option name="MAIN_CLASS_NAME" value="test.com.coding.basic.BinarySearchTreeTest" /> - <option name="METHOD_NAME" value="postOrderGetHeight" /> + <option name="PACKAGE_NAME" value="com.coderising.download" /> + <option name="MAIN_CLASS_NAME" value="com.coderising.download.ConnectionTest" /> + <option name="METHOD_NAME" value="testContentLength" /> <option name="TEST_OBJECT" value="method" /> <option name="VM_PARAMETERS" value="-ea" /> <option name="PARAMETERS" /> @@ -298,19 +281,19 @@ <patterns /> <method /> </configuration> - <configuration default="false" name="ReConstructBSTTest.construct" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true"> + <configuration default="false" name="ConnectionTest.testRead" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true"> <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea"> <pattern> - <option name="PATTERN" value="com.coding.basic.*" /> + <option name="PATTERN" value="com.coderising.download.*" /> <option name="ENABLED" value="true" /> </pattern> </extension> <module name="1511_714512544" /> <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> <option name="ALTERNATIVE_JRE_PATH" /> - <option name="PACKAGE_NAME" value="com.coding.basic" /> - <option name="MAIN_CLASS_NAME" value="com.coding.basic.ReConstructBSTTest" /> - <option name="METHOD_NAME" value="construct" /> + <option name="PACKAGE_NAME" value="com.coderising.download" /> + <option name="MAIN_CLASS_NAME" value="com.coderising.download.ConnectionTest" /> + <option name="METHOD_NAME" value="testRead" /> <option name="TEST_OBJECT" value="method" /> <option name="VM_PARAMETERS" value="-ea" /> <option name="PARAMETERS" /> @@ -722,18 +705,18 @@ </configuration> <list size="5"> <item index="0" class="java.lang.String" itemvalue="JUnit.FileDownloaderTest.testDownload" /> - <item index="1" class="java.lang.String" itemvalue="Application.Demo" /> - <item index="2" class="java.lang.String" itemvalue="JUnit.BinarySearchTreeTest.traveralByLevel" /> - <item index="3" class="java.lang.String" itemvalue="JUnit.BinarySearchTreeTest.postOrderGetHeight" /> - <item index="4" class="java.lang.String" itemvalue="JUnit.ReConstructBSTTest.construct" /> + <item index="1" class="java.lang.String" itemvalue="JUnit.BinarySearchTreeTest.postOrderGetHeight" /> + <item index="2" class="java.lang.String" itemvalue="JUnit.ReConstructBSTTest.construct" /> + <item index="3" class="java.lang.String" itemvalue="JUnit.ConnectionTest.testContentLength" /> + <item index="4" class="java.lang.String" itemvalue="JUnit.ConnectionTest.testRead" /> </list> <recent_temporary> <list size="5"> - <item index="0" class="java.lang.String" itemvalue="JUnit.ReConstructBSTTest.construct" /> - <item index="1" class="java.lang.String" itemvalue="JUnit.FileDownloaderTest.testDownload" /> - <item index="2" class="java.lang.String" itemvalue="JUnit.BinarySearchTreeTest.postOrderGetHeight" /> - <item index="3" class="java.lang.String" itemvalue="JUnit.BinarySearchTreeTest.traveralByLevel" /> - <item index="4" class="java.lang.String" itemvalue="Application.Demo" /> + <item index="0" class="java.lang.String" itemvalue="JUnit.FileDownloaderTest.testDownload" /> + <item index="1" class="java.lang.String" itemvalue="JUnit.ConnectionTest.testRead" /> + <item index="2" class="java.lang.String" itemvalue="JUnit.ConnectionTest.testContentLength" /> + <item index="3" class="java.lang.String" itemvalue="JUnit.ReConstructBSTTest.construct" /> + <item index="4" class="java.lang.String" itemvalue="JUnit.BinarySearchTreeTest.postOrderGetHeight" /> </list> </recent_temporary> </component> @@ -769,7 +752,10 @@ <workItem from="1489628754510" duration="9391000" /> <workItem from="1489647273393" duration="3740000" /> <workItem from="1489654640274" duration="1134000" /> - <workItem from="1489658627416" duration="365000" /> + <workItem from="1489658627416" duration="1354000" /> + <workItem from="1489726867862" duration="16000" /> + <workItem from="1490016596218" duration="624000" /> + <workItem from="1490090580129" duration="215000" /> </task> <task id="LOCAL-00001" summary="xuweijay"> <created>1488937445293</created> @@ -841,18 +827,22 @@ <option name="project" value="LOCAL" /> <updated>1489658675286</updated> </task> - <option name="localTasksCounter" value="11" /> + <task id="LOCAL-00011" summary="xuweijay"> + <created>1489659000096</created> + <option name="number" value="00011" /> + <option name="presentableId" value="LOCAL-00011" /> + <option name="project" value="LOCAL" /> + <updated>1489659000096</updated> + </task> + <option name="localTasksCounter" value="12" /> <servers /> </component> <component name="TestHistory"> - <history-entry file="FileDownloaderTest_testDownload - 2017.03.12 at 15h 16m 40s.xml"> - <configuration name="FileDownloaderTest.testDownload" configurationId="JUnit" /> - </history-entry> - <history-entry file="FileDownloaderTest_testDownload - 2017.03.16 at 15h 31m 26s.xml"> - <configuration name="FileDownloaderTest.testDownload" configurationId="JUnit" /> + <history-entry file="ConnectionTest_testContentLength - 2017.03.16 at 18h 17m 53s.xml"> + <configuration name="ConnectionTest.testContentLength" configurationId="JUnit" /> </history-entry> - <history-entry file="FileDownloaderTest_testDownload - 2017.03.16 at 15h 43m 04s.xml"> - <configuration name="FileDownloaderTest.testDownload" configurationId="JUnit" /> + <history-entry file="ConnectionTest_testRead - 2017.03.16 at 18h 17m 57s.xml"> + <configuration name="ConnectionTest.testRead" configurationId="JUnit" /> </history-entry> <history-entry file="FileDownloaderTest_testDownload - 2017.03.16 at 15h 43m 32s.xml"> <configuration name="FileDownloaderTest.testDownload" configurationId="JUnit" /> @@ -860,6 +850,9 @@ <history-entry file="FileDownloaderTest_testDownload - 2017.03.16 at 15h 53m 43s.xml"> <configuration name="FileDownloaderTest.testDownload" configurationId="JUnit" /> </history-entry> + <history-entry file="FileDownloaderTest_testDownload - 2017.03.16 at 18h 18m 44s.xml"> + <configuration name="FileDownloaderTest.testDownload" configurationId="JUnit" /> + </history-entry> <history-entry file="LinkedListTest_removeRange - 2017.03.10 at 22h 32m 52s.xml"> <configuration name="LinkedListTest.removeRange" configurationId="JUnit" /> </history-entry> @@ -877,7 +870,7 @@ </history-entry> </component> <component name="TimeTrackingManager"> - <option name="totallyTimeSpent" value="66350000" /> + <option name="totallyTimeSpent" value="68194000" /> </component> <component name="TodoView"> <todo-panel id="selected-file"> @@ -906,7 +899,7 @@ <window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> <window_info id="Capture Tool" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> <window_info id="Designer" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" /> - <window_info id="Project" active="true" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.22800429" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" /> + <window_info id="Project" active="true" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.2360515" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" /> <window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="9" side_tool="false" content_ui="tabs" /> <window_info id="Structure" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.23444206" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" /> <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" /> @@ -962,13 +955,6 @@ <option name="FILTER_TARGETS" value="false" /> </component> <component name="editorHistoryManager"> - <entry file="file://$PROJECT_DIR$/src/com/coderising/download/impl/ConnectionImpl.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="84"> - <caret line="6" column="13" lean-forward="false" selection-start-line="6" selection-start-column="13" selection-end-line="6" selection-end-column="13" /> - </state> - </provider> - </entry> <entry file="file://$PROJECT_DIR$/src/com/coderising/download/impl/ConnectionManagerImpl.java"> <provider selected="true" editor-type-id="text-editor"> <state relative-caret-position="84"> @@ -1200,7 +1186,6 @@ <provider selected="true" editor-type-id="text-editor"> <state relative-caret-position="336"> <caret line="346" column="0" lean-forward="true" selection-start-line="346" selection-start-column="0" selection-end-line="346" selection-end-column="0" /> - <folding /> </state> </provider> </entry> @@ -1215,24 +1200,6 @@ <provider selected="true" editor-type-id="text-editor"> <state relative-caret-position="379"> <caret line="65" column="5" lean-forward="true" selection-start-line="65" selection-start-column="5" selection-end-line="65" selection-end-column="5" /> - <folding> - <element signature="e#600#601#0" expanded="false" /> - <element signature="e#641#642#0" expanded="false" /> - <element signature="e#679#680#0" expanded="false" /> - <element signature="e#713#714#0" expanded="false" /> - <element signature="e#766#767#0" expanded="false" /> - <element signature="e#803#804#0" expanded="false" /> - <element signature="e#841#842#0" expanded="false" /> - <element signature="e#875#876#0" expanded="false" /> - <element signature="e#928#929#0" expanded="false" /> - <element signature="e#965#966#0" expanded="false" /> - <element signature="e#1004#1005#0" expanded="false" /> - <element signature="e#1039#1040#0" expanded="false" /> - <element signature="e#1093#1094#0" expanded="false" /> - <element signature="e#1131#1132#0" expanded="false" /> - <element signature="e#1171#1172#0" expanded="false" /> - <element signature="e#1212#1213#0" expanded="false" /> - </folding> </state> </provider> </entry> @@ -1241,7 +1208,6 @@ <provider selected="true" editor-type-id="text-editor"> <state relative-caret-position="105"> <caret line="5" column="13" lean-forward="false" selection-start-line="5" selection-start-column="13" selection-end-line="5" selection-end-column="13" /> - <folding /> </state> </provider> </entry> @@ -1273,73 +1239,73 @@ </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/src/com/coderising/download/ConnectionTest.java"> + <entry file="file://$PROJECT_DIR$/src/com/coding/basic/ReConstructBSTTest.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="126"> - <caret line="13" column="13" lean-forward="false" selection-start-line="13" selection-start-column="13" selection-end-line="13" selection-end-column="13" /> + <state relative-caret-position="147"> + <caret line="11" column="33" lean-forward="true" selection-start-line="11" selection-start-column="33" selection-end-line="11" selection-end-column="33" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/src/com/coderising/download/impl/ConnectionManagerImpl.java"> + <entry file="jar://C:/Program Files/Java/jdk1.8.0_111/src.zip!/java/io/RandomAccessFile.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="252"> - <caret line="19" column="37" lean-forward="false" selection-start-line="19" selection-start-column="37" selection-end-line="19" selection-end-column="37" /> + <state relative-caret-position="283"> + <caret line="487" column="16" lean-forward="false" selection-start-line="487" selection-start-column="16" selection-end-line="487" selection-end-column="16" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/src/com/coderising/download/impl/ConnectionImpl.java"> + <entry file="file://$PROJECT_DIR$/src/com/coding/basic/BinarySearchTree.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="95"> - <caret line="31" column="0" lean-forward="true" selection-start-line="31" selection-start-column="0" selection-end-line="31" selection-end-column="0" /> + <state relative-caret-position="358"> + <caret line="340" column="15" lean-forward="false" selection-start-line="340" selection-start-column="15" selection-end-line="340" selection-end-column="15" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/src/com/coderising/download/FileDownloaderTest.java"> + <entry file="file://$PROJECT_DIR$/src/com/coding/basic/ReConstructBST.java"> + <provider selected="true" editor-type-id="text-editor"> + <state relative-caret-position="-42"> + <caret line="19" column="5" lean-forward="true" selection-start-line="16" selection-start-column="7" selection-end-line="19" selection-end-column="5" /> + </state> + </provider> + </entry> + <entry file="file://$PROJECT_DIR$/src/com/coderising/download/impl/ConnectionManagerImpl.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="399"> - <caret line="25" column="69" lean-forward="false" selection-start-line="25" selection-start-column="69" selection-end-line="25" selection-end-column="69" /> + <state relative-caret-position="252"> + <caret line="19" column="37" lean-forward="false" selection-start-line="19" selection-start-column="37" selection-end-line="19" selection-end-column="37" /> </state> </provider> </entry> <entry file="file://$PROJECT_DIR$/src/com/coderising/download/DownloadThread.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="610"> - <caret line="35" column="42" lean-forward="true" selection-start-line="35" selection-start-column="42" selection-end-line="35" selection-end-column="42" /> + <state relative-caret-position="568"> + <caret line="33" column="54" lean-forward="true" selection-start-line="33" selection-start-column="54" selection-end-line="33" selection-end-column="54" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/src/com/coderising/download/FileDownloader.java"> + <entry file="file://$PROJECT_DIR$/src/com/coderising/download/impl/ConnectionImpl.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="21"> - <caret line="44" column="15" lean-forward="true" selection-start-line="44" selection-start-column="15" selection-end-line="44" selection-end-column="15" /> + <state relative-caret-position="1029"> + <caret line="49" column="0" lean-forward="true" selection-start-line="49" selection-start-column="0" selection-end-line="49" selection-end-column="0" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/src/com/coding/basic/ReConstructBST.java"> + <entry file="file://$PROJECT_DIR$/src/com/coderising/download/ConnectionTest.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="211"> - <caret line="33" column="40" lean-forward="true" selection-start-line="33" selection-start-column="40" selection-end-line="33" selection-end-column="40" /> - <folding> - <element signature="imports" expanded="true" /> - </folding> + <state relative-caret-position="189"> + <caret line="21" column="5" lean-forward="true" selection-start-line="21" selection-start-column="5" selection-end-line="21" selection-end-column="5" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/src/com/coding/basic/ReConstructBSTTest.java"> + <entry file="file://$PROJECT_DIR$/src/com/coderising/download/FileDownloader.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="147"> - <caret line="11" column="33" lean-forward="true" selection-start-line="11" selection-start-column="33" selection-end-line="11" selection-end-column="33" /> - <folding /> + <state relative-caret-position="452"> + <caret line="47" column="56" lean-forward="false" selection-start-line="47" selection-start-column="56" selection-end-line="47" selection-end-column="56" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/src/com/coding/basic/BinarySearchTree.java"> + <entry file="file://$PROJECT_DIR$/src/com/coderising/download/FileDownloaderTest.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="547"> - <caret line="349" column="26" lean-forward="true" selection-start-line="349" selection-start-column="26" selection-end-line="349" selection-end-column="26" /> - <folding> - <element signature="imports" expanded="true" /> - </folding> + <state relative-caret-position="630"> + <caret line="48" column="36" lean-forward="true" selection-start-line="48" selection-start-column="36" selection-end-line="48" selection-end-column="36" /> </state> </provider> </entry> 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 zcma)6+j7%L5Itkrk#SrBJKUE0HP~@tVFz*{*+3Ek70QGvE~%n;peFL*DCJ0AX^i;+ zUZ{e9;VA^F_yB%n_bYbyND)p<%77lEo}TH`=XCez+rOW`0=R*t400%$7|S4mQX1of zD8ou|kI%aggSd`L231TLT)q#NH{#7CV#D~y#7z^E0t0i7>*#p_qflHENG^GGC2+Xr zxN5b%wXXc9a=l4UzUJAoxh8!lT*uC&-f#keLe2KJESr(O6F6?es(T%`>B+ja<hic0 zwd1)@RiI}DQi0OXS^}BnH@0ep8-a-_fj=I%UF~eCH3ATS!F4??qwOfQ->^2@<Y_Ic zSDvp3l-5f6cbP{ZSM$323$L{Dxt-I@$Lw0Ux~ANQ-ViWtvUw;OVf7^}Th2bxJS-a# zUNVgRnbO`sGB~o2RV<#I1N~UZI_q4QS_&jyEV33)ytZ$vdrnyA;og#!H|1-YMIOTf z)qYiWwpz`DtXJq2nA*^~b<46kolbd!P3;6_+qGJbZC$r26V^<{s!r0FsZ=Mcm6y}i z%GAtcd9&3pF`dN>Zkd?PVh(?rn9t%i?qsn5avtf&rI$X-5DKuGl2h?$eUr05iF>Z@ z6bOv>L+q_=+!9vMYbkbQu29>9d!l`g-)!+W+siKX)zO=kIvVQ7dE$*(;l{q<3j*a+ zU{*%P@?UM)<n>4u9z2NdmLIi#ps=!1e6fg&IKq1zJ}Gd>G0gW-t}K2<=pEgL_(&sx zV|))p&LJG9o!vcv6FA8gZx4fwD7X}@>H9G-zb{b4fv0#l$?(%SLn};hHVQxYYq;aT z1$RDzyU>Mmn2tXsod1Hv^KBTlQa-tZR00o=Vqk0sX@R$&aA=Qvo&mrqq{%TymgmSY zEWm|bm{>=e-;20J{y7ZcGOn;>2en;|$c%K!Y!f>~e{_J%n32!yV9>xSX^npkDUBI9 z<G=5|Z0yS=ku(4P?j73o?vWqCA;MoG`O74Bl@hLzT9FMdVH)FDrnQQRNYLmmm9C)s YT|x7)pws;GUqgYy`$;P@TLPp11IZdsb^rhX literal 0 HcmV?d00001 diff --git a/group15/1511_714512544/out/production/1511_714512544/com/coderising/download/FileDownloader$1.class b/group15/1511_714512544/out/production/1511_714512544/com/coderising/download/FileDownloader$1.class new file mode 100644 index 0000000000000000000000000000000000000000..548ab88f2d593c9ed0234b9abdcaeca43467379b GIT binary patch literal 820 zcma)5+fLg+5IvKGm>5F>X`!^Gr6t@#6%(m%AYN#ZDg}^A#rwwIHjB(I@}-y0ssuvt zzz6VAh*@KVkU)wpul9^)&dfQxzP`D<0`M8jHH=`^MHR1Wn8BMdyv3Y@cMje=m?u=z zfl6BIgq2=kj{U%dGFFMwzx>er(UB3MzoR1gr2sPC;F?XPRk}r38@g!qkWkrXazeeQ zwA{;%`!fC^`VmK_dL|Ijp@@~mMX+KABY5AmmhpBZl0-6W4>@J4%X60FO!K;8o4W@l zivwx35SouAb&kYu!GnF(L1e7<U6~F{=-`8gk7#-rMa_e2cME7aSoE-jCR;X~W34Ws zVO#i-U|;w9M>0rR^+V`;ruCf_OT$qT9QjuUS;}HYBbB6*O(Jxjbw`{i|NabnMLs+9 z>A7}K<r5~fN!8DPJAC}fK!%v-yHy1b18Ov^OMK-@{J9w8sK>i4#(AW@b_Qynqx3(| z8Rykj0v$~7I$hM&G0Dg>ST^E!3eAFRBgepa`xJDF@&zh{2Rb*WSm(CgoYLcTPR1Q& X87~->@RC~r75)`op^-Nt7Lh-<UOdL8 literal 0 HcmV?d00001 diff --git a/group15/1511_714512544/out/production/1511_714512544/com/coderising/download/FileDownloader.class b/group15/1511_714512544/out/production/1511_714512544/com/coderising/download/FileDownloader.class index 50ad5affcb42acb8850ace0e47914bb899eed312..40bd7f6b60815a4a90004220a42d836765568776 100644 GIT binary patch delta 204 zcmbOsHC<}LYEF*g#In?a#FC7STNiWq>M;m1m@o)4m@_CcSTblZSTh(h*aBJh3{F7k z$KcG6&EU#V0OXf3cr#Qn_%JjxcrdgucrtVV`8`1XR3JSYNH1Xsn7owpgJ=i?H$xbM z2tzo7B#@S8h+<G?h@QNP>zr;J13N<k0}n$Y(9UEADTY*_o#_lZ44FU|WC3l?0os-e pG%cASkfCt$QttJvr3|bLWs@U$+*zxEteVM7dE6N5C%@s*0RUTlD_{Ts delta 205 zcmbO(HA8B`YA(*4{N%(Ox6GW>jawFT`06qUG8i)mGng?bGFUKZFjz4dGT1O!GT1RV zF*q{#0m*Cz7lr~Lzl_0)p^Cwqp_##*p@qSNp##Y80rIB;>DfSf34{OSC7d5bgBiFP zLK#FD!Wblhv^+y3gEB+Z<dt0KbYmIV8R8ju7!rVXCNW4cqyX(qW6)v9U@&3GWUvO> t<jjx*G%1N8kfC7m67Kb^B@C<#rIRCg+*zxDtm?^2c-$E4Ccoy<0RVFfD_;Nr diff --git a/group15/1511_714512544/out/production/1511_714512544/com/coderising/download/FileDownloaderTest.class b/group15/1511_714512544/out/production/1511_714512544/com/coderising/download/FileDownloaderTest.class index 0e6fd361ddbc29a24e186e9a107a15324d2e8f16..8b742b607fa9f05fdc8c14daa6e9a076d0c10606 100644 GIT binary patch delta 114 zcmew%a9?1<1SV_qjFOT9D}DX)@^Zb5%)Hd{V!h-%{esM7eFJ?%V|`0QeIqj<!_v^m y%*Zg_!pP9v(o8R_Af1sxZSn<1HAO}Su@oz83V0Y~7{VACjDV^nHajz$vH}30@E%40 delta 126 zcmcaF@Izq31g5yCjFOUqVk>?9;$j26q?F>4#FETpz2y8{ebdA+!=$XjjQBt!<NOro zG<}GiesO6*YEf=to_=O-x_(Z6dOnzlFVDy<NsUiSHA_h}Oik7+$V+ErP@8;#QH_t0 VfhWaEKPfRYr4%T<nUgt;6##ZBE06#H diff --git a/group15/1511_714512544/out/production/1511_714512544/com/coding/basic/ReConstructBST$Node.class b/group15/1511_714512544/out/production/1511_714512544/com/coding/basic/ReConstructBST$Node.class new file mode 100644 index 0000000000000000000000000000000000000000..408bbfa3fd2ce52b6241d3af5ec042f512a68c63 GIT binary patch literal 514 zcma)2%TB^T6g|VMf>jU@AE?BH7-S(EcN!Oxn2-=mgb+7AhBCsC(k5;3zg!R#7k+>r zWjs^exY9H|r+3=(=>7P7dk1ieS`HahvPfggz_x)M3snny0;#c#q=4w~(N#|osppTC zfZg#t6|`L$hAI>|>N@_s<@jUmO<E%vYNvIh+P)V?!NQ3y`-8fXoe87^J(<!bbFMud zUC^)5IUbVQv2DJqJ=I&xM=BV|k;|ZB*LS2llz}$$&tWQ>YNqD;{vvSHl{O!ieg~e+ z<g>J~j(r;zR%~Qp+gO8b;Xt7NpSl7CW72XZf9iTPQx1zK8>VjU4?PaK#SHhG<jr^@ zOoNzNg3PV5U7lFrbc+Nppxk_gXjYd<G{q801F09DC$K@R&=t5t3iot-p#BjhNEG9D av7YmHN;%FIRF-4?CRWKg=B2Sq&VB)x!)9*) literal 0 HcmV?d00001 diff --git a/group15/1511_714512544/out/production/1511_714512544/com/coding/basic/ReConstructBST.class b/group15/1511_714512544/out/production/1511_714512544/com/coding/basic/ReConstructBST.class new file mode 100644 index 0000000000000000000000000000000000000000..c998fe6a427173902103a902183f9adb7c95bb2e GIT binary patch literal 2449 zcma)8U2has7=F&~?9R@1`_1stR-styc9(5Yv|5T4`vER)X=zKbtw^W4({^Axv+T|i zns{SE)H@<+yf6WYnsB2DC={?s@d^|Fha_I;y#~bR%r2CQk!F)~-t*4;^*rx;PW#K> zKdu6J6~!<b&>zM&45&B|h93u2yc0q)i~tU4JijZKl(ZPsa2P`>hQo-UU#gEtX(WVE zxsS=^Xc*%-rsBOYHle=)6PT3Clw96daa_d*0?J`0V+ur)wr%G7vPPj`76gL(EZcH> z1pLvqaT@h`M%5|HHV+pUX3YGUF_WcRUCK!t*>NLp$#Yq$xbqfcG^f(eLPy%kSoU1U zj8U-C9V2F+V;9_fG41w_j&%!Y=|^XQUD2uJRI=?^UM;d<x`uLjb10uN^8&u9q=0JK z<zwZjYot#N8o6>k75TNa0=t<e$wbMGr}E_pM=*ykN6bD6&Sz25@{Z$<8`&adMalxL z8!f*^+9&Odc{cf|?wV}hSjx2L-1*0<da4HOjAu7o#>?3dsLACmoBqR2!7amXi*78p zY^bmWs@=SC#>^Yp-o=!8#>^6f?X@{@x@byBwW*WF8Ka}<TG@^xQbpD`uW$Hb?ordb z{%yQ(W7YI@t2iML9(9WOw0XdiQ&qoyPTFM|5j=<IBZwg`(DIDI@<v2DObax47_tUu zaHMFv)`B^3Hf`oy%OM5z_bz^V@4^qip8xo_&+pv(_QD^ZeA6ubm~94oB1p^S4Roo< zL||f8V9Q##QI{>4>n&PY4q*gyNJKCXi{$Q*!pR6uA**5`0vm?FrZqBojZT@FlvQwv zJpu>02u_1B3g8HBe+D`>f31k2nUiLkPStDCy;iZA(WLCO9xXM-W1v)Ww|Awp<}CdJ zd24Q-`x7BY7YnYrz^m^R`9UwaTTaKYoH#}>jRg*Zk}+JO3L3ebX=enQnC_`eWpZeq z_^&el$3EmbrD923^y$EiSnnZTUl;Ls_kz1KJ1d`tb?{4Mb+=8**P<}6kaHKk7mjBo z=VW;U*5@kQqnQtG1D|N{9Tsv9xo+pFgS(L0*iDFQ6nxmhHRvfdx`D5-XMmk}fhP?u zc##_EJPVcfKuhc{YU6iN8C$)CP<-_w0^(}SA6r#2aetiaE%>g|&hNzzdp@;%(CfYU zn@cg!ikE1^Xoyl0XrrvaSI3(r?@TGDC?bRkep!k&ws!_s;GfWgH=*oR8=EepSy%MH zWz_InLRZ=^Be+eyx`Mz&9c|P*y3!faLwewA)Ft##yB_=!+PRRp^6+<Rl}xABsB6=m zVO_g~t=rUCqcW|B8AlI!2yP&xYfX)rue^_XSeb5O6xsv`?*=rcVqGPSJ*cMKOtN>P zhKO`>*2-TSvF*Vwyp9A0N&XmiV-hdp1hp<+!-xFx8TNX-<VrXn^Rh(0gx8BDv{RDI zFL_+~J*k5_#gleZ3h;NHkrV7?4bI^eW>6XZIR8o~$l)0FGhc%JoMgUEN@0(29l-}^ z6ExNC!!Ps)XceM~W_&}+ZU2ZM<w$hJt|N38VY%J%Hm!8hc={d{D~L?o<WO8k)iSE< zYL-#EjJjpi%Q-9Y)WGV19#-}is?bZG`p|>}Om^^z+3RA3duUglh^k7K)BU)dKN(9h zkd6He<=P51F{z%4$8KY@569xSu|?nu3{%)D@Du!lYo+aasx)c{sVXk_QUFSX<!Q8% z=E}qGBm%{o<`{Vc4w3B?D%n#VL%dwW?8_1KV}$>{jPfNN<3oDXL$rgnM#=p?B9a}< zma$cG2HqqSf=ra|TuHN^8i~6efxvxKt9bi9_Om;Gq1ML$z5L|!NCOMuQ^0%P2<;z` 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%<v2E-F?8Dvran8AO@6P`I^WztQ7pUfu!B!rR@gy<Z97T>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`&<u;$sjJm86sO3U5g0b7z!<8fZoOMC&$^O1 zt^Bc2{@~zCLyX0Mp<J4cTW-_UwCJKHj|IA&;AFEDx%6iA&g^{$`$kR*IkL7%7LX^u za0$R2@<9GwBBu?xVq(huPjqe&*@SqHz)9~pIOHV_<_&#ey4><ia*IZ8=}PV^wX-O9 z<nW*QPTKN1R>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 6be7e88dabc3686818f3fbbcec12dfa9e463accf Mon Sep 17 00:00:00 2001 From: maishihang <446031103@qq.com> Date: Fri, 31 Mar 2017 23:11:44 +0800 Subject: [PATCH 092/287] compele LRU --- .../datastructure/linklist/LRUPageFrame.java | 114 ++++++++++++++++-- .../linklist/LRUPageFrameTest.java | 15 +++ 2 files changed, 121 insertions(+), 8 deletions(-) diff --git a/group12/446031103/src/com/datastructure/linklist/LRUPageFrame.java b/group12/446031103/src/com/datastructure/linklist/LRUPageFrame.java index bce6b36a64..5e20d9a49e 100644 --- a/group12/446031103/src/com/datastructure/linklist/LRUPageFrame.java +++ b/group12/446031103/src/com/datastructure/linklist/LRUPageFrame.java @@ -1,5 +1,7 @@ package com.datastructure.linklist; +import java.util.Objects; + /** * 用双向链表实现LRU算法 * @author liuxin @@ -13,13 +15,19 @@ private static class Node { Node next; int pageNum; - Node() { + Node(Node prev,Node next,int pageNum) { + this.prev = prev; + this.next = next; + this.pageNum = pageNum; + } + Node(){ + } } private int capacity; - - + private int addCnt ; + private int size; private Node first;// 链表头 private Node last;// 链表尾 @@ -27,7 +35,7 @@ private static class Node { public LRUPageFrame(int capacity) { this.capacity = capacity; - + first = new Node(); } /** @@ -37,20 +45,110 @@ public LRUPageFrame(int capacity) { * @return */ public void access(int pageNum) { + if(null==this.last){ + this.last = new Node(this.first,null,pageNum); + this.first.next = this.last; + addCnt++; + size++; + return; + } + if(contain(pageNum)){ + if(Objects.equals(this.first.next.pageNum, pageNum)){ + return; + } + boolean temp = Objects.equals(getLastNode(size).pageNum, pageNum); + Node currentNode = getNode(pageNum); + Node nextNode = currentNode.next; + Node preNode = currentNode.prev; + + currentNode.prev = this.first; + currentNode.next = this.first.next; + this.first.next = currentNode; + + if(temp){ + preNode.next = null; + if(null==preNode.prev) + preNode.prev = currentNode; + }else{ + preNode.prev = currentNode; + preNode.next = nextNode; + nextNode.next = null; + nextNode.prev = preNode; + } + this.last = getLastNode(size); + return; + } + Node addNode = new Node(this.first,this.first.next,pageNum); + Node oldFirstnode=this.first.next ; + oldFirstnode.prev = addNode; + this.first.next = addNode; + if(isOut()){ + + addCnt++; + if(this.size !=this.capacity ) + size++; + if(addCnt>size) + this.last.prev.next = null; + this.last = getLastNode(size); + }else{ + this.last.prev.next = null; + } } + private boolean isOut(){ + return this.addCnt<=this.capacity; + } + + private Node getLastNode(int sizes) { + Node node=this.first; + for (int i = 0; i < sizes; i++) { + node = node.next; + } + return node; + } + + private boolean contain(Object o){ + Node node = this.first; + + while(null!=node.next){ + + node = node.next; + + if(Objects.equals(node.pageNum,o)){ + return true; + } + + } + return false; + } + + private Node getNode(Object o){ + Node node = this.first; + + while(null!=node.next){ + + node = node.next; + + if(Objects.equals(node.pageNum,o)){ + return node; + } + + } + return null; + } + + public String toString(){ StringBuilder buffer = new StringBuilder(); Node node = first; - while(node != null){ - buffer.append(node.pageNum); - + while(node.next != null){ node = node.next; - if(node != null){ + buffer.append(node.pageNum); + if(node.next != null){ buffer.append(","); } } diff --git a/group12/446031103/src/com/datastructure/linklist/LRUPageFrameTest.java b/group12/446031103/src/com/datastructure/linklist/LRUPageFrameTest.java index 2d265f0bd3..956aa6c697 100644 --- a/group12/446031103/src/com/datastructure/linklist/LRUPageFrameTest.java +++ b/group12/446031103/src/com/datastructure/linklist/LRUPageFrameTest.java @@ -26,6 +26,21 @@ public void testAccess() { Assert.assertEquals("0,3,2", frame.toString()); frame.access(4); Assert.assertEquals("4,0,3", frame.toString()); + +// frame.access(7); +// Assert.assertEquals("7", frame.toString()); +// frame.access(7); +// Assert.assertEquals("7", frame.toString()); +// frame.access(2); +// Assert.assertEquals("2,7", frame.toString()); +// frame.access(7); +// Assert.assertEquals("7,2", frame.toString()); +// frame.access(3); +// Assert.assertEquals("3,7,2", frame.toString()); +// frame.access(2); +// Assert.assertEquals("2,3,7", frame.toString()); +// frame.access(2); +// Assert.assertEquals("2,3,7", frame.toString()); } } From d9efccd000a74dc3a2bd74bc0dae91b1e4db36c1 Mon Sep 17 00:00:00 2001 From: luoziyihao <wangyiraoxiang@163.com> Date: Fri, 31 Mar 2017 23:12:54 +0800 Subject: [PATCH 093/287] com --- .../java/com/coding/api/ArrayListTest.java | 25 ------------------- .../1204187480/code/homework/parent/pom.xml | 9 +++++++ 2 files changed, 9 insertions(+), 25 deletions(-) delete mode 100644 group17/1204187480/code/homework/basic/src/test/java/com/coding/api/ArrayListTest.java diff --git a/group17/1204187480/code/homework/basic/src/test/java/com/coding/api/ArrayListTest.java b/group17/1204187480/code/homework/basic/src/test/java/com/coding/api/ArrayListTest.java deleted file mode 100644 index 95f0085b66..0000000000 --- a/group17/1204187480/code/homework/basic/src/test/java/com/coding/api/ArrayListTest.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.coding.api; - -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * Created by luoziyihao on 2/25/17. - */ -public class ArrayListTest { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - @Test - public void testAdd(){ - List<Object> list = new ArrayList<Object>(Arrays.asList(0, 1, 2, 3)); - logger.info("list={}", list); - list.add(5, 2); - logger.info("list={}", list); - } -} diff --git a/group17/1204187480/code/homework/parent/pom.xml b/group17/1204187480/code/homework/parent/pom.xml index 7af48c6fed..ace9bf9cc5 100644 --- a/group17/1204187480/code/homework/parent/pom.xml +++ b/group17/1204187480/code/homework/parent/pom.xml @@ -92,4 +92,13 @@ </plugins> </build> + <reporting> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-report-plugin</artifactId> + <version>2.19.1</version> + </plugin> + </plugins> + </reporting> </project> \ No newline at end of file From 64c524d64a4713bce3d9c41102ca6ebc52a1c8a4 Mon Sep 17 00:00:00 2001 From: Korben_CHY <korben.chy@gmail.com> Date: Sat, 1 Apr 2017 11:16:54 +0800 Subject: [PATCH 094/287] 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 zcmaI81C*p&lQmqnZQHhOn_aeT+qTtZ+wQVmUAC*b%)j2bGxN>8@64Yo^W@64;>nfg zWbD|nBO+5l8W;o$00062fW7oo0N{VzAOS!CWJOg3X(i>v=s(8+02Kby6as+l+w|#c zNwVhK91suy0OkAnzfENY<s`*Kl~w3u#cX0b;eZGcM7@wc1C*d4sIgs6b!=#=ST?YR z6eZDC`!t@P3M1k~Cfc1Guh-Id<l+<D;v1p_8>J+q&~~XcVMg@)Q>u853k!`i`Ur45 zyu5Cd37@2HgH)`Wy1`l;*oM6)Aov<x>I`MZ*5P^GA<XNX?{Wt5SUNH67L0z6fbc7T z?_w;3Au;BB3E0_*N_x5Q@-;KOuC!CtWXc+|?mCW`3|5G(#Hg{7CT{}%*Zu$iSpRVp zAm975b2Ov>e-{5dEZG0FFgLI<ax`&r{vW3Qd^4nfni|<Tn*9IRqy5v~!q(Zu(bmBF zzpsJ#j}PnwLYPGe3;=Kl3IG88eT|Hyu&A7}D4nyrbBu~?+#Ux)xA?dp#gv8CctbVk zq`{Lhk}yq3aC43+M=A1xO~g<&3Co#Z?+h4=b(~rzG)CIFk7`88_|Lj(OfqC~hvbgd zxVfIL>HB7%e7m@~IKQ2JFQMZ<9=GfFm*%A&yCZ2FhNHwGWyrhp(buKg?hqDS+*3t9 zd{fJ?i!iu3WWuibV>u(s!C7Y9Ec@WNo2&8wt$(Q78NE9faKyXMFZx?z#3g=W!ggoW zxBju_^2Gk#d1;@npM{AJMlo8%y|Ejj#qPY!E?ZE}{zt!8D)Sevt(Mlx?wUpBu7Pd- z+&=5f)$cT0MHpK#AxKNtLgIJ;1o0;w;U`Im=XE0^FJ`(EW^RqEi|ti|O73QiforP# zZ4`hWX!GNBWxLS!_Nha8kt+qvaywJz^&^fC8TLt%rr#0pz;rRNvOOFu-M3nI=avGe zGeQvShWz>WK)WN5I{5e2?{Wf-#LUiZA$BZ*U2cs9(rD%v`A}Y>;3#xQ<ZkIRzAY=d z1*cO@zUs5aA5byA(mNb9lPteQ&UGl1mZYxJ4}$-wsmT-VW70kqJIPrz|CX+wW<69* za3~K?!L*g89d1}grR!k`nWiu38~4Gv#n&E7DU?cFwT1>{>62Eo>{k^kl!@X(KI9@K zP|&oX8WJ<-Sx`mN@Uw|3vJ}OpTfpgEQ$i8C2HuxCnNO<j8!?|KMzhdmklfI+r5+x` zo(PtLCS&8#_Qy*e%5yK@mpH7V;KQtTB~8<N_tT-{RB15jr<Xaz%TFv@e{0X(gIGqu z13`l<r<D)kzrn|GP2VI}R~Y^(zl9JTUk$BpFRcB-hYAf=VMuFA^$y|_LaNZCqIIt3 ztgfVj)}*G(6B%FHR#D;mKwXL?&!44X00uHB&>7><T9yjl6e({{eo%|5@a~IulK`W_ z^lU`1R|RYR^)t~c?#u|{g}iBk^NR5Z=_`Sc_6S%}f_CZYx-S;tAxD<#r31lAuXIzL z8om)ZlK+RE&<l8Bm-RwyKr>v;M|S?XW0&?ONp#Xsq{bsj*Uh;RjX%<g31oSR2aYb& z=<65se*yb1B=r{+DpG$(ME~!&M)Xhg2^lz<h?qDTIa=5|TiDss8Ce@RIW=p%Y2z$m z`hugGYJj1ok_1cJ4#k_W`J2nk5rpQ?X~<X$DhVku(*Rp{T<l$02U|ARi&dAW=`9vE zqk9!pcZ+DJ4gGwWSF^Ht<MFvu{tEqsZNBDYhT*PT`ze11e4PC<?dH*Y?S1?<eYg9i z=Lao-{)sx|@(ZLM*_G6lpmH}j(rfssDw31Yj}-#-DPrk^s)y_doQ3D--Z_?Bg}cNc zdvIh}5J!kO3s1!^BkZ=ytvkX42kmMvst9JT!fkP6S)e)EvfQpk{cB6;HN@^U*ex#) zF~tnnElv-8@e%bckDkJ95JAhnsNjnMsc$fT)Gj%d9#V21)D%DR;0)`#&|qMwzU6aD zq<*El=CB<~^3za~L#Mi+MX`;BU_L*qEhPl(P||Y1#eI4T9@8jNaWJ?NBQv9Q>HgjZ zDcD81yIB87fQn~>(|C4lNp<w^_LWHucI^xeE<U4C<+0yTfk%_kDLD8IrZ%9s2?6^@ zkd4d+WaQl7m(Dz#?VVG#{q(qXB|7fS>49A0PPu*kkf1B#@2_ChL&1Ygu98+J<dY() zJvI~-LV_hm9;>^LoG$hkZK#b=S&+3y>I$q^Pesl7%RmMS5C%3|Beac-R%1#O@FxO1 zgA!Vxayv;1V*Dj>CYT#C3woj>nT!jiIa1715Fwi6L6eK+)cMN&Tz(BxQ|^%LTr5K$ zk^Rrc^G%HwiAcP{>{ZKiZ<@NrpM`v~-eSWZ$sa8#XjdrgO{MX{fuTSLc!5`kTVoSg zkx^J3fwyDpx4}j+V|NjI`)N0O`^5TV&nOHkC@tDhIZ<tm3eiQP&~Z2W2@~#xX$@+N zn4~oVPW0@xg^sIEWB94mm-A(fYKtX~$KD!p(9M*t5+?jn8Y8BZ&?2v(g00G}Ne=dO z7FmrK&}#=GRJ=CpEuyrf^^}qKe>TCD*PJKU(a}w;ry|kT2x(5AaXMUN2y6CRpK%|^ z8zX`PGgBCxWr6}~wM(DmZ$S+2^~1@X-|@^qkVAw$29(R2s*U(<$*W+veIM?&1gJPA z&jf1a4fTmkn53m2AI{uCYb&0EV)^%2xmcvmVyAR)RO^<|r`!`65={#m>2uhQQ>R6q zQx_b-V^1_t0Pgy{x}^j^q|~2G_ahv3mo>AId%ES4yqvQ~v8lEeZ_z%B_ieJ3Z)0QK zZgcByNKyTkZ_(dX1=S6VKZE0a81awaxMFw1BjKIjVQWvH5&YC=RY*#lFGPD|<8DG@ z{dV$TrV`K?NrvOmfP+?bE+P)Njmu~#HT>#nOqe*YgBh(ThQp)|_Fic28i__O?DHtS z4;ay#B`2=r(=q4#h+nQDB{wf80Mq1S%nkyiP{Y(WV@p~AV#*upqgtb+h`}c<5-t-0 z?NT2Dulu5m0bZIZnVAoH<Rb!F>)2|uZ>`B`M>^)^ew$8l6#^Z829~mNHxDT_>If7E zVJZSK$$4y{Q9kc!rXpDH(YAKf%!_SKQSzA)*@R@N`V{}zz}8bbEn+T??gM;5gCjXS zh^u<?rjpkflgtV!)4}n{+c6_}1=fC!+To&D9mZ!{%GR{w(3`21n}#}OGC~}u)=Az0 zi#<%#i204<5(dcIme3few|M}yEpml4U4b}NFvPJR0Zz&(Q@~Yjm@{}(fl$eNl9cKZ zpkv}w(-8U70j`8pqr{eX80&6P)%}dhp4m3x>~U93JSUN$b*BTt2fqUm4q*p~FT5wH z!9xXmu2r!m{0{U$Lh-o1|EI;6AhI)SSfnTj?f_6Oq3|J3W^^WA{|^!L0%)^ARi%AM zTXpnxxUoy&%^J!kUFz0O%vO6imp|qV16Bi8gXhylzQHo*=yUewfamJtOZSm8hre*d ziAQ4~ejr!WVOrINRH8K*Qu{UN4F_$FD6}$BZD<k_V~Am2g$6*1Bp~ox&c%Yy_Uq^5 zaKu!;Xg5OB?_tsGXmyPxd&E)xL2Q1{V$_X&2c^G5$9UPmxJ8=N-3-b;RHrl}_C$*@ zyW)sDN)WZS=lPvJSbAd$_rB?f26J1A(~_HjiT0y|rQKIm8n(Om!hr5kawAKUx=cQA z)L+EFodO1ZSn}1~-wSA%H<@-{$3(=fi5+BmuL7qfqA%r$^toE;RxWH#Sv@3(iF^1= zE+ftG0klTy@GJ_0WR>vR5@KAp7-qtVQv@q30h)M!0D_ZYx<J(c-&zCGm;hel7ckPD ze=rXLA-qJmskpZQ$YCA0akAe<CtW<vb<nIHwSV^LV?t;j5mA)6Hss+n4@EOxvKG8l zHF(K#kdpMExQ_zJ;RIfCrzE#)M0ypF<BCaC#3>-={x%~$*|j6x@uqG^rA#UV;D`c4 zTxv57a%R2oCZ}LDmAB1J<%hx#^|gV~FUIvWsNA47P^?iz-xx=i;F4>KOiX_Y-Rr^+ z-Ec`ePh78D_TT?~PewAJJ(R@>8<wDXBYh;}=_PC5dz<SH*iS~diz#7eTd0mrLtrbM z;&g6s=g}#o@qXVvl)^71(SQ#0W?Oc!6&UZdA^lmFvX7)%6xNQYkC+ZTU?_B!@kle% zk*b|@*FMj8USYJorYAN>vF}Jfs=4?hmcmqX^vdX=V_UfBu)yMBwuy+6m_mU>2c@>7 z+PLl1WXwrH4SkNh503CP;up1p17UO14ZUS>Z7QorCE`_Llo+vhjLss~uGOIsbEfxC zZiTU1!R5K6stovuuLs0S%G|r6Dv7xIE}m&@_e}CPkj9ttE-0>xU3}9nGvn(H@iW;k z{J*Cf<)rvf+CTsR0^dnH-v5?r$Qn2snVUHNm1e{!>pIN~pzuOBH35dqYgtr(+#s(* zsg0udPcOQ97rKaHcu&%dL2VF1Ceir5Q~S)n?!e!Ob8dNafEZRz+FzSK<vPveX1%{Z ze1Q7{^DM;==YVcb?c!a%?FNK~{WMmbGGve94SgwXD&aDgP_NJpovb&43Kf!G-?O%U z2;SK3CcI46itP{6y^{LkT%Y_IaF4O99lKEr-)7P_p!|@wiCm_G3B1dOp;i`<C+63u zomQBcBex%)KjXYmpF&qXr=St2HrHNrKL41!Q%c82Wsv0wQ^jmfZg>C{L~X!S)s49! zrBz7HE9nzwy`iWhIr`{rbNtR*3*Y{`R-R$8-5hGh-b6lIYUa)Z^DIT<_I#_ILB;45 zj2zJPz=<7*z62@tS_fz}o|$|Y5_n$(2726rT7BIoG)0P44DCv3*iie?re=h$-E;GT zN1l!6J?#<mxVeSd74}x@HHd0tv-*X{gGQ+6&1YxJ746M~M~F6#3(w3UeiSU1A(=jl zc5X_l!0SVHf@Vx|lQAYvjO7__Dz89IvO}qRd|oH~>TXwKvX9uUCfH6cCj_=^5m%*j z*M`v>9qnGo2C_W^cXFXsYM~UKT{r`$G`*;dcs%-U^GdyrzDa^u-hpp*(LTnIkEYKB zg#x|IHI;(CKqTeV{|fZuqY-4uF*=g;r-n!~%vUQ?fh`DmWgDgiYXXtnz-5{ex<px> zTYwCd9eFoP1;7%z0^F-j*n=X!pX!L#Y<;-PX5m>xs9|xy9Jed??lk+PPj37Ch+lis zfGI+&M0B2;FYw>p@~*f3Pu{mXPJTcB%`JuPY>h4cmHUz~{^gc7(SlF|3<#oM=FM7B zuB3FjZEW{2qWvLlHz16#Hc~PK5qQ%f;5Q0}kvrr3llXj-Z?#YRkoh9HM6wBp4UOHL z-=bc6psS%&O;EG(@;L_?jhndXVVp%AQ%k!n9Z_wWwdzoPw;28+%vuTv;-w$slxnIw zEmz@QRK{tcZlNTJ2qE?B#Sr%tum@{IPzF-$mJCBYZ)9o@{-HeG`+w9e{w2lVS9d7Y zzh$!icY;syPsIJdt^I{N<G(hTqPn59pn#%VMp>LJ1x-cd-Vd!YZ`t43v<E7x*auEE zeG-JcE)(&c6|!)=;`cnm^PNP;2EqIK;~%z7OGcn1a`j|4KCPuSPj9`E^!k21L;ir9 zNyO-jAxUiG6gW-QIRaM{u|R08Cn(_#N*~e1eRAGJmvGl!4%OUl0TEN%O1GO5`t58P zVwPoB6{(Jbq0wp;dur3^JUecZOM>OvY2cYc8*rOas!eU35ff?E+&utXsq1i=YQ~QH z`jBQl`iKSswH6dn1Z>6zvKKW)bvsYpVpMIz&PLm6ZM%#*Y&u+JmtI5rFm158(XavZ zT0vr>3aT^_Yt$a)()hc@JpBSp+nP&NTPWumB>vpoZR@G}_onh!IBh)%v<yQ=$?TgF zq$<lsIpjgZ?;2mG*0wUa^IYkby-8`ks@*KqsXB&J!{!ZB8+~MMP7pGoeb@Gx(8k-T z-DH-9@-q$N%N5>AQhQ=-RdNgZX%P)bJhv*h+`h5gTcCyRi;}2fE#DftKNa`hpF3@| z_Xkhxe39monl3yD{(X0Tu+AuV*_n~6oto{FV~2ME=*=tIJ5uF1uB{T&zFtY^Q#P%J zv}=yJVL*RKGblm~qJJG4Km|#Z#EXfIDnZ5FXpA~S$=|Sqpq@5HvIZ!3>jRUsYz7do z7JUL4DYhONi?mGB?<CZ%!Q#Q@ea*$&j$z_Oonc6uwrHg)(^k%PCBu3Eck_8?R4B1m zFYO4gjRrqF0ZD&7QAT^Rr5~E{j=}rF5I5Lmj|od*7fz!o#VQ-wwd0jOrgo0-8iikn zW47DPM!&NU_1?$~BGwQ`1DMW&2W2=-CXOoR%Dg&Y3_A!&^5rIzD8cL}i?_e&AqT7| z^qql}BylY5-UVQq$Pt@)hqMIsVDJ^ve@1BW^ag!m=ut#1y5%ptDEB!gzxQq6@72=9 zP!IJ)($riUSc1sFW*=oJ%wuL>8h*bhS!wq_^^j7YJYn{kik|204wDxeJocCCmEy16 z`4~C{;F~hUYKn7PBLmW=1DI;mAEZ!7%O`W1P&*N$`@-Fu;H#qqHGQT7OrOqt)}7PL zhz?wE$UvP(3DC`w7dQvdH#t1;#WmU-^`I*|!zi)1LVpFfSCrEvy9NJy%ppIz9M<@z z!e8H1NdA8VQ_jx$Z`ce`7W@|{ex{OuAV8~Cr)b%rQY&cx<mE8J$hI)cb|`)jSP$~l zBmh1Y7zo}u@w>|}<HCCf{G=Fd%}Pd-F^7BG+IZS}@_BRpb9`O94e(f(7Z520hSd`C zq%#^Ds~c+k+ts?aKR<cA4Cbt0qZz|dcB4L)e6Zy(ql-5`=dg5RH%R$vjR=liwbw2V zlWDZZZ|FmA`;5tWn=AGZ7w*~JTJcJ9;lXo>58su?>Ovh}x6JCT<s60H3nny0^S-tS zI&}Ww(q(}KD>wlwa@ExnX2Z!wu*8gI=GjaS*S<{M<^?YW>ku9$(>j@`FcagxfEDjg zZuWp51dLUJ4|>BqZRfGQ-=3lut(Lk17OmW_oVs|5>F>L0#KDQxi104O*s*ctn>mSC zGao{b!R114pRmPD@;ht%bMo4nU%uOXja)r*8Wgt;{Bl;hrY?&Z0)|F&k1)4}$ofBP z5cCJ@^x2D4MjF7MQZ3q%YmK_=hnaOUOWi;f&?HX`DNRpTJp1cBE~!h7QFVo{&H9@# z)b{1XkaDPRLX<9k7m4|Gf!&r%KwPq{pnO-w=He5o>YPY?<I4zW4cj*aLYJ)-0<blR zva;63gg0ktX^><4-b50F*b2O}20dx(*#fP@NxL@Mi2p!t4ntJ~>96Kf@mF_<t5(kU z%Ig816BbD({8aN3df^-OAm9XMaTzb)Bg9kWV^5lpcfwXKo$3;x3T^a6XR=6fsyk5x zwO>z`8dSCpQR$y;ikE_<%q<|X!DJspGuPKqN$p~7fKRmGK|@cI|M&+X(mttr?tVLE z#do!v@c(vBWoHxnzbGR|j?s2N03jRH$Os%lHM0q&xL*oen}vWxT7qs8obKoVhso^x zDm=NiWCzegWeBra!oSj*nY*!*`R&h}56DeqeHb`Au~6KS%ZsRn><ahe*g)bKk<7Lm z5Bpq)lIU~)WBcBEuyl<RsU<NLX17ipTFPeRAO9V*!uUxX6!M`3**o|&_areVE7Z}k zjSqE;D7M}-2thSmm1*_DrrPMwO|z+rF!2E=uXhsWE;0^u3=$>BW{Qku9psT#!Qe7i z>@<Osd`d?MU5?Zzn)ANqi+PWeyt&a?L;oYPzP<<fzk}Dq$r;h)n^h?x0RV9R&-3|D zHdWJBUQj^zl(R_EBVtEv-yWWa0!3BCQlub|2vCF~e%%R93}CQXmkcWU8UvrjOi#e{ z^XDITkVg{I&Lr~rl{<0e+qr$kS?2fo`3n03D$78m4k0u+gaGS>WSBpS@RcS)15S7d z8<E-|xQ=SCI-C{J0*pbTvZDs8JX?vXoHX=CtY1fc@}i()hJcG0@f_xpR+*MbgpG|k zZ{?V|Jf%c5bl16`Ljs5DrK%uxQlujP+NxA-R=j4D1XD<RJ)kCiG<2N7sWBv*PpO9@ zBD)ZugzYJIu__~*m_D%TG?R0576Esoz+EZC=WZo=+1X{EqqhtT(}Z4}y82W|ZS0aF zbmVxtaGPh5q8kq0*>PLX;<4J@V*T8J*o;X{r=JI2djTF}Z%#^=n~+#DbvD%^-qP`c zc+l9!X2Z@V2~4!CV^XAB;(%2u)`R>-ax1sG-&WV}jsrA#tu(z0XJVO7xJ>+&=gxmP zQPhbRHS~(hnBjhDKk}^%sFJJMT8|Q~TFX6U>L}dc{>!nHxF8KTqQ)H8wd_zv*0tNC zF$wuk+ErT7$|ZFS`jXP}Y$TdtjzXZwXlx>P%k&^?T9-w0qH+SA9e^bVRKjkzxM7pW z+X-Fc)x$+cISKzxPi@jlAoWTC$$|BBJ91$&aaD?^d!@a#@sddl{*~CuK8SkCY=9hO z5Jn<HAUM*xeO%@YF<2RO+Z@>7P7FG>`T@JFjcDl6nfd9!om3v2OwOl?Mz<>YQf07T zydEOtd;Q6Qcf5632K>`0>#f6pc}bMok>q?<puh!Ak1`fZepXLl^J*yGt5ge+=bU&$ zub~OR4YOP~G=q#&MIbl6DD)+NF=E)8z^4yMP`$g=Am;maB?33?kgN8n;6V|^h<R_X zp<UnasCIJ)Auo{=wsknk8rq>fGl*;z1D6y7NV-&i2N{(gkaTF<(#a-h10=i$Y-(|b zNhi;MyF)~uP~|iA?lNfdH;eV|;xLY13DDu4^&H&dbzDOQ4G6^PBh1i5ftWmQLQT^B zPkI`eIHoO_T^2b|wF&o}sHRJ(J<4DR_M8v`BNI>nWy?d4*&AHM2N7Sz(7~>huQ&1# zWvUtMiLtng)LktHJegHP@4>i$nL#^#?wMmn5)C27)MK4OC;vlc{;O3bI`dxC`VGw! zS^xn2e}|`|$$!dBr@s)oqzUPbV}k0JbYYr!YTuOHQcv6BpIKy645ZZnBFvRM%u;O& zN2r!<O*Yn)_1oF3g)Q3<u}Uild|WXfTohrk5C}0vy6Z-$YuFQ?Vhh~;@z`ry#?-Cn z!!&8FxW1)#JIn6a>-y{S+UMHm&(uN0AUq!kKv};5sM>%y3J1hf;xk1=T*5O)#GAyX z{2n0a$SyJo9?7jFQXbK*1rmIMyGDTcjv`VV<qf90PQc8-G0HQKcfb(3B#+>pG?X`H zkI-Hvls9ZH$*l{Le8O`m&~~sL<&DiVT*Nii4ev8wL>cNcAP&*3FcLq}tr4g%5I^ZH zGpH|Iufk5+4K-+Pfd0e{HfC;0K9y;yY^P}8c*m<PB#}*quW;c0`c%_g0`?ViLyo6D z)b*s*49SB^YcA_)s~58&d`2or)CTife<`64M+PfRXE|*W>+-p)<F8*@Q%E8YDwc!( zAk=5;?B^TzrOCN?){z@xsSKItA1yVwnX2%e2uPFYm{N6p@)pj<fy<TwzA`7|Ee(y0 z?Vw-M3P}v$3mrKVME;29Je2@O!rP|A7VNFzK<OarIC{}jQnM;6)NuR^)X=~%BpOt? z4jB@4j0B~LrX{Df)yPSZn99z5lUi)r^7TR~CM3+KzL2TOa1PS54Jmb0{I5|$qWEm& ztD2h8&+C|Q<?r_5rUaYul0UJ29W*?~gS?qBLLZu)WD=(q+`zI5Sa>~CNNT@O{^p&a zgv~Oa*p!R#ef=VsJERv<k&l}P?y{hQzaim!&(azLpbd*%bYi(S2|Osx*pBfjprOks z%qf8SLAFxCfxK*Ov)J>Flim#@L(R?o)tc2rZx)A#%bBIdXUC1@X0D$KkNcsSy9`y8 zHBGshR=%4twOBl<E`R$lD$c|Re9btlLga(#B@wzUWpAi$+BPGzz<jFHb-X8$KeAv! zypcLjJJIJhFCwrkntK;svs^BOFCmPVYwxC{z;Ss@j<GLo$N}YYW=~Tl$Z*72%Orzs z_v?n+n{?{j@}efKp$2n20UoVepG~^p?fobyZ^2GutZL2dzLhH^o;<Ox(bSV6|G_f~ z6Fiqj7oWH#Lvmp>jR?IBY~x-fR_Yc6kO2>vjNdE8@SJ5NnNt2<F{Xa%SL|Matwx}# zvi4_SzHHN<3i6YorD2?h(T;%&Ro(tFojHT#)1)k@*PbN>bi>0!Yt477BU&laQprGO z;8ZYjX|q=1cQ9S7x*i6mmR3-3w0d!IhMIO!wEM%*PWFJ>Dps)uF{RcRU&y^Ab>jdB zi@lW6B`QJIo{UvtjX@-u3TToZq90Ub1PhbZEgM7utA)N$hq8F{v}L+PWSv#;x;TYE z(|#*B6#KuMXvCLnNmdzRTnrvNex7QGdTP3Xkmj@Nfbr;A_SYDK9v5X_=aYVnk1S{B zo=xshFb5{x12!T-qje6*Xt(6bVco0o_WpdwUM;t+n3`v>s4Qk?vz<KEp<24MmZjP{ zrFgbD9TeLv37$dKo`J(MX9Cajec2c#W46#1Kaxu!E=)OZ+;s4;*`aEP0s3uhQ#o2Z zL#f(k29v%~UmWfHHN;EJ-giYAAw!qNGR=G{{k1vJ%UVTbjH)J>1k<a&3&W8#v__&O zSw-vs81X>DHhu$+iZm-(m^Bna;wfoO<iH528_Hi1A1sL4BA^w@U(NueZSvd*Wfy$O z^e!4QvEzueA$g%-Kz<RwTT9giyCr9s2IHq}5bZo7am;(8hh#Q!lMTh*f5^mBJ7CMy z6$0~BGk~YGA<X=xU_f7RQF7|TvM$c`rDDLpi%XE>S8fl^`O*sIHuu0!wF%ov^7Fx@ zmq8v0X9hhL#A=)mRce+e#t1bRA5`4wm|m<9^H_P2Qu&6Wf8MaVIYgWtut#hZ-Fkd4 zg9D2O@we?muAocdX^RY12<C{BPS%2eOtV^X#aw8BxZj*k*N+K=n^<k!#lxsz=G8Mm zWylL}$W&B$&gxU9kzev~N|Gq|HUzOpEsQi_sC7su`ot28<rMmny(d(=tm`)b5>I>i zKyt#G!?t2SSf!Q}{nPqS-Kz^8#b}vqAEHMK_6Xppprhk%F?(_J0#;aixXpH(GuopK zuJ=L-{i_cQ&>ib&MeB~;>uQaywRKl*yVMZmg!ef_+&2$l+yaUKkA<+M)ljR36NY#W zj#=#F202GpJSJDTR#wo4YKAH|XWI;M3cDJ`j;u3^_BfMt%~-hb#Zf11^rZhZvB*mc z(}oFTBewOC-jL~ZLFiQ`^o=|G+{4W7$6(>$!V9vD6KtOF7pommB;8M3S>f@STKHaI zA8^$!qnA9>mfq|G3f)!1Rc(xMjB{5wqgPI2Q%9w5-6`?thYv-I;BZ7S2D?g*G%a)g zT0&FdR$!yg#nR4sfBlSvn%LFC#tpN~waKoxak%GcsTfszSgpX*UNVs`Qs1W-cRyxi zffxS6@L!8C40+(n50Gaa)O$r(d0xaq-cAhb*18r{Ja=Wy=HJQ<E&3A>IutdRoIFAO z7R#<PC{}MoBNgmFTU2vbmN6?Yb7z}BxJF!*?QQS}8@ulz7F}mpEZ-hz0;5E;Ug~+C zT7y?7y}H`pO+UfB@pd6qX2nNuYes~4;$9g*cxIt~#2p*h-S@-QLo7dErQ=<g1`iWA z0Jze@ck+W+gC+Ts+oHFOt~~s4-+A-a%>#`xQ8lH@_H7|NcI`gf!W5c~h_)NVxY3{w z-v!xP+V8;-i!#Irk?z8v6V>pRM(CS9Hpsj0*8@~{tW)3VVFvU<4MMHwO$g&<u^92< zS!HKl#WkN9q}wsbd+67TLA?&^#;WN*Z?;CoxoIWh=plsUpg-u(%R_R<L(^~5StXSL zmXF=93s)!sS{$qy=1w1`TPZB}m$($X!4)XM!bdEtz=?Mw`ju{Ppx-A-y!0wiL#?%X z4u$rp3!~Ol7v-_~DmkI>=f`$T#^{PX-~|$%YYhCOr!^M;#lv%chQAMg5Grm~+FhLk z{spY)#v&}}#$rr*a8__TZ$y~v>km7+@yjWlg$p#a9cT{?YGc4HqF~*TK|NN=i)y?J z8;DME4af<P)%tka9`W>zB#%{XVOt3=QC)Yam5})yP~A55^cH0gqNgyO7#|`c`n?Dq zH38$i_+L>TMDigd4f^RPX*YGBw6BkaBHPoXul@)vv0*-BBp0{?y!E-;$a#PIee-|F zcOeU2AqBG76QF*wzri~axIqhIdBl70#d~=ZpxzL&y)wY;xZuUU?jkbeqba%LhOU1B z{aunRWE?HMe9P7DZ&^n0Z#kcfle3-8-<k_P%DQ$)f+)O$;xFs#Xf{zFK<gDKiAea~ zh(d*`$VnCO)(m`b6Kyh$lZn4IgZL*z7Jf$XWj+^0yP-AZ?@i=*9bfStZzio>^Yi%t z+M|<u7}uxu`=Wt+kSI(O21x;`;+Wbe_cIQ@T5%!<i4!>kaW2oR!wmm{{tRX3t=TkH z2UlvR4NYlLQF6mzv+`?|_k<~D_9MVpo-RR}DN@u2VY~Jk=zD>C^5lsx&DAZvR|tji zI`-XR3-dkzAzGYjq*(ks!CaYE01?r`m^@$C0`cVj1XcThm)dC2#tj^oFL)hz#C)`h zLUuYI?Yy9|V?OAZSJe>*WZbsecsjmtpX)`4wRJ%o#lKT{FE2e84<OF{wVDswUj{ZU z1lWoJSDT;bnQPzvL||W(pzwM-gvhKt?sP}BI~&&}SVB(~Nrmd6xAa33&GDC+{l)<9 zqIv&eC}VPJxtYXrG;fK?)vTd651QqVs0dSzj}>K2Tbl~0T4rhZG#W-nN@)eTGs+sJ zlK5ime3f1hEAPQGGZH=2q%;YiYIZ(?k62Ghoual7mSNoDI;&5B0q#Dwag8W1MzH02 zz#+|qHjEl&+w{_IY-igaNj<raPv+y3nlZ0l#r%e(0cq;qFKuojT5-o5Roggd4%YPc z8qBdE^%?F-i<wSO<bQXYpZkG|@852-|Lryu|GV3$c-WgL8<_r=X!uJr#3*Z9Aq%2> zlBFHBG}~Cxj}+Tl(zgo)#bqMIR}hH!{6e~QXvnZFwKg3zRok0EN-hlKgZiYny&zi! z!G1WL%;5Cux#q?<^Lu}PN9_YvX_P2R7ov;_qA_es6NEB_Gr=jf=MNzcor2~>4I(!* zd~>WSDZ{wSk^W3&*Qv=CQ-4$9lnrf8RZ(iibfxl3t>g_IYG+4)!Nx5gn)tDZ-ZT7G z1F_4K)yaD`al_{)b5fAafaAimZ2|N0>v33weL5)OQEa)h{^Sn&Hqgq8!kcIY7VY7Z z4tRdWY4*%7znP|TjqKM2OanblT!D(_l};UTW_4Z1Wc;a=xC8EU@s7cSXVZ_F%FmKI zm&WeR9x25YXm4$vq+N;-?BTqSSujTqQ;x1ukE@P>-7BMQNHL+)GG*<_YARX@R&fxE z$B=Rg^?>tKVUj@sur(ApnCwEKy04b_g6CEbjJ=fErVrKJxu5^xKoRAp9Gw;gYS_6H z3vgu?-4=~Pr^&+<Ws(#%3$lcA^nJdUP*tC}=lTd<Npbpwx7BK2;Rjw7!wyk<bcrZY z68R$G;K62walWxJKhX?+AZrUGA4WtOWZlJEsCCL7qq&}(W4gt44Dc1{z4;%IR}J61 zX3}FX#Y&!!0fpUW4HCq5lfoHIBNDeTYzY!_U4Q-~@QkB3KgN6)a+AJ0EOh_$p#L#C zMIz^7ZT&x9|K&&3D*q9Nx(Ai=QEWoAqO|xeE1{dKsux8Fhl(xdCDvIG^j=wJ18f_A zlQs$$#rfPmog_uTe**X=-%ejip=qS1-Z0_2U2#55X2kLP`F()-<E}~zq3DtRAcyO8 zaK{ZJ3eeDGcTptF|Je=}aMI&44nd>ll7#z6ml?fcvCt>cVcGn1E?+0ji5>&htRrSE zjCb(4?*eV5Q>ax2s2q5~*n2y_Wr~4Nzu8@!y9k|j+PdIHi9Ix*6bN(ulIhPPI*%o? zdnKIXV)~q`a%RUG<>82$z(~8a<-Nj{76oWPv37gKMxcOpb?$<61?J*~IcvYkI4m)E zpo7ICh)YYpjzpMv8^q*Bl{6<R+9<M+jr)&j)7iztd?^q$F!(d8r!NCk;JXR!f>f2_ zz|1Yi@)L*RXEttmGBvn|N$zs4x4;opAeE59qJe(eHWJt;N0>Ss))`Id;KpL{Kev?6 z9KXGWO7AZYLLHd^0XEMhyJK?{YkIMDYh<WlIfa{zgWzxk@A!15RK{0@3SN;09B-c^ z7j<SkrI)Ml?CRw^yg8-$oCV3s2*4bG1O&RTMnh=^v&ibW;9~Nc1N~Ti;hr7H>qb3S z$?QuF;z|tYzL0;x<B0sg+ek;=3?XTuWCujsVUtLRsyhhS{(+y6{{BRGkQ=1qpw3&2 z^E;qPnE`l$BMHYwK6RqtnL`Rrd`|blVN+CZFZ$|%x@u3tK}@qPPTOa8g_anevEe8h z-{69gC*$YW2gZkd&N|5Q?wUw!oDuJ8-vjk(@G&y)GfxRPy%>+e8{Pp!iwEpioY|3I zkG>bQ5xv32AKQ&iZz(P&YrR3Y2b5ZO5Gc9Ie%gzqw$l7I6yvY|9tr+yE|8C(Yq9M+ zG=lwa&HDevk)`E{1Q9;55)k`AT~u%C;UE0hL>k0X>>XGc3GIIv8uG9T53*Tc&odi6 zo(+E)@uZvYeYfi|t@_dvhHnv%8J1K}uN6<PIy!rMKyR?m(RyS9cfF7t-s^4_2B?Hf z&!`{7+hP-V<y~2YUj?iTTv6S0cbSGNo6qnD4NI)nhkM_L7zZ9A35VbYNv<D)ZP)km zM(Z?xIzLm=Q`Kw?cbFC1UR#S4n1P=t)Gr&ZQt^x~hFHS3u;`h{z+%9+-wnqXXcZCT z&|~F7_EXQ7<PL@BZYgp4mN_=iZDe}&5N=c$+kL^)`z=P;h)cKfN#IoAxDVWfBFzbz z<*lzkydX7e#XjD+8-Ry-eMZdp6475$*N{oYCTe+_gw_v?5O#O}woS4XDkW<E`AQCJ za3K)#zS7y_Fw_H+XdQ0Cd^4orE@|R((q2{{>Wzgg!E~SplrVJT!AK(IQwix9;ef>e z^Wq<>rj`vu1gaooRDs`1Abbm>DYGz*xsEzWv()(fnmnV(hd+)UPA^`?;!UAnBz03_ z+ZS7d&^fd!s_z={2^mRHj*<E{i>iSVWP!daP4M-Pb}_M6*xls!cRu`0hyT_t7O^le zv$b=wur>QzCY6#XEx#dvF#46n;c(Fr5}c^CK0g}<QZTSLD~&9A_6H>q7%>GQEk=_w z$`E@E4rx0A8b>Pv7~daW)x~u`k&LqXY>>yzmzn!K3txQ&!1ZQa3{akyXD|~Mct&<n zrivLQiz(S6im<o7eddREbS%iAkalPxGt?{5)$M0IQHtxq?Ji$j$z5Z90-W)Hf|Ypv zHJtm-Fp=bM`NTJa<X^Mfhvn=D4nYN6y1uU8boYwiJf&AVN92!bp4UNZ*A(|c=@!Ow z|J(LU!`;H@kAG-FImBYVlV<2Jae{mOMU-xaIYQ7I_~ax_#}P@2;;KTYCRD@THWEyw z8~TSEaz{ur`A2+NQM&7&mNhSS{q0OJ@12PBwUlo37(;pQ1k3)V_7q#{;vga!WO|$~ zk)?hhJjSYz4@wNRt23Ug%=P%WQ&&Fh^ZOOld_G_qR&q_EYhDYn4uvl`S3xm6w6Q|C z)E`OCBjEONG&`Rv2Y{zcF}>-#9V&UmHcPE^32&kAFEI0Szs{Z&LRHi-QOD(XmTA2q z;hCQa6YealUYD_j{BokLtn@N$Rp;K<pEqfHlW$X+t2*VmQbuxMgu8)WIIGNGFe<h9 zUm*XU996;FQk;KNn)kOyVEvQY#0-p_?HoP+qOlNpS?NIm1RrIaqGn4_dZI%2leytW z@&ZcKsuYZF_w`Uh+qH{vQ{`X!fBrS2Bgszmh-Cl66t4^3U4I)t51_^YWtU*UAegY= z%a}UtR>Xn~hK%XY@{+oAdtz`>F_RwZd!bbGthZJ4!#uT>)WEP$5u#S6&M$r;l8ZH# zlh9dRN!^geIsSR^N>w#*;bb2EVz<V0`(<0nl8H6&LlbU%D>@-ltzIXD2U7>GoH)qQ z<-<K$w2b}vsO{L`T{5E{4aXzM<LdgXJz}5&WLM}Z=eiH4&XW*7ECrM{+!4ChRjVE9 zaK^q*tiK=8&jLo)o^P;}e6v5{za5c@fwRkhSDXJjsT9?7S0r_mPdH{kAY|kSQmp!z za`g20e49n8bTuc71+t+~NV>N&D}P|j6$WG2AnCk*_7mpkQEBHA-Aee`u(LBhvr>@E zgc1JZhMCr<&&RFpK7GHhPjdgPpRq<rZpi5aybe^6B_yeDkXmYq&uH7Ew*c__8mMWk z4w`WW#Ie+n=Ffbg_=c;-5?Jzh)n6U;ntIyXCco@lHq{Katygrn9-vb99ab1G2k7k9 zyRI~6+HUv!?KI?qIz>Z8TGcn$x?lO+Fy{w*0&*1gQ7aGA^=1xXG87an=2od|5LlKD zklIE%T~@ems$zvls>_a;8-HZURVv)-OjsZ?VG>N3W(|l*ry6-s!#p+a(#VB!Sd6J+ zE-uLh?aA6|!qGpivtD7DP8|h`l-aJUE;JAEGE{8!ESa>iWIGL-xo-O3*U`H$-1Ksd z*BfID=hIg1s)E{Z+t`=|rmD(zj=E*StTX`k<*X}b+B3S%4<XDTrQwhorGJ-ge@Ctz zJVJ*GNkkho05{Sc`4(tqxYU}h4?6M6Ewywofev1b?lYJN4Kq-PC{zXRW&hyL6fPu$ zWwmuS_g+K%ai-nC_;bX)+!owWxnb|cVXV!qA+Z}_W85B(5M*wIb;6o6hc3qA$DQFt zgjCt_@~IQDRtBEhXkvKHE{zhF>1|P{MfL(i&>t+i@I$DYk(;DYTI*4T<+>no7;Cw~ znbjqQfd2fvPi=J0M+~~yc<QlJ=OxK0?}3@<liPNN7v>=#Mka4GG83%(mpIwf4l6ty z`!a)@W4u8nwu3CplHPJZ)TZAn=j6UnD$7ms27NSq6P;fc@*x|t_)2g3TFitl*0x6# zXC|-O>4m*;DP)p`1<FzqV2fN_;_;>2<>Kq~zkH&%OdS%on4G;NJEh*DKfx}5iCzZ? zQF#3zRP}j=R;@gh>?4+0I0J=-erXavH6G-arp=61yb<1j9szjVQHCc;;3beJ==Gam zQX}mgzdbwW-KAAf8E^IK7oDsmz(VwvVGwOJ^xWXhHGIO2?;#o@zK6c>{2qx#h$CR7 zYaPAg^a~CKI!t-3(4V3yY%;Z&Qnbx!pxptxdxnw*Mx}kC)*{QM`(BK5+e9GSCD?ik zIoEyOz43cR-0@ZO)q7L17r#dxLdLW*jS+Kx(ICjX#JBDE1e2)R^8^GB`O0?pl5)Q4 zPTq5xp3urCfa1$KPJwvu4IQh+|LMpkW_ST_A}@zjeeq|u>leWyTM#KZ2LXMe+#bPg z_xl6?ckr{in&{Df$HspN$bXBEf8)py#lPaCk(H6vQiUqQmw*?e`;DQfLPZ%`zZAS) zsw`8fcB1T<?eO+dKmJY}5_|m~c?ZKAnCX@mbLR|woIC*B++*FT!Nee2zjO&KxitiL zPQS{QG=BouV{IU1Sj$Q`X%i8fK@AWdl`<RhyS^5<Cf*xzMkput`IGeYWQELAhtWVn zIFn6?lo@2%MT3Dw7BpcpTdE1kbALnZP&>=J9*GJUXy@Fq=5#?54&r0Y@p?t_==e{9 zUFK?LYG~rt!K<=%J`P?XpJGGWOCGa<;jyXPnHTvlZHu9?-y2#1^YshX(G4DWcO_EU z=1z=%1Pg@B{R-$TuV{O{5FWo6$`K)?>8P%@sZ@nfC;SJox{%Zr+#bLp8_x=lJhR}^ z>eRN*S1IZrp#FZy0TQQIP~Q=D1MGh(?EL2;3pzQOI6D7lfK|~}M^eQ24IbZbAR<g^ zhiZy`wK}CTtF$<-fN#7uzcc|r91R`73Pbxw{TZdl<XG)_E#CY(ji~}Ln;FJ=?7h<6 z+i2$d@%ahdhg@s|LwF>lGeThc+t`C@HzS&FXwy9woo@2>p#=KRW;=mFf*FZ1g@lww zV%_A9%$dpW;uv0pO(XkaDvuZghU&ED%U1_AW+uxP5j4AwL}h8Oih@5*3nvUwo-qbg zx{Oe_g`U~WO_`Y6N>e(D%xadbQw+#34OFffg_cagz^B9yNm%sdheF=uUd4x#A}jYG zVf!jhrn<DZkGPsJ^Yy6XJLh^r99jl`HF^TAW=s)!zmgOk>5@AA)ajE|8*LQ^yqOwT zAq_bN3RX~eX;QT~uQNmS=tw@zpsu>qCNMph7O71_BOd#jsqqP2u`;#x6}P5SVX}BR zoJT%^srA#EfUizkueAM5z@5K3Q#ukB*qjTB*j$F(K|x!0ObAqC4a5ehL2K&=>|3jQ zm-0iZf>l8&tLEGf9+IdK=kB6>LC;rr$oTylT#~Z3c4!AzQCCx-z0X4x8Bw|h$wqH- zO*gcE!3g`w#~KuCzn3taE?`^|JrPV9SFPaQ&6H>@jlV>@3c(uchT?R|0Sv0SMmZeE z8xYRsHddy<RmWe%poY;rm^9ONlesev*}aErOWVt~O-6>~nxa9tE|{)JUK(V6+6eE& z0Y^iJYz;a`E=Xkx>Yu<|K-*Yj6tpU1<Y0iVBtiJYw_041yTmA?$bUj`Ujn49ph5Ws z<s5H__E@hGD)Q9sTIG^6Pztm$gm9}o*=AjDmCVTZSOgsPoNz2$xXV4@HkA_Xg5j`b z6FJ28d@ysg78QVzV0Y2gi(s9U1<}Ca6YZJ<+j5sszs=QRa0DG6qpm^{ja!Uk<hQ#c z6g}a1s6k?Z;}@ptP3{5WDS@$$67!%bC<h`SbIbi&7NQ`9(0zV4ZiD~@Dfr>^nKgyz zNhV)l?_L0Hy)5c3GU_12Ab3)$6?)n(vP&3j;1GwHfd0>!o&d;X>&Wj6rS|*rZ<&g+ ziM8oplFsluz5feH+z)mud|+T;!eDZ)V6LuUaAIIJ$%}gjg_FgL@!n!!ny`8Ah0Y(* zLz@SMi+e~u=yf`RlBT}7&88R%4)(qlijEc9rgBuoLH72Ra#$jwN~U@pdTNH6M8rWX zk$^v?Ffc&`BJZ7${>(poBsC}{Nv~pHVqm6Y2>2(2Bm`sxfDRe{08NyEvHpifaTFNr zx&AJ=n0^O@f72++&W_(3_&0U>U9OYI`YzXr#fN|n6B(j5H$4VMMLsQCRsNJj)=ILp z_SX54%-U8tq4XB_s+FW>DZBpk`Lon46&3xrIlk-TWV`n^yV>;n%iAAxe@SZzjHG@B zI%5B-XmAYp1Xe-=C3owm<Y<dY2rIT|&aUJesR3^UXeO>Y3LR;rR7`KNDMN_^_$7JE zmcldewWWQdnzTis5PBw%R2JPvH41v(hKZdSOwwtDDJw2NeQqjyCvg&{p*u0f>Whj} zvd7p3yOd@sVJf?H@U;d{6&8=Baa--uQv9kvmUD}-v{SPYrSzAy0`_3EMT!Fq89ji* z)Nio)K*Q+bIs`FDfmc;6B#bay5rW>950Uiw>q;1&^Q{FTY+_{>7QrmUZ?0DRP6_%s zW9rQ^a~SZlpU%@Ybn|IO;bpuj6B}YvG<UMH_e>6zHv5Ia1y81jTC$bNZJ2^MyoQou z2*T`xv%gyr`l0ls-I4nNQ0if%G-7rbmoYkc<$lfjO}!VCYOf=@fhKVlsZo|V4@%`^ zW)3Tpva8~70(MU`%obY8Ry(GV8QO08Pqa4AF!*ibG>K@7SD$M=sO`q1TfFY;HI6du z_T1}evbMfR#+-|8F`3iOh~B0nr<s*mW0g(yUlmc_fE6x-oTvtExy$I_X(FvT7c`NX zw*ug63W&6WY*ZFi!);?;Zp=zo%J@YR%E*5d*sQgm2=~TFGVktKE0z9AN#S~zI^tfh zRpg2Q4j+i43zmoxkYZ`TB{6_>iQZ$Ohdbgqgy=aT1tO7EnnvUiKe0mQ_z?!KGhc`? zK>QjOZ#iImN^f{M4*!ciDol6yQm#I)<8g?RuOLSuPo<}T*D1gro6lG9{x>PtqhU^w zi-=#|+OPqa=}>?i0t$mrkK!FwF_rKrPGh+e2ztpchTL^p2{!HcA!Z(O8o{rDC_ayX zny<1vqHP+FvIyHyileI%`6S~xD$f?UkK~1p{QM{LkA_OG{v#FRi>f)lzcZ*0JDEw^ zH-kccYZRJ)YLx$~ZvS86URBp=K@5c#n>vA51PA-<Mwh!yFcp|i0cx1c2AO<#5fXP# zlHA9@*leGIcmh+>U|i-4;sf}58YaLU%+&oL0Dt(th6ZKAHS}h0X{*-hnzQpfE^n&` z+#VMmRc8N)1nF6@pZ5Kyz_3kychT&OJk(Vo$$oAihb`0uJ<+E+W|YHZ_$nzTD&_<X z`B|194ZmJ_jcO`B<9GK|uCmRjDGSc6yU@aGvmUncIowXW>oh~&{o@o*pYf9RDj7rN z^9e8GCAE%;#Hw=yxyT&TwX)3^vqqXQ>D+XJt;;9uy$t-r#3w*Vt_8NXeek!7QI@tm zW~7$>=HLh&VRE65YTJhMB=5|{YRS7k3}&_7m(VYfwI*4+fXvy@j!8QP3F#bKOGZUz zo1T_!Tl+Fw7Mg})%bZdJ8;n@W#{k7USD7@yC_^Z;Aq3O~^EKR+Chf{k<G>2%CKyq$ zk{Y~5u?#U3>nWHAdJPm}l;&DRd1DH_HnVVx0TOUS25)8|u>N9W&n{Yb%sVC-yO$>R z=Ze$UkRB~r%Uu<2i7O|DY;LXyLOolpfS%Uzht9!p=(!8g!9(CKs`DJ5GD&L)MLJx{ zK~_brVa~~Nj*tZ=HI?_!H>wKve4>ctn?vLGnnEzy5vrWTBCMI}OKmmdUqkVt)$43- z-Z|}+hG1qYC=4_C`1)3J^H_tMw{Td48AWYG0pJ;=SK6C@-iQyI-owd%cxH8I#CD;y zBc|Dlm>TwpP-WOIx$+L$-u3elH;LMgbsW#Smsqm)5}KScW|xvXM{^K1pHP!JgXFkv zXNJ;91|H2iq9G0EmeoQx+0Al^RTjGS-w$9%cNgozpr5)$s(shFG-V9Y(#+GYMEA8D z2EWb<Oo)5dX4Bvt=-=8n*P%B@RkTIOz1m&@4Z-8Z`i?1O%MhV`ZpIM!BCgGM@Vca| zX2^FyS9Jhf^BRKbYrev6>B!(1QF^yrezoncTrY)#KQtmvROx>}HRYet8H8Wx>;gBu zT1BJ65%3FZ(RT@ZH%5&CQ_O^a9>*Kf3k^Z`Ze8|RIPS7=W~#->BtbizCW5qmDUj-8 z4CK5<ztO97Gi(n>9Fv$B<mP|zWHX880P#nC$#OwNsWk5Gn*jyze=pv*E~qO%I|t>M z1j!vxg!O8FY|cn`1$AU_apIjDo}rF_GMr<xi86FE-|#BZE@Ll76Xe-qk8AX;{j*Xl z?WoI%_WiF7kl!<JME@7S|E5P$RIQxWzhP~K0&Tp8u_t~OoV;iYJHY5u5|`c~`ECxe zDhW&K@@fxSRnJ7glbB7$Px=A;IiDe?|5%)JI_g@=U$M}c7!QbC`Y~{|)%~v@T5VB( zejc~-19XA%22xg0+$SkB#Ka9bsP>Pxl@Nq(47iH-V=aeFh+$+IJ%hM~km8T<I#2{F zqNHgvwG2u`)x9y{{d!I|sOozAVPwbL+uc(?Sf^sG9di+|RiU}*+7NnbKe3p#hTF4! zz&h$aFfjx7Qfjc=-aL?hR~BY`<YHhFj*5RSe{ZeKj=k1gYP)fOM2QKj>=sMYk$2WR zV^Mj)l*ueJsA&RGGLH&oQLRgUY(B^E@~BujUfrN)lSry(y>f3V+6v?F7?bGqV--f- zD*~F2)F;pGRPM5`glhp?=E*nkr68f*(L>ZeTPmkg);@>V42?7*%lhm~f|3Y@oP#;K zRmWRf!Gg~y{R*r@-$w>hZ9Yz-69o|^D}$@mDpm1NJM?nIm8cPz$g8}%Ga)Q?j!l;+ zarY)Q{!IsGa5y!uhdSKg>Jai&HG)uB2>~~j`i+%Y<`G@kN9!64=GaoU*TVK-oPCB_ z_cElTXyb#vB6(e0Ed~T#mSO4X|D)`kq9l#7t<kEqZQC}h(zb2ewr$(CZQGfZ&Pbb; z#?5oO&;O6^(|3$}AL4t6#~3r#xAxS&m?X-Nz?`aR3lP3dl(UDd9b1!^7f>HIEh}sD zKWD<Lc*e<yU}5oyvvuY!CpW&Ra0{YW@(QoT5J{j!)isRuFIJ}6;|hG-*%0jW9ker6 zD`e90P#-Qb?fq4x7szchxR6=001W2pkXy&@apbArhX4~6^_VVZIXIKqQkcoQJ=<6s zi}G<3m-&~;R{|!rb6z6GI1M%cd%=t;xv9E!$njC>U{nF#{gm3{KJ4l6I%=uzy%8AV z@cuNyDY~b6@u3>8Kg$ereOS2G4{WemM+76mjIcqAbW*#4QDbmjR<9J}CH|4HOQIKQ z%g<pfiBz0>`F@bKOXS=u*4SSq{;zWcqIzXhgqbk6u-N1~)G5t1NHqa{xD4V%mXo}e z?eEq#_pD>jE3|;lNq%12wzfzgR?j3&w^1IgOAvG!2Cg4I@dFBJMVy?0v7k4M9hrak zx`_<&x=6yuq57DUg2Be<GZanYHCLD<OXJ>>z2FPoc7i26Y<^}%85?P1VA?M9UWln~ zImor%cyRmqgi>^$D<ICX>Rt;S$xfN~@=atByyM76uZ%g4Eie|%J^jp=N561Uy$tu0 z8X$L6@f;{cK+eU$zX9)E5jdhR)9D^<Tju|S`%~O@2V_VR{{~Xg85`?af}WNqxWvoD zBN7CVWpFQ9#X$tQBe~*@D&)J?9^!I2QMy{FMUbNdc|{dFjPa?ky&Ve`f0LP|2LxcF zf8f?{xoJUV0|2vn0YA<cOb2j@2p_?p=d^7<|E(9|hpYcn{r8TokNV>W?!Ql!|88;N zx3ZEo`Nv^lS#`q^SsCNYI%8U!A|HLASS2W<#Jp1v(Oi;6j;_CjfR+}t%PLX2Gmgx; zF&OO{op0$@dz2mDOCKkD-hU$M^&qh4_2_G_@HM-!lYF{bifin|$z-<mIP3b&r+3G7 z=IFfE_v41x&$|tkk9+2IJ}R7m%$_ccQmS#(o!%tiW>)|K-F`eYb?uoc(|tHp)mzRx z%~;W#p6RE<D$tlgjQYLK$<L-;2L#o)djtLeTYlEX`waP{IVKPF?uy6brFSjgi6t0k zwo+K}8`%>__hl_67RWbCD@;6E49AcAGlBKF2$QcgRNFRJ2L}p%UnHJE4;^-7r1ipP zCMQ{OJA7IriuWUV-r8t-+9`_>63s*eJldk=%_NJHi>(}|%zLiA=p=F(beQVj>66(r z3NtMZy~)C(t%W&@45QS0e6(@!yJHk?w1kkVU+WO1ru3HPj%Ay^LewR&-t$Y)FZox{ z1FO4jmLx=Kbl$OLa|z|gG-f9L)#9LJO3E@STHRxUl50Bn{z2L2^N9#!H(QPCB&6%8 z+M&>=2vbR9Bx6*IDgs?Dr|0#{A>`ndkfdx18S9g5jbnd`yUOX!6g}ii)yBPg^eSN7 z>nl)3ms!fYnTF0h>)Eb4oYv1d;xd|5gC0!JAnI#2Ub93Cn)_MC#AnV#=8HD8mllG( zL<H_L201Ix|Gb=6rg`j^0wlUSYWG|1N$FUMgbH8hL?;N;ZFr3&uuD6i5l+}B0?0Mh zn516cy<Q-c*V+WwzgUB@dbQNaHe|mL|FF@WqQ|N&hy>G}O-h~o{sb4W?Sc?&{-gXJ zcYdbTBe!(#h`Q|$*)e2(**5c9`olKmRjm%eg$RFuO{j|^s4i@^i$Q>507f5DwOqSA zm@<e?>)wDf2vw_eyO=p>^;QJJ7C`F}sUXg^>{XI@afPrw!u@crUTSFg;_7~D1983g zfdFR5H?Xn*FSEd~g!))H_~^Ym9F1TDz;gCGZ%mm(G4_^f>sZbUk!bCtvw$zyYVNGJ z`%B~Oc5h*?rOD>*boRXI{<#1Ep}gMEuyl%>vefLJi43cZjMVtmXcE(`9ZCgv6O=Nk zp=lCse^^dw3k9q)Bo5bPOIrZB=$7Z&xX2t6j@H!Q<0iqUC!7>l{WHHm-6Pr*^dW*- zs5?)TR)gSC;aFKa<7{RWSDFzha{|5W)q*UL{6x3j<rP162C9>n#io=U-GzXU4cDT9 z+sq_I1U=e+O<Sx!=X&ooWjo`BgO`0C;#GAfTIG2@M8?Ci(M9on>ql$ViEK*sC88y_ z&{4OM^B$!~Lszf7Rr-k11$UduJc)jnE2<4-?j8YVLs0G>rjzI<Z{<zL4JQ`>@rlZd zF6g5YqK!dX@>UrnbI$3wve(ys2eGbo(YO5K5C3>)_!%LQXVA6`0)vRYACfCV5=C_f z<bnRs++cYLNHq%JgtTnxOz?NVD}+W4l)J{;lU@9iey{WelCUXLkmo@Djp3d&TJJPd ziR1v-a}1poA*Vz^i0~srPDxfu8DR{OmFZohEP}9pdd&RT%KOtikKp0PU9{Nl9`u`= z9kpNXDx{^rtGlzF>M<rx(??G6En6|CQ7L9VXUh(HXXp*DRrM587g=Pi0bGi)KC>Xv zq@6mN$WdMPp(2(#B-d4;u}DwkO1+yEs<qOwTP$zNA>2JsRvreq_y~$U_prT_hJ0Ke zAV70Ao^-xPMc}SWdu)MD_(EZ*hUBv02Csa;b7|y_H5!H=eej&HYrmUqTL;_Lb`x*X zuJu;YH^x93@ydL_J4b?huzs{E49GJzI$NFCsC~>5-E@9PJ?W9!pqJ?T;hXTN=@p}V z%V~4}veolVZN;WO*L9jQ15)Rh05S9D7{(V>m8to_HTu*IPA^9%+p~+P3&YEXvY~r^ zdK`MpMk|mF85AN>j?RuXq_V<pR0E2LIT1Hf38llYMyTgW)335vm;eyNOT((eu#37B z+?9qw4Hvb^3r!<+<9F`e;!<&ll&~*lfN%6OJ@Oaogm<=OTpbe>ERsNA&>VrjWnY!z zqp5{oC7~m$1S1NfAmaZ#h{YLcv~|iBjF%RKBj(1^iqhz&FWlfgi10))Vu_<h5l8kR z_7Ml%h#Cx&#hWsJLH5Cdlq*{F({knEFW7fW?{vnVB;GS>*U7d?k<<PVC`pQ=BsG$N zOjl@;n!+NMEO~~cOACcoi6{v(iwOI_kCY;_6sLXT1<u^aMUKHy^nc%=X}}yZ<G+0l zaLE6!?>Zaz|9RI<t7<Evh@y0NUrhPbQT5kWHHb)y+5J>?WxxljEJKWjCJ|sMAY-Kg zj?y=+`a?*XeBE^$w-Z;|MXEd=nWmOp(RIW+`-15%edr`BdkxnKjTl7=zvx<e&HI$a z%)B*?|MmWgjhJ21X}&J3x>z*NE#5IQ>JUKo9G02LGF<42{GgMe;MAR1VjhA{aO^Ge z8g{wn6F%SHbH{s++*oJD6&YOFbC~WpxpEVZ9R)z&a*v$PX}DBNq+aHn%-nN~>X@_{ z*6PvsVEdxA9r+;b9HG#3=^h?PP_K4VnWk6Lnx%^3tW<;^j7m^mtff)MTX<}?m^k4> zasTTR=2L`wF*Y@22bnyK=0`kV5T5romPfHCTyE|;&-j4~k2}+Jrw<Ksr9gxLD*c9y zSaNiwj_Uh7L_>V!Fqu(;QG8sjG2D1ug=uu~TF^}w-u~8e$yFeG?DYXwD0rEOX-?)E zBA@@aaO(h)HhL<{+C*bLhE<cd?&2@%XlvyPY^MpZ&6K^?&H<1GfYpqq$4bR(Rr64` z{n}-+B{PC+tpqHmH7A}3L%OxzaIt|lIrgdf=>A}$33Q|KMcQW>^o+F<z;z$h0fb52 z)2&6Z!TR}#YeOrLaPem|JrVn+<$bB*a=Yr0#Kq`ti=4?Fd&RK*UhiUkak-gzy16v( zWjuQheG_$7*Wlr!vC%-3t@^{3&H5Z#XLtMK)61=uShv@6q{n9PGULOq^JDe?`Y|R) zNI$VrDDcXBr!iaDz9Wp6W0=0QkQ_C=??k|IP~#>|$AP!E0if$t>DWTd_7JD+fdwr* z++lSOtgV6YYn+j}Df7{&ER+L&b#hL=!%w?2dIV%^Y7X3qTCi4*zOehRx7pPFlyVQI zecvCDt(iI83C6PzS(^ID7LMNOJ7BHV5Im0j6O(9HAPzX->C&E~t(L;rjV^8v{MP9g zcdih}S2}=i_D~xpN+I2Q#xTZU+40+I_(xP(piUnv?UhTR1$~VWcmU1&I=P(FdaP$1 z1JhGM#-za&0ssS7WJ!=y%e@zJ_x?ht=l5rv!SAvVE+h!Mzb25&H2k6`q<?6L?~ocW z2LpM?@@pkejCy)I_X&sDBTo61YkvMNze#k;(uvt6C-sTw{mHlYY-@PnSUy^`HBp=R zxd?Vw3wiT{fb=~dY%IwxxQM!zh`a23uq}j*+$dABjhx~DUmk!+%I-qR<|GcpjDI?C z{ZL5<98ae;m3MJRYr@TNgr|76!c|NTcGoLs8f63bFv+;kkqKyv0qP05bG$j~%Cl$r zk)No9AaitrLPTbEG1?o;$X}hKtfU??fhC~A_aue9wMx2$&p3(sAkmQ+m~fR>#LYo4 z3ULYS<{Ms<FOSK9oW~2vq!{4w>xa^kC#f@Dw?9QlMHa$5q0rKOB-M`GOUMMifDgg( zG#RI@IH#{c3Nv$2R^zRe7SzPZ+n^o+4A>w6(G^183wTz+27(hf{<?P4GeYb$F`*rW zSw0AsL>?jN-3d(roZdn3Qd^uxElq`lpfXm)f?Tp-8H^A-dpKTv!Pf|lDGye}N`nT4 z2DGqcz8Nh_weh|_O1v*fF7rHZ(=&!cDq(Mg3EV*^fxE7n926E6v`8{&;Y5JE`OjDp z#9@C9lBu~MOy{VA0S1(id<K|ceF_*GBR$FT@f1gY+6w}c_JrFxG~UY4mXmy153@+T z^#W?mhblA?#K4&SV3Jpq>0g1Exr2H1bB~f352#_j(uNPw45t!vI_WGmQdp{F(bS0} z#o|0%v0}hJ;%mjwoo8mk!6p<eg87(G({g4Z0@y$rdYfv6_S%MC`zhxi(gb!eR;0k^ zN#*oU{ao#(`u-N15_A#8Iijg`MWY&4RC^9im_^TShr0htcP1_robP=rvbx`l$nXDn zZV|M#{+2oP4Xpmh(@XMyzY(x?GW!>*BwKOAW|0piYkGQ!wOX@`uy~F-t^_EOeLW2V z5z-%JH(yz4Tdh;FLD`_NIdDkVA4CZ#9DcVD!Blb7dfl(!m)mU4<V@7)_KvU5JJ1b; zGBTLTB!&KTUq?6(+e3r-ZjHYu%<z-KFl69jgwp8coll-nR$Hwbl2dR6bJCL$`N23J zWXNH-;CA3gphuvHWDbn+f?k;td7*Xl_wRNRmv^MWgi;Icty|`O^;Fg{7Xh?w=}79F zg9a_GIsy|pU3NVwx0)j?&OU5drxTJdH;or-$Zz=9ew{#JfR{HtXFV%S_%8YrVg)nx z?sQOWW^oePtz4Wsv0Gev3GUF{ZS3Yi7f*)R-z`F@dgpNX>!pMrTfEi-ytA74Grp4- z&t;SSGae$rW8WaWe=`z{3SqX`WxCz(Sq{HmZ?7kqnu6I%icoM?w^^<qX>g{v7dX&c zhhAN0%VN=(a$fuAiRw}TMMlyggCP9kCW>h}KygZ*#d1`y`O<dmJ3bf7sbNY96f6H- zQgks;GR2ub!czl0xCKDi!aUy^^I*ojmtLPgFX_65(3IWy9q+687O}|)wXq}ro>iY} zhIcblw~kpEt$D0=8KwLrqn-+RY2=FS8e$K+8nS*8p=kRvx%Xeuv$M#Owf~JClW+9! z|Nlmhu({KBebK+*r}#T)u=pK~cl;%#wU_}!=P%%oCZ^~=Of7!T2LeQCt=t?jfo<wY zqDsof#Vz(u9p@)Oa0~n_AI7_CFP>Q-=3V#X;%Z}JbNTjhJWBsVR=!aWU;}Er$!xzP z@U!x@*#zJp9tu<Z-w4_WSDHP)*Z)S4n<fwBs{ktom1hI`olz0U;GL4({p}}zq41o8 zVhEEtqmt#~pOsFSVV8%PGBhqGl#RlC`lVk_;7aNjLO=1H+7q~DBZiCU4MU1uSRRba zEa{B|lrV_{Ke%9mE#Td7pn+^;puppiw#T=vR@XVLoIo5o$Xv)Ty<Qnw9^Q$Nrmd8y z7s->N6=ui7#)gjE1G9#K$CC<3c&94ACZ`A3Ty!k)c+PR|VmGmG>W(j;Ly5$&svAkc zEa|bz`MQ!ktgbLe$UP!qv16^Y1cLRQ!LYG>|A?TnV`8B{Bf!j<kHQ46d!$}TrPsjl z`4+VZ&lgPf;qXdTDrS{N$j;}PEywnqVeja9<yZNEddw<<w8#yyF<$iLPw|TEL)H8| zJ@c5jl6gqE+t#Y_3RH30m3pGJw`{sc4rc#b%Mc^C`5d!wtko^$ruT%eOs?u|cb-&{ zSb4S`e#TUfTWhl~gQaT6`d5TK+at2<6ZBsZ^why26Z4H8zVDV?%KvW&`Ui*7{oNF> zA%gO`!hr!D@3+r4MM?;XU?{kmvK@x2F;G00F{cMEvEGz?IZR<F8AZY+SSss%u6trT zCdj>*l0WqT{vhh?pn`<dVhokP2!5%4nZvu|O2<{%`}J~9|HC#=GR%-PLZ-@PU(t&! z#EX69h9uxG#IIDd<MJQ~wxKEnet7|QHX=8&d~j-mwJ1GFf!eiq0RgEo>kxm?ZXE^I zVx@h_iss2^)?undy*O3YXl!WKVV3rByFpd2D$ULujUpeW^VxF|*2c=ENig>6sLFWb zFtnwL616ulQw%tz32F4mKb#7eQ{@>J(~Kku{VQbbm;=xr!BX0jl~}$Fy7cyi6lRP= zcOL5H)>I)>+grnR&6P-Bw<4a#Tf3M$q`6kUh0%fC$lT@k7-Q`|n{Xx9uasFQ_5c&K zBwQVCy)lw|`sC{*De3u&^uG&|IxP*+Y-sK3Y)ib7%gq-Djt)}IZrU7M4l((aH5qI_ z2K79tVQ_~+^;yILRt)6^^hs{=rWoQm`BFX3s_&o!a!pW!g)Wf1raCnzDcZ)=rlOBT z;!vkXwXp$hs){r^<CP`N!aF|(oiuA)%ARPOQ_|UC4*78E3oj|cW{aXHq~<)XXjDN4 zOTPdYnQJhqPJ4!XOfMMFR$xZ&D%=n668$1yzeF2Dt4X<6R}_yANX-s;ZiYsBOv;^m z$}^}=rz|sUC=0}<Q?8n;l4!R$5NN|IWe$1YVu@DfOd)qezbHvy+kE8E9EJ&QMD`2d zBV?M(sFbDIm8;huXvIOjcPQ?Sm769$(Xik_{G#-EQtgq$A$pQ-QFX?iv37)Rs$oD$ zLp+b|!fL8is$Vp$y+udfp852Wh8d8m%5bZ$8MNS^?TnOe0`woF&!Y%E!-E*4vgiRz za)|}wBY_cvow35yP;K%;)Zc#9L(6Sk`~Jz$Iop<v;$13FPp!%<4P?Sx>xv_w+Di^9 zlxPb_M)qw5;L_7-jZK94Msp{MWT>k-df6<W#1lG{VPS{3Z2=4c^yzXGGoMHm2@*k) z;w3^gst;~~-UUr?n?<)|l1l=qUTOI;jN(=w(aeh-(2I1#51qm7v{v>5!q~)Y$W2#! zUy_Z1SGzOzpaszrh&|JXb$Ufnh{dDI8|ql`sF{GzMUOdAHbWyun?_7$D>ti<_#qO) z2z4m)fjf6t&#s`Aq*2QZ6Zp7%`I~j8eZo@ERAMbi{mIxcqia$Myui`|LeFQWZ6YOd ztcGbp7kSK&x}N=4o&3!($6G@u8+_u1Yzh2=bA)+8v0gW|?8ldQMGkv-@|g6JvQgga zp&b0buI7(A+y__4Mw~xhW{Tql3trmBe#fJ<OW+imz9FctmI!%$^)*+QH}SsS$TW<W z%aK!TJu&i~-X&(=l#ysrX&3z^{PrTfX&C0L#FhSyYr^qRr#i*Ki*Lzm6;j~9<rTSR z^M>-Co=>Z%<lu~6XN^@<N27Km!Cl1PGkn_Y>VCq2u4Z8T>DY~FatOo_3Cn<cb%vB; z{Q_AmI>aO-OKuZatdjsN)&=&jL+#1}tLf}}s8N1*Z4>{;q4rPvh_Mm>KWi0=Ri;(3 zl~KN=krLuCH6;9zDA1blUjme<meHaVC}^RQ62z<#*T)Z7VaS;EO$7RD&laLRTWvPm z>ZqDdIPq3<_P2XQx@}D$2&Fi9N2e#dueV&UueaYiZSRhM_kP0dI(wn=qqJ(w2XA<# zhwt)s;SUg~ng~zn=SaE|sr79^pv50b(gncRkpS?19h`kY;OV7T;@dk1=hoaE61v_{ zfN%=@y3?oFlqLir+ja6!kH}Y{QC@YZ(xMzkyL6eVnap(PAh8^FT47SE<{%?bN})B5 z#sumxbuLWPNt}%6m!jr9zDN|eRH3zKP-Yzy%`KgGqhn7YoZKzZs$fd|L9;sCk*I4L zAv_8g0#t`WBe!o(54-=AA1$&dFK+6Ou%hlJ&_rWqxiZsQR-z^*K<0*8$1W8edQR}` zE7Bp@BsW!#o>rZ7H#s=)8m|ed87n6JBiDXq16IYFyqn97BQOt}lG7lWVHynSI7O%O zad|n>6M8?YyH&e%FnM&SWtNb&!6UGVdSB;8z&8i~)V&fZ)(@IY9QnDnx26dGP`@AM z?1eP9v8m>#%NC*2U0s+s+)`CVijCHvi8$92Yb3*Z=><~6+rWvZ&)2Nh4z@(s?04}+ zB-?18ho|$~;&VaBdV9`Ll)6K0nWlLvMM;sgK-w(BW}L_Se(XSIGNKrJ!-<loCTWxZ zZqzMZq`Mx!$5)U|UGPCnr4|b+Q-yPQ<NTRtDqEZ*RvfbXB+(A-<DpO7Evg{sCrn5k znLdU&WG$c>LCK~bZ(tNjf<kgGFH|nR?k6#bVnA?3kTegZzT^PgulO6vUx_!IPLR4c z#=x>9THyL;zg^}yN}z>Wpz9AO1y@xP>>*`ui~Vv;%Aw5UB|1c2oJRmU$cv}Tct1@u zx(tA7mJ|&fq}dv*3MW{CqlaTLV~Ia4;(=n7tMyzHz&eMW$ii5D2}W-gPEA{EI~`uF zO-XH@|GhS6Q(AIpSJ2lW6dk0}TMOK}-Ouq)Daco)e%HQ(^E%VB6=|f9ouJo>hfR!M zzsb5BE#wgfUqbqtV#&M9DF_)2zXbx5l%m#nm<mGa)~cuEJxJGWyha8)jl?dd_xgdG z^_Rri4j|Y^P4Z?J;{^CM-ktUMfL+8)M3Svda*6#4d$Ty?2oZh&=M}yL_a2_F4f4r1 z2^TPXvJ@-X<Wd;Cg4YmRko=yV=O!P4R=5?k4{D#FCy5jN{fV7T;XwMG&_bVUnd@*l zi=>hp=@DkLP_!_?xLy3sh>-dC|85VBga5t62YN{W%my)9t_Dm9VEXurc;S~|P2TYn zG-@~E{L?mIroZ+xh(Y+~vcP#JSNxLbj#ebWt27tI9(@6C-K%Z1HK4qYPNu7GJf62{ z5f3wK!t3i=_ai1S=6Y^#b931Ic!eL6Ug4Gx7D3#Scr!cb6p0XzI4d#fk%zQLpbdVa zLu1km)mAUbE^-V&wO!=3QO0Atm!YXbKDn%s^1#!s{)-6ucWYf_+PYvVK6o0D%c02l zwKDgWpP^<Xwf<%eNh$}Bt~Sef^dsxGNXXT#*`yHa75_V|_7n2>lB3ht+FZkiv%iqT z`f<yYK7A^OrdMdjC}+d$h3ietxn+RQU>pCiqXKSIwf{;CGyU8>^T6zd22Rjb4Wcy^ z`{mB*zh`JVP0V))zDH%|w;KPSbu(cX<NpaxB&%rt*O2^_K^n8pV-cs6%af-D11eIh z79c`{GE0tR^M}%KPJr2SB4w^h7gv3ud<FN~<6pgND6njQ-3<LCan5B<G#4N%qyLTr zY`<;n^hn(SYInXs>OfdS5K#)`ZuoHq)uQ(WH<2ebaL(KC`$cdv*N{?UiJsN8@Pcl| zqhNl)8fso}>t8ShVOMB#&P#>NTMt$p$}EWtFVS$f?vLHW%oEj~R&24bhKTDH4+xYe z>5_hjSXSG+Cm3>WpV&P65ISs?#+Q?=Yb-mbMbw!kE!t%ghFaw1&%rCkhqq8eE|6{F z2W@;&2bUZ&Wm)fO=!vhJxVf!2WS*F*+HSWW;1>^x18^Pg3{jU2t9?f5lK%J<{8Dyw zR<1q7Tg#w~yW7%XW2rQ_Q_RHn@OcdL{}Zr5-PnDHTy22t<+o!X#z`-oxr!UwLfC*; ziSd`KJRVuL6g!FV&u&UoEpWVkfiDXTzX4gppYz)6#7-ZW?9oZ{kqQO56$!9Gr6VNc z3Cpf^Oa~=oWx_hJL4)3v)74yi85izLww^uR`Gp=5RoaW%2Ni>6S!^+4-^~EqgrFWj zOy9Mo@8Jj6Hhiity$Y*|s#KlBxuHO<WH&$3E@f+!YRYqS(V~`u0S8U`TW9OYfJq47 z)~>k(8*SAxHG#6-$UwNzT&0PYPK1i=*i`<6x-EnkR5f1i2J;vEetrOv1k|HF!U!>_ z?rt1m!I`;yo)d;BRL_tq6yCmNh`zeRak!>A=+3TY$hkL|ieB^r%HNUlU9trj=C5c< zSU!;^-Js4yk-uY8ud;dtsuDYs$jj@?Ie!)qlL?9@B`YqAJo^-Vs`tH}$}wwRmbBV% z&sAM3{5(7=PL~sgv@e?I*U1>W*Xp+Je=p!I;65$h_P)h5q&f+lAY9`z)99uZ6sY`m zQJVNdLenYSDMWnLFD#1mDc}`v{h@%7$DEuqvnsAo!prArb;VxSenAiMF4RgeVuo9S z8%8YD^X-}A*b>3Dmf8g)kd1j7uW6;cradH-T@1&X9QGFP0XNf~Z9y<v(>5a<y1~7g z)A!RSWqD!-+RsM=1AfLsz7My9j{kwj33x#(;0KxYeSQ-@*^G1r3T)CTb_8M$${>E= zvF{c|LVV*6;s{}<WUoaoWk|UNvk{Lu$IEs0$juiUKK+(!HTr325rYnC)VW?2b3U_1 z86`{IY38Unez`biPLUZfc_4a0+ZWtYjWd=r2@}e?l5m`YCJhk<?~$m*`;%(lP#|_m z>wqkgT>@xd!IK234(DR=`trQg;%0Ec<zG7!^Sm1*?^>K_)i(2`I9;xRh%J?xJLw9E z?=X|L61-#fUUcmb-+^R=07bafF?8;+4l@U*-t?6b)b=MJS`WrmW4vGg7C6`|EfQY& zcJlrBzQg8!1rGjOk{AEy@|B(J>xd<cG1?1F(r5n>AGcCcZ(gB-Y!+B<-ApQy7)K$2 zgw4=AbJB*R>43{|b9J)zbb!xQXjs79^FudjztMBlzRy1<ar|=op6AW0=k20#^dBiB zSe`|@pZF#511eznd;2IY%xnEMUP(p9^x@voo4IDsD8`&`QiI23B=&uAR*tJ2sBDAF z5~DU~GVU97!TV@%Jf87{+N_yquAVJ=Y7sE&Rm%~YD4d<<8YP{>b!}MLR+mA9^&94L zC6cI%NTJ;>+H0&jw(-V23yf~(K^rArPtlN1OHLz0n7EoK6EgCg1Cct;Z_uekst?I@ zqR<bU3dOqU0=nweUAy$|`NP#Fdu5*j7&i8omLVLinF<eSiTsujqjl3AWzHBjQF#&* ztIpFg#bW6reSLP`4h(~bKHI>H@~;?Bh-W4DNF~(kFn?Nd3sFW!jp|p)v$u=jI5(?! z@lxwqn@1F}&2QUG+f6jH(qhC*+pX1cQze7<tLtWATMc^)gxkvkGf3QzNNxX?Ndtt8 z+&J`s53=Z-Xs0%<?MKt2q}rCUVH^#q%fO4y_3V&EiC$T%Njh2>+NiN$4#kCIwRpU- z^#OkTF>R+-%sgQtu%(-OF&N^N%G|sg2yZ1_apMh*bdD!!qxmtBZAnA%F{}21`rmmk zfl*|f^Rj}HecDYEwXlvsCVsYXdgrX&ni%CO(p#lb)iu2~HgP0I72_v*p=5oht-0hm zw^r&Z5$X5cib}>Z!R2P@N=}XSJ?hNADxp!LvzU0%TG16|yiWpWUm5m{6=a?}Pi~PG zGzS#DT$A$h#*_B##t@YJ%z@~e1v^2|4~7D{%<gn7Iwh?bM`Lu>>KXKL#WIFbBD7D~ zYII-J2EP|Iaa2#-<3;9Z{42%wSv>+im07yAftRKxdpHg{@t%)>?vSR-m`^C%WxZ_3 zo}dk09ES{_8Gp<wAei<4NQ3mlq}eZlUsBc@0cWb3Yw3R2c|L7?c^Tp~F^EfZoEo`t zs{1V+TqVb96D;@VNAfVXn<GRrtlZM%uQTomvh$+K>`hKlrWpAVYowPJgDSWBpMvCX z(#e{m+(MDTW*xGUlhFL<B-XJa-xW*#OUzu253<C{owW=)0Zm*uK?)_y@qND&aPB@k zxPKkh#8SpfkCZx?&dtPO7GDHWP*yFX4WO7)f+V?)QeZDBB;3*d={n*L)ES4j?;5~0 z4C%q$8|e&vGRw;EeKU-9g@*^qwdxA37|MxwN`^{Tu6X97bQh8Ue91$WR{i~|CaKET z4NtT6jw--n|98<cIb19`<=Y6q`7K=jFWcWgrvbl>yOY`fvGhkPTFQR6R`511*>qMF zbb){z>=kOqRRqy5#N`Ev2BeLZMC_Doh^q^@W^Pr-e;t5Ju?R{3S9|P!_UXbEkZ|wR zX7|&k<IHyY%YT!Rvvpa5{d{P`z?^FC5ooXVVdPvXM(Ydm26Na%Fz(t6FjsiDv0YA6 z-5%z@p|omyCgNy2bFix!A5bGuL#C*EMdtjqSCKudMU+9<YVj&fcJ@Y5@!IaVWlRbL z*^Sb+{|0)T#<6Gd1<8-!0?V&Mu683+QOD0a-HYF6>3y!xG+5Wx$iIp0H8`59*xrnB zqU?bVWuC>`6)Xe5!H!COx#<`&SP{AWHBs3JOQ6iLu`5=hw00D^KALR;^b6S22uBUC zVGM%}uwFFUVIh)tT+i`hHGW3x)q_`g{b|V>e%?qyZ-<q)7fcmtyK?s#Dt0Ry$s$=l zkU0P+Uoz5W?bA70`NZBF1W5exu@@$lzD)=PWRd+cG2F2QjahR#oW?lO2_zjCF4W%P zu4{FDY>|2}RHG{i=YheMmG*#{#U!iklyV~IhS8$2CW+nHoi4etXn96qr1|h<8-Mdt z_Xy$isC0rZR*q;uNp#e(U06k9iTJUFWn?<nBexc+*@UI^BLw1C)X#`1HkelX(8qoy z6EVm+DT9TlCF)Mta~SWH0d}K~u2wT}k@$XXCYF*m(T$TdO_2pE$ubPwWJG~h<rec) zZ;d0zP~OV9L`aqD!HRf*T7>d>U5p`-N%he7H0U`s(~iC1U}vOada-Y|q*)p+Eb@~W zZ@K;mmb;XGhFZ}`)ESV&?|5F0K%WX8rw?>{-S$kvViy}aleAdO6!X-vE~7k3%hHN` z$@&D2CZ6;J@*OhoIHG01g&>c@+y1{1@LWGK%Q3!fXSMMEp-<zVs1~%fvNAUOuTu8! z3UeoYbDRHz@a*q>8u>e3E5k$>7v%>smq*c}B8U{eRuQbH0aC71phBTiwjz$9cVQI3 z94K(v{b)e{yKlAU86eoHqFG#Xcy=baYT+x4|Bl`KHU*Oyo-TJXnYHoD(|70B&L7jy z_v6*kAFsFCAlYqeAc(fY^D&b0Q+g@B+c5y98Wun{MU4O;P=GkXivc|ZCm;46kw%XZ zhBN?8D-xhxhM1Ih+w6cL+0~5~GBZb0=^(x`)n$Z+Zk%zFMR5+DE?lm(WIQ;<ajzay zB5ur|IAyGDvUX|7;$&t)l}Wr9LMW^_g(JwbcU|q8!H+>X8(*0MDV#V<mkQPJixgEU z!#tA$ozz)l0ri&)8K|Q?BSymVXN0l#OcXY;v2t=`iNcD=L<Xh2oi(AQ{4JM;wuWoU zpQcp8(0LtSA~-`CQ_b-VCbD98b#3DlSt+eV8!=4f1vIAplB)Z;KNj?b4f0FLq<Bml z+=3*iigdRiN-jCnTEtR81bG*xX056z(!$N&8OA;=@deOZ&E+wZ2-K7zp!3K{`IWy2 zLdp!XQehmW=3x{4r|s@FcCO0tpA0XmY^J!GOr=o{%9#XR4S)?LoSbGP3A!jS_f=M2 z&&;cH@(Ou2YOan$OTaAeb2gqgKhV!h{Yxo*^wpV@6L_jIpsHakHU1=VU=|+TMT-k_ z?JBP)Ni7*vO45kcW867I%mcm#woZ&P^h}T%HK&>hPPtB9MYFw)@+Pn_>+Hei9qCYL zD9Wh>D@9+BBl>NHT6>vQV+&`kFe?nNL^t%Ox0aAcLgriJ^x69<9ok<6;kbh{ZCYm8 zLgEZ^lNmbmu}oUYz|pNnMB}h^@A@Y6KTl25Zbucmvr{c~Bt=op`Khs$BH76o$Bf+7 z=_d@K=pQ=YD?RX^2n^6+5V`9VgTfCPY{J^YQ4uTM=%X}=wnxE1IJS^SLWzD2j1v9o zFNNVQ&XH&@zUo-SL(JV{6EtYFg$A$Vj+zzr@+agPiO>jj*48*oI3&{zxlIn^ekO>j z74{0W6~@_rv~D&>xCMe^z**BGI<+8m<F{7IN)0-bEm-{uHm}TXw!Bt%A8x|AJ(g?) zyF8bv0R3}C&g1~-%7nr7VU5|msv@W6vNAUpUpXqNYV+RyNGzH01@d6`*wI+c&F;Eq zu~A=1>Q000XZE(q(cevXHB?YJwoV-I9f){?JX!i{EPmLU)B2u{g0#=$<>(x}f9PNn z17%$utFL@GCXldI;{7FimV|v#h(99pN=-_7gDq&CCGyiLKmN7I@XU2l%76VwbNm5t zoza;oh)<C`g6GMG6m1<Y(2JP>jHmgMxn^M~QQz60?c7QY&u#5<2jXk;-$gFuSIBo; zeAd6xB&!L>7$}B<Ss`Ft8OJ;cGoVO)1qkpo1O@#{1P4B@IuRDF_gGoL?B;c(YV#=} z2wksFulwKV9)LkGP=4|4c0lq)_~8&Oe6V1V5E+8p!T28~Ie-*p(!de<BlzQq&?kVT z^tH3xH|3B~b-6-#t1QeA1P-Fq3h-Vl96x^0{Uu)VM5LcjRqVYe;z_ZHRFmR}XB7%p zAbmodJRmUsbvo`j1&T5#AE1A%-Q+i%wJWV;9g~QTcZSmJReg#$B<VD;;bRBPq6V!# z*?yS^Nw3(lYd>z<QP!*uBX@M+txi4_hkVq8EYdW<Bh)Bc)J2|PcDRlmKAUAnd{{xW z)lcoV9R7fw4V^mON8F?(@ymy=7jxX})t=5x>I9*qcXZn+)Xs<@3BU&+45$yeOj_Ll z>U?^*UJ`6l)^lFa2Uew6R5jPiv(hOhPS6&=;IAycMDUl4qmV(WLsPhc5E&Q5_P;L1 zOCA4l_)_F-f{C<ZIaB_iX0K7rjo?rv)2Xsw!=Y14=s8087V0P(vqIQ8Nr(;4D>Nne z5RN~Ojq*$uttuwRF5cS8BP1-PwvK+90JkV^U+|_?;Hgz0YM-LQ8LR{=f3+Wk8m^h` zSWP7~>lxk>qd>J|XEOxj4xu4T@fUl2u{W>KA<_CTi>8^U6}9YbJ6~J+a%Pi_v9SEP zF~zP>?m(sr_XqvIvf1);cx7bY6wUj0BI<t?1po6LBW&-iZ}kshE?7m=aYG2@(}=r; zl)AOWevyojl65GaFeHwxNnCJ|#UG{Bf255iDe{6QhO5PhB;9=b1^F<1ubAH54-?|2 ziCYo#JM1U8olA2HeRC-I^<h@yx1;%wE$iob?#}0r8?v4`h7fEjk-D1s8yP6}`hL~c z=eqJeww7m$O!#XHH+XKZwn5x$ONw0^pr<xlc7J#jm_~9~mD_JiWfg0B0CVu@(W*(0 z$@=oU%?o3@3hK}*&Bom-s+5tg6MYiO5L-4d7mr4rl}oKUJ#(vBiY3rYd0KPAsfHJQ zG~?IY9f}kxPHV<*mUGlpcb^_W8%^)Nwf8cM<xskjSN)y}YEdVD3>Ix(dq0HbFyM@< zU&ve~?@C>H;~|p{H^Ov$C{bofy4PW>>!<N0wOBf8?|8bfWfSm`vR36(L`*=s75kI* zp5=3jA@t1>|3=;}U{|kV$titIz27TW=(Q9LUSZ!m0liEw$d65HmFJEmYf5*Gt48B$ zws`=0s^&GcS`eA`UL|@t{j&8ULbw;#BJ)uENAPPL!s-yW!GooN>z1qVpmqi49!r|# zdeXykGvF^ed`+a}nP-P{Bl;D)^-e`&!l8Om2<(Q7S7PfDa>OZ5yR^66CNY;&@o!Dn zXWB(WUZeG#MJH;j4M4+U@dz4cTukG$+$hJ)Nt!5|{~On%+){mzB$vbHU3?7E4h>Ny z@hmO8lUGzI*W+z?jOa6q|Ln8>Y<Y!$#F5Z3iWHnga#POXL?#XiYfY#~;GgQ!p64(0 z722ixZM%g0HlMTSmzG&$-IcNQR4Vz(DR>mN-Te5H0+dDF4{qp>Ut;1BJ5}l51Ap2@ z1cDee>M>2o@zFlK$J6iuvlt$^mr<j<sicP}0CGLqJZ7#6vzL$2;WzOe@nwP7B8LDo z1(QfTmHNyg9j=fe68ew&4zaQa^Yc6D&>qaYZlQAs6LVJ47m5H^)w>GLeR3fgL|!=a zeH0+B^%6xvE>!wZr;ad1((HiAF|nHjkX6v<+A!gpJna-RuSPL>E^9d6gSlHMolC$R zY3RsbI?f!i7~_4;5Xag0FkV3#kE}Q3#u3Vp90Mlu68XTR=f#wrv1|f+8mt7gO~LO| zA)0B~)_oFx3Z8Tgajh{;nB_jT;8M*kJ6U5Jaif@HN|BMGU`rhNiFpq&d-N)a4OXq> z<}iY*Bp^nS7K`6v2iDK464-$!2nU|<p0G&r^4McS$X3d6>6+14DwimE9~g316Gk|; zH=JVj^MiY3BM();Ba_5Fx<)^kq>fDO7=m74ANzsa|K3#KQ);Xig~}$}B*%V%!`~-h zZ(G6!YHD{NQAzbiCB;5iEg(e*xc?(2KJ-CD#P>x0q7d!}sw!xoQmS#t(Jo_^9A|&K zr2)QLt)cRi<-Z@!VzlPE%f3fU=r>hE@*f2=aYu0*M<;z7L*xH3mPV^+Yho)S_^^ws zv(fw%fCSaRqA(DnsMqMt2)k1+r(8lRUyAiez)2XMw(00Bm-`?->sIZ~^QLKjbbtS; z^PK3F)d-m>TgT3AdX$y!ew@wO`S#T7`w6;><pX5^)`}vv-$=mAWZ<mnA2m(TVkbIs z425Df(N>u!J7x{~Az*?E1Mw0ZKuG9{0t4+X+aDIE`)JS#|8%R2pu3M<|Ee+)NHAhw ziM|6lE)<frHUr%}2Tf-vn@2H0A%1cUj+*1@rY~&TLaR^FIEz<bG!td8z*<Z~v7s@q zC$kJdnrXc*-H&u4Q8JO~8FJvN9X%Dd3^}4n5Ue5wY{mrjMX2Z50b@?@W-dF#XsYkg z5@s>pOYP{VkUexT?k2H7VNIv0Fsd6Ib`4vTr?b=MY}T>EZ0L*R*j^&WiB-PoACe52 zfy4Q0@ui;z)ImevUj6L2C+zgH8_2S9*_gOQ{!_lfq|%<<+7wZkE@E-@3$>E7ize*k zCUH)4#frTt=ytJC3<6Dyb+oZ0NV1+83F)VIaEQMaYpg7!<5rtFq{{~Fl0-Ne;s%mU zNh3Q~K7G!BPOI9f6&tA-PNya-PW6;4i)JAn9cIWW!_Nhmx6O<8nY$Qs+=Rqj%us_) zUQOPkk@Et_+1%)B5A13zYOIoK%;7{wZKUvRt4w9;*;Q7?6v65HPJ)@rFhRvzFcame zJ>1*8<zFVoUbO<?(IaxiR}JQ8S@IhK(k+6aMDXm&N(N|%L$r{Au;&%(&bA|bgH1J= zQ|95l`W#&pIGF%bslqiti#8Lj12l%RcB+0EgM9q0TySs$6m}E)y3=}nSm9ws3A)g3 zPML|Qx{@$ztkSz5Flwk<6+o1ygk&l#XUcGCGg2ar=M9x$O|mKX>;xuSe99Zz*!8-q zIZojmIUfLDDOJjked^#lOxta@o?HOdC=rYuO!GUB4|@8ud0}I;;_n$;lXO8_ypF$< zx@Es>n$Ds1yzE>yYIo@o-JXT2R;iPCmwUu!`95Zhv*+&#C%wevVRoVwOfez5sdX&H zhnMtx`a*bp#^bn~lFDJRT+4Y+Gili3zdY(tB;F*0x9D+z@Z+0dWZ%9o9RE_Izxx$y zf_^!M4>+Z^XCU6}^alPk@fqX^ZqRnB%~Pvp)d^MV20B-*h$ySIIWPDLfT+JP$AHn3 z7tA|`gF@4jzbwH`d8L2jOFT4wn-j`n6IjnJhKNCXt}~b)^I9KJ_#7y+N&fwjiYSm| zkwK(Wa{IGJFS~6D=@BQp4B-{DmT0mXQJPi5Cc13ZEnCe4{dzv8>{fMRpS+!n)JM?l z7mj<lJpR>7?vSr2fqfKoF9Bn&TR0=Wj=t9uDA@pdtbMo(S*(4!%4k?l8%RzYB*=yM z>+DZb4pEJ;K3JqI$O6~!G41>VAe*L?HOm>S?a~Dj*S~}|Z3m@sHNaa{vHT>6IS$B3 zeE9rjq`qgya2=%z50yzaSpH$Dqye!MY#%#%i1^3>?(Dfc)0JHV4|LIglEJ=suS811 zbwP8RZmDTteNyYRo;2;BRCIq&2YyL69u=$Gitkry+5!|+ZQlRwCL_kr2%Woc8VV8o z|4r`_cl^G_=%1^UlBMjT9EQ(2Y=;YKl0Ej=Fty>Lw36If7Es`jkpKV<hRo-rgGr*r z#RWIM7l3~giO(_*k?{=tE<f_rWX!JezVMXw^vH9}X*-+S``Z^-Z6GCxA%O^_Xu!>{ z7y&Qj79#eKsd`_8P&_$OjzMzu3P=$r1naO0JZt2j+jbLGxnOaLhQ^>wx5Gyg5!ypU z{+hJpKEoC}r6Ns9V-jcDJnYttL)geGyXNLT!Y0e)k~v2$_PR`?%0g9vLPdfpiEV|1 zvuwRn%TpHro1CrO;FV8>xp{eNH147d_Yn8F%-L~sqmS^hm+9N0(_mC(DI6k3<Y8=* zA*r%*l!QgAQ&G8#$1QEBpMf&QUub?f1$E1^6rF_#ve0zAvMl7vjSh1Tu|0>4e*KBx z=>)KgM{y5{Yu8w=OvBBQERCrWcBj^&y6mu;wdS54g5=$+uz+HQm}uz1rs}d5^K3c! zuG|=(B=DGIi$ppmzAzjWFF3yb$#A+S`iq)Ba#$L&*-8wVDHYb|R%s-r4hdD!QI%t3 zarVM}%$SO4C7i{Bv(RG`-wiiREA{>Q1E%k4AFMw!nH<#O?2%hJq+a9m7f09pq8_>R zZMAD0!$^vCR-+u`-*#gpHT?suPeqDVo3AJ%+m>->wt(R(dG{6OD!^?dPJ3|+KMvMB zc9bd}3eBg`q&M?YDWz&LKNO|(8U&m68KZt`B-%9L5z2<s$f`tq{Xm!X0{=>O`6+b5 zEriwtWq?97asnOI`KJjRJS%y_yMUVQPXughTwzlIwF}12H#{4XPgpMi%uhUgLXh8t z7|)wT3}WMX18jChpg8@`Q*M0?iRia}r@RAM;P+QJWQ^b8y&v#kt|9z*w(G}9SxM?t zY4`pa<h*bE;Z`SQ(1GhjlLi2Kh_@n>6UkZ51R2Lx|C6zhn3MuyG@g2!{TNl()j;(d zJ%<Csm;7hSAw{unia&5k2nI#+<WToCEph;Dimqen-5kT~uYbE)36ZZ{xa#}Q68g<> z{jaMA|9SHGucFw0{9FFvJx1WoEOG{bNI-WBh-=!2Yh<8Nq>@olRZ}TL9WGEnY_r8A zcQ{;(xgdNH>A3loqQ$uh0}2ruTQ=5Y-UWy*FJ^K$9ZgI=j;~{Nf2`C~5(g?^O{!Pz z_5>+oQYH;4q|}Ev*LxD|5e}LuGqadR5~@?MVJL8$NE%~QnumDIowF!c&SY}AlUbAu z`~_=ev46~_JQi!jJhCWRro+FDF(_|QRFRUTz1{%l)vjfb3I>+#IPQO0E3@d<`BNZQ zK8SlLRt%FEyw3PFHp#`leyBQasBBL)3=cDfG67bDagbs`owA~I9+XBOq<Goksx8VK z9YMjhamEc+0U3bF1a@j^*DVS<g%Y8EBB@$Ksu!xUu`4r6v?c*l#Z{(>!u!@@%Ap}@ zZPp^<z0L-+xJT4^`N$;JG>SUfBtt<Vnits9U{I&c&DDA-QMHsLNUV>6ABJ#B)N|i| zp?aPvxCC$X_lEKCO$&RleSnd^ty%<dAlPV1d6q-At+3+BQ5irEj;UTDDJ3ybh{JZ1 z7J~Y;=Fk>{jg)h6gEBj$PYDG_6036wh95K4sl9BryetbhXi<k58dHpUX+}IiZ|PCS zmspk%a*7C-tv97tFP7^D1|atjPnpXoTx3%haVc_wdW>ch*D7#ca@HyN4RHj-5JGJ< zDwqS=0HbO@UFs>##;>CD2}}7Gv-}_x;<#;+^Dy5_raqGdAG&T5{bDig_Rl%WVZAI# z4{>^5XOF?3?(_npQbVRG0~@oDC=AZ}Fc@eXl(^6Er8mVWFK5(;WqSRb6%ZSu>o+v5 zkYVVMuE;{RT>S?ag(N-N5I?*O**eKq8Y05AzGMIVB75joK|#bEZli7*S8$`pMmI;< z)S0+PXRyYumunix9Zz`BRkVL!e|O<IQu4oX{`jBDWB-YBMSW}If5rKEk^LnHC5p!S zoWfNRBnygJyK-`yas>(>kqSbWb(S)Ks-Ad*{~>fY7(9-zjNtaC7mC4(y&|_X$<XA? z#YGmUsYz4s*ZVW59`2K~nc8w*0ZX(4+P5->XSw(tf-hI}(jKM_iP~60R_SBV+}gi( zD;~^NIW)%b9Lrn2NEr<5A;(ZC5s#lrxm@dK8`Qex&}*KF^8v6?dX`vl1B81w5OT(` zaS0){B3;im8xMJ*N&;IhnNccgRx6s^SMP%Gm1tIxleK$CIs+(<6Z<~43Ehl|EFzn1 zB%6gDil~|=fh%d>Av<;yJU1;FPo(!WbG8slChN4Mka%EsJp3=Y^yjVaDeS63-IxOR z5-YSv;oA)3?-n=^#ozDc>c}%8#4_?wt!>ibWA<AH@kRsSN9&#|u0dQ>m#lY6#(5oZ z*mo7u@nzU!HuqF^J>Ebjz%J7O(YKr8H-=Y{h!)*PkGzr>YYzH<`dwCxaDm-7+46`d z<055C%K$O{uvS=Yk)AMC$@=;W1;)wg^G|6o>z4907WxY|Vuat7x{EBso>;dUUX0Cs zjoB+FR*8|*aC6Svr;&)y&)p+?ZG2yHg<lfAf-(VB{Oq8dQt`6Y@xB2>unkb^-4D1` zN}phd&|3-|;-)z?W0H!nu%#y;N8o>)xM72~^Io+8);`ZE*i5;Ewm&1CBy^Yo)2WiW z`Cfh*pJ7gCi*ek7?gUearaoioqWWXzLGCYMiQk20L?I?aaul;AaB(UG;cyJadThws zy7<l&q3M!EHl!nJ7))q&QI3!!0z+kp03PM|sM)az_Dk|5c9z-GS>ns20YD%SRyBpB z3mxKkFgs^WWE;vJU8t?<XST_GuXz%M2kNST=KH@T<BP~{jg7u#_>%99hx$LB?G(*y z9h?lEo&K3C`7fp7A4pGDwpK)vNAaPfqZ@c6qD;?Uh-}XjvDJW(H&;iq05yNK_Lpwq zPf<@PF?l8aTW;%fE2;QLjafSP4e=xCY;y}#Fr`6%&2hHfH20q87?18dRq_e7%d_%+ zGVBBox9{*nH4Z`#O#D+UybX(wec_iDvi(*pp46LN;D-8V+Wnr%k5&eHKuZ`mOb_fZ zO_EaK$Xu#>36CnkxVQmNmqA%@Jaw5wP*z2=mcnF94wJ5}sEDbf9*>?98&t45{Z<&8 zo;7`vbn!v|M8+I-T8bGbd5cO&6(fkVTkIy3Nkdq>!uCL!c=QP)0JA$UNfkwKzXus* zDnZ0+R0A5_Nif<}vO^#3>?o@zel@JQL^X`R4E4~s*`KBUcUV$!u>OQ}-|q)U_kt}W zz~&eEfWv3H21DXJIm~B)1~rC;&h#mapab=Rv}LVD_?{ghdK@{<aJivcgtk~bNUTeT z`+~C~^#+qv_BCTRdlzg*NYT+lkVBc&vuy+>z&HO3++&5MX`+LaLT*!9ALHVkOMbqR zZAYa74g*)7ihYrea0`mFa%l<7GPLP;<!W>QSM6;*hF!XUBaV^)1T<0r2N9qq$a5@A zEvYWZ81m`XkL!E|6B02iZ)N-ec}>#2r6xJ@eMn7cK+uTv;3llAEDRO0(rt>NqZX5N zC7XrGX}oK?|Np7%Jm9hX{{K%%xb00wHrab;-9#aYWW;TgRQ6tR8)bKAXA{aMD|^dM z$;h6GvNL~|&!@USu8%(d|M&8^jmN`zo^xH-xz2UYd5_ojR3_ZoJU#W2*s?T5!!{eP zo^lRX4$pO*q%66YI%<Y!8IJx{2y3m^B$PnfCQ3^jvHMe)w#!bIJPsS}nBt*0Nx23> z=|e%EG-EoCDL=g}74LmXkb18&Cf{nAI+>){bJn#FpXar_sLB`Akl7Bm_C1s2dgB?o zDOaVt<YE0A^mph{P>IGzFnO=uZSQG)<d1sKEFHgW1y^KeF9D&1-l{}E?@pA>#uDKj zzbzKN^K6PaA;{Cm0@DC;Em}fyOGwdj%4`?DN;wtFTZ`8J_?w<flU_odm;ZzeiSQ+d z`$ATjSh3NRERlTY!ig`b9TJgJuxO-<%2Rq3n?!I02WKUsr)}buXwSsb-^7J&Cq$Du zHAc1vBs!wkFgS!UhXavJeI?siM@B}}1L&TwTZHk@@kf^NT#Kqk&FhBB35|)1Toi2* zSy<yp5=%roHVfPvrkKPC6N1~U)}c2$zP^8OdaswU3x44{5YRIUJg_WhKdgV{jQeRx z{OLav8Z~YWSjyXuqissY9aR%HyY@6j_xc5)k6k_yMHtHlVJiZ*kWXP9SNSiOlt7bP zFu%3pU=*cHqV3+8j_WRs7lb;)EPCSXy%r7@R(cI5yih6vbuZA}Lp6UW)hsS-UbHl$ zcy&8IJOPp^m6Kt`&pD)9@PqIHq+(fUMDg0t==dtH%YH|yQS3cs<`<?-`F*{v&N45o zF9-ifX(}r%w|C3p(S&zvr@4np)3xemWD&CJiq3nbL1H+@%`ObQN|;x}k<d)E4q=qG zOh%XTbX1Gxp`;jkT1xSdkr=T(M-6Wo*%mYxbHXh(nA;Pab=eQE4BnR;eLh;8UC|+^ zeE-OK`tzrHmIm!)v(EO^#r9hRb5b`r_!v<kT{9_Yv<V7z=^2Gdrs8Cn1E04WcauJs znK8U$2;vQNrF+9L)=I`K)?Ycf<sAxd6=9w=g{ToX9b~YbH_Vm)zC9)@)p-8US$bv0 z_mkohb<~i8@7<JJ6JqE0uUDVr?h|?UmYhBBX^>M_I@|g)dzFr5CU_urZrD~|5r@PU z51R+{yOhToTFrEurcJP%ES7f!Lemrj2d^@SIj}}PubWN#tvYc8;v!LK7!4EsBK95O zE$P?WoV#Ih<Xa}sSWxx6QT_Ds9<qnuX)z;r4A6$>Rql*{I!!QQrf3o9G-dyfP6M?y zwZ9F-eEmJRhel1<4)T(;UU9Y>F@;f&f8aZM4WZCueMt~QjUX_-jlmQWGTGBT*2<<D zF#~a7<(84Vel8euGL@h$N5t|rda&vKMehaYo}$B<g^z0}tJBZJv4tg{^?!SWo1mp% zFbP-RR>TmY9P^C3I&Q8rzFIS{R71L9I=pPn96j|}Exf@smKGb{5_Y{g+T%U>ve;VN zY>wkVM4ME8M$zlR{>XO}!V)=D<qXo;h<1m|*Aa#9lsaJBa?6(C4PEPA+M>8C*X=sl z!(7Is2&HHaGTU!Mp4y#PY1Z!&>|po-hncxskd<)QphCLu6m~Sy+0!V>X(T4hJ@)lb z(sG{Toe~FTA^UY$`xXKB)AFx$5pyY}u?i?J?9eOUlv?#omBtdEOjR3l$6l|t%9ndY z-|fqzPWy!>nni~6t`C$`tB^D$jH*d;OSP(XG;OQ3E<Z5;A$)e0!$uQwZP1{f`10Um zfn+rE<&=KbyilS;pV2X?^ZN>UMDtdgIBQ}dx-v3(dpgh;0e;i*!a-A$lGe{1CyHyv z=PjPq8m%_5_b_8!-KCyON|WT&dylQnwJhAtVw^wkk?8k|G{UIn{v}%3kL~=aJC?%k zpGBS-3Wrarp_Lz@xKzkg`fkbD6UMw+=I@5w#$Fo&#hVs)#t<$5eWecQD{TKUz-T(a z>>N(@79cPXh_y9zwyN@9d0g!Dv>=qP^#c}1^PD2He`(%1BH5(L9^AV?pN*b@?5gYg z_{X9XUGbp{5LJ8ISjBLaX>?&%s#mOSJ3QI24y__wLfTqq>qZMOrsyQMyrvTND87BK zqI+_+<JK~syh+|ZoNmLZaZpy`y-L>O@vpRxH$>gJD9Eb#N!6dg3}2GhBu8X_?q+zg zSrOG*uBOz+Z!x@RZrvC5gZC!G$FFRfjr{W6h#vfmFlWk|n#G08(aE07>{rvVtW!CQ zpQa2uJzDD7?xiR+mc1L0e69q!rZ+km>m|+Yn<|9sT)xYyuT*q{WQmsj5!-~uc<RLr zeew|T)dLaOT1}z+d&B}XckaffDfbeDF4HPY$$(d|*KgZ3LtyK(Afb6cNOP@V;OAJ$ z5qB01pF1w7WQ96S<~}UT5PP$=3<Gz)^17q7d-2@jZ;3{!nx;)3Y!2scZoXUaiPN>* z>{w2byE0ksq*gE8pX-MsxR>c1mNrk=mn(KN(xNt_B8${mv?8d=OsbUgLG~6Uf+zL| zZ)+tJDwcP84PR#y^AlaUrnJ=o8wPVA*9um<9Tt}2DA_cjLmVgZo{xFSf~WkJ*%$Ox zCZi2}pTMqX)H>`!w;vAW=J&sQ_;&O2E+{yVfbeqgFt9Gt1lIq5=q!%L_J6&QPDPOh zJX6)Ak|lsopz7=Bv>1^HQ4wDEGg9b&V;J18BW5Wn6Q^RQYvf<Hn>*gJ=-t_p>;FtF z!>%V>CDTHOkf8Kcd{W%1SJnR4hPq>~!}EntoxRW_Z}RywU*YPKeue%GUER}VzRCX4 zR%2ky^fH1xZ@Px%xg(Eo&9Lc>*KQw*Rnu=8UHD4#h1D%L<2H6qX^o!AjSrzAu;>NL zgDTgfh=vk_ZhQFT3ymqd<vC6f0k`sIjQse)Yk^f(K_&J}MNi-@yl-v`;pC*<?TH&J z)~w9!&|K<L*>;q;J<GyO$JzB7@gdx0>6JQea<KJq%{$)b3)($`#U2xdrn6@Hxk~yL z7!v%&=F~$WE7ln+^dk^R^x<QQgP2bOTJWXa?gN?HB<fjKx16El2ExbY>rvcKwfkT4 zjfM8^P^l>yVtz7tQSxA^%dzUcm?f)<&hu(?r|WV?Lib5HstiP|{4Xa_@>>XTJ2+*P zd%f)eM1`t!MeIF35`-I-y1#$IpeTQ#KnOAu2B%=5JYT!4&9vM?jjQL<RiAb%h}KF` zQSjXqs=<IcwFIPT+*Rm0Ot;Bj2KvC;7NRM#)iN1|gW9&=aZPHujH+N(;NZQv&dS!U z2X4~7=9{T^b2sw8b;)kx@4Oob7r%N;xR`SR!)oDiAUaK?NIkdyCgv{jl?I{?x`#=F z9RV7;fs<K|5eI=OL}pLbOjIBE^Wn88r9_R%sRvdr^CA?AQFq>usb7*{+aOi4dPFj2 zFDiI3a3k150b?p4V&NPbH`5%|&Dn(+tyC{89AXFkM#k<!GRc+tmQ`u<_JqjZSJCrN zG;KL4*H!G&Pz?p5M<l%iznnXwWzQyH?$f$bq}@qz$Gl#W_PZ(S-asBY{0-ZDYV@uY zV(Iw^>oI*{pO4e$OvJzkwd(nBf*7YO^H2$eB$>ukThXsCqekkDc2J&``wfxZa!ko6 z-ZZQ?`C)JX@^7XQbN^BbJRNg@;p|_bvsShaW_GqP8y;CZJD967@COVKp!oUbeWrKf z*w}VF_}sRdQ(MpWZr?eE`-B`JBDNz0s_}x~e4^^3<tfXbjE<X&Gw*77Y_^co2}WLH zigdp6?EAZNJ1f5LsR9x}hTk5sV}U`#I`0E?-cY|_^wpL}7&Cj9O&Fde`UX?1CM-5) ze2(LfY(tZ}PVGX`#7I0IE68gyS>($KG0;~z^1XCtWU5+n&91knz-Be5INqeN6PG<8 zJLL28VG|=Le6eOm%sMiaXV8_Qx|QJ0`Wtllv{@J9N{w-nb=(PufUwD!%Ien4^p9L7 z3R;QcO*$PhPPL7BX6(xxYc48R!>fPzspVhA$@fskq9na*Nah}LDY3)0?-7sArg?Ep zCLJPec`c+qj{ix4czK(ae3V)FV4al}TU+;WsOZE}*;Re}p$F~7E??2j4B8*5&=vLt z!f@C(bzMR%&cD!$Z6RoCr_5ihYMi%~9SP-NKd>&~wC?;aMKr#l74N>3!bc@!F+~-1 zex8fdsJ{`X#+2fU{M)VNP~Gkr6`R-Z9jN@p+Ninh)fp3vGiaD|w>HZ+^Ri_r6p!V- z;CWxIZ)_!{@ip6|KG(mS-I~Siz``5l6D&+D^dW~lK1aXecAkp(3!1S!Ux7T5QEq7O z8?|P3ePx&O+=ChIfim1^{9vaJ+wW0%k6~`&ST|ZOT*?{B#v~uW%@mW{mfjo`mC4(= zFo?$+FM-|_utOLxDzl3c8NMi{_|c8u?ZOO`NKyFk8x;PlGq?&?f>@;TiL|EJWN^0G z3m9+JBo0-XevG60@g$v-k{M&DGoOU6!vuHcYZ(>lh6$&WjTEFAiH_{3*r|3i&gBkm zKG2{9V!)r2$#|3dCeP1)z^Wj0Rm!~Ba4-U=k_=QyN*l<~Ar_K%Ta?<M82_UDg+Pk+ zzJIDcdI|J`#**8`mT@E6ebC16cf0}Wi$J$$16)#g!Lx|pUH_(;`CpEYPG%>0dljv0 zP0fBj0SGNU&5KZyBR6L!OgL6dKmf|6J6KWUFc>Ze{0T)<ONzcRS-Q^~Sh=rqchBUC zO=rzM>vXgkqU8yGkxEMEt*L09Bkbd#)<G#v>f-9u&AH7bfrWL?Z1tUkAH5GOP;C9~ zT{WsAeH%+?tQ{mqx@H~Q=1z6r7Uz5I@Mn#p6k`o}>MXrNrVn#u9`qlosRUnH?h?>h z>9oZ6eFzx7@hDvO^2TKS<<|*jJrTN|meTw<VN0vzA-)f)_e&sX2cz<~7&WDLxz_Bw zP1as4MLX9YVx#H7Eb(dS)^B!qMkJOPNW@w!b_uiS-|3Jtx<OV$M7p9=W<WbXF6c~y z)lhPM!FOrYn2r)LS)XP6L#ua!=VGi`*8(ENsQOm7P*S63?E-<^KH&rtQ&+j(v^474 z7~_5Rb3C=YPZKdqCu0$vHu(*5=#5zfJN9&kg(@&rFGil0%|k+XLlREX#nmXycPtH@ z@O+jz-5rktP7%mko(<Ob8u)I@XbVqW3H3^M3<O^8%^C|95=-NvH`RM}Ifyu+4LbF{ zv5br0g_s$tvcFMHn!~*`LmnVFb<leJ9iQ+Xv|w4!p*D@?up7@)u6e1#FWhl+syNIG zvPjX4BI^}tXR>n%Be$X;JxG-%+C{TX&qc3|HKl*WWvX&^pSIiH@Q`34XGBf;`rbFc zrK-CT?7<B@gPazey*upgietg=UMyHRc!cy`@DPr{%C?qkBP++~q#;fIvU_fnqxSuG z(%KI&<J*B4R8li_z2fqc3GS4xf~q;5w48Qbe4cl)6Z8nP6RIDY@@U*Ba%=aze0?D4 zzMIm!Ci&Ip%WBe9vz6yH-}7VJVAb>~2qfKiU<!9AdD^_To+l&l(qGJ@N&JgE7RPax zwK$@xd5WUlbv12qWS@CYH*(l1zR$Mga!Z@-!+NyQD9?%3dz;v-i!EV{%voWj&nP4- z@jA6o(`RTIToF!q#-^xlPc?Z>Rw(#pI{Bts`}m$2w$nBVMZtQ$%!>JG*MvDeO`{fx zxRgiOsyPRfu}<TTj(>R(_|UL^aqJ|BMjU5}BDC+>a7~0ZtH*XE(^pD+31>EE6D=v| z{viC=IvCs$m(iar>AQy>e@pj;SB#NT?=i#9hqCkqZ^_5yTaf#D*?pQZYJIi`ArxFW zctos=lF*N9#h3irweAei6PciksM{sxk5Sl0eic5PM^CMu6?m$aCKke^Arxe(E$l!d zmX=DdDhL@MQZRdwwh@(~b<Y=iXG6hBuAH09m6W02(ZFJNWcOR;Pm7&Ofklj-zSJhH zR|5pAl8t<vq%2B9kA0j51}EgT!cv;O^OMwXZoBI?uHkCFuOEw0So}`jtMY#T$IA$o zo0{fk>sAK&E%ueAy4+lyq<+Z^Uukm2_sCCgh{Rw!YPSIEm2P0Y!t=+G=CmS!Hq6HH z=U#p2P1O^*FV8Pbjx!ZZ9@#fW)`#E<jbF<YDp91MUoUC9-IcheWBMU-hJMRJi$iX+ zkFGvkE~!ku-v8D`CkyBKukHdR_V)V=JU+d<mZ?4>(Agr5M!gz=@1L8qg1O+082E~Q zuvE`ho(kfJL(aAC7LDQf6d^R9ZcEZa(c3GzUGEBJMm>50s}w#oD(H&10&(}}ev?Tw zp}6oONPiV0SY~k}rHe6V&BQ`l8X*r?lz6(=!+vFlk?$!@jxixSttbs);>F-pI%V}- zuiF+XVy{f&yzo|srKOUyl!r<kq=dv5YhK^QCa`TU)ac^R496^jXr1HUTBU*9D`|kV zsqS<+Wa|#*b1Dm)O&5tzv8}h<&cS&tt<hg=UaHYpj!Vp=x-vZ6f(d_XArg?fF3JVp zI-Z4UY78E}?6F2E3&B4xx7B*Euddp?vJHz?EJxX6(S>tAv58b1@qs=WhDCcqX~SR1 ze#kZS9ioom_3Gye6dPG+Kj(J9HFAw@@IEs%-OrU?EOP}XZg`r>T=iMZV(E2?=Zj8l zRZi(g)U85x=e@=*>nXpw9*@Ax-BuWC<;XSBO0c2QyY6ta?4!=LmAxycd&KVT)gVb= z+QkbPYefE+9&vgShKN4NltchOcEn=|vx<rmEX6IIqsYFY`RK7FNzOT~a{+ddY(x*s zu&zya7Ddh|d{fi+LBHkGjP~tD(4971$BSBDLoJ-lcM{^f-+CV%9pD;~;|p3=AY{+K zDQTY$3#lH^7Gi>3Ey&Wa)oYO=-O*a%&0rm)eL^T-<l4+Sc5(mted&#WHqVcvCheuK zYMTy=SShs0ZF1g>y5o+-<m-jaiBNP7LFv<*B0Q#RnN{+w#HJrgu3#5*R|`X*C)kFM z(yZRGqd6aaRG(H(D{N5k0B^T&Avp4ZE*>F`Z2}jp&YeS1s&`pet&TBJbZATE+3xp4 ztgZf*N36u!WVphrolEag>1aamrRCGCYqE}#jEXdb(wNf`8Fnuys)z{_8Py{3&>d}7 zH@joT8T&V^J|?*BKa%_$6i6oIYL00q{CY0z?F-Su48;VCpd!X4@%7=p)S2Qip;rPF z3uIbK7zyh&IWtxMw;qPVb{b<EBa)L7kJ5J+A(__tjOmZL+%Tyqq_ECI!{nTTKS%go z1g82L^xkm{27vwLwG%{p^u+%1ny5l<g1Puv>PH0gi!g@Q+F8{a4EVkxnK6u&c_sR` z+O7!6f#}-eRn$9V?+>x(Fo__^=8l81EOhS&v#T53=B_Ge!*0$*{P64P(w`!aD##im zY2q75Ug*ozT$F<t#HKFc$!~60R&z9Y$CVnb2t`>QN^&ji%o!5d?a15aZqvlfkKR(B zy2+;x?CfA|jW>qYe?D<3K|M!;2KdSW(;tznB^jU>{ywl!fO*kh2LZ}g*^^&Xp|@nY zl+_e@jyh2Qb&y|0FQ5nmMR$&el=FdqLIuV+lD~@m{Vl`y#8&gWsH&`*vLaOT7PqP* zl7NCD1giX3)hH+@mE!=+2X+>KJMphN|J__5?a$BSq{N9n)JX|T*nJZ_Gkb?qMZuL3 z{VMraWjf%Zf7wm{Sv9yk*{SkD;PStxkx0hhQlIwdml7@kuY);Y000tv{5~>#YXHV| zWqGKYCY0O3#Q|KfAw5mwGH}a$fD6s=yBG>ehVO}L=&AFTgV~$?OP2-A%VDO&)&oW& z8KCrud&I9J!}k$zS^vd5wM7DEt=AQ8Bm;nVz~?mU0s)8x?ERZsofzqu`2Jo`f>{T{ zlkB&F3uFkKE7Pw=0Y5W*Xa3CkyLF~#6ItiKw&(z7+76s4>nWlKa4k=rDYA8d8`Xb8 zxpuVNrT|zjaMv!Kf>M(I5vu86_VDaBy4pJsngM6c4rDU8cnT**@h9BBNhgmpwD%zW z4M17s`rG0D7c9efnEGF&--?MpZ86}R0hW44!rn21VgD9>2h+d`;7A%8+nKaqiYfou z`M|2sNGg;AME%D@akfS@xW!;$UL>0qxV)#j&Og}yzA-1G2UzeG$sz*ghNoF)%fEtK z2Nn%Q66yIs#8VQYU=CPW6UmY12XoHQ*#zUjT75{Ij4%lIpEnjPM~CEO0#m0`7wjkJ zpW<}jR)IyikhHJjAlm5(`Pp|9ERBW4l}mteXA5P48wl18LJ}9GLBwCr#UGS}z+|v! z36k6{_XqNS-Waf40g^|n1mgYm9{q=S0k~=4Y|uy)w%VB}WNv6M3Y?4-iTa><77Ce& z^ykU`S87slW#HVE$jV5x|JTaS$Ycqw4xH!^S)I1d|5tTqcVcj=F(me~!CBb9$2enT z;xTYL!3lYgKyBl*fd5F(14e-pa3E1d=4YXPrQ-l|z@hs{PM!7HoYR5)U>-PV8p%W4 zKb!aG5Na?R94v=q|FA!s{g2Q&Fbo_PgM{h3oDBm9$$*Jq_j4ps(erHLZ)bEc3hbPV zMA`fN0rlHe7t8`XKq6UskI!Zy-66p&u)i6SB?>=_^+)eBFc|C`g9Oh7p9wz0QwGcg zyG|gPR8RlRJncvUW`a%ZNTy=gpP68TJD3W##UiQp5oc1*w9JC3U>g>a8W|0u{$7ur zVbKC(!S(?p_UZFKVgGC`0Mo&Hf=K#y{GaHjCnW#aAq2z0+e=9Jg{1!hetNU%#x)GU 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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 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<String> clzPaths = new ArrayList<String>(); + + 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 @@ -<?xml version="1.0" encoding="UTF-8"?> -<struts> - <action name="login" class="org.korben.coderising.litestruts.LoginAction"> - <result name="success">/jsp/homepage.jsp</result> - <result name="fail">/jsp/showLogin.jsp</result> - </action> - <action name="logout" class="org.korben.coderising.litestruts.LogoutAction"> - <result name="success">/jsp/welcome.jsp</result> - <result name="error">/jsp/error.jsp</result> - </action> -</struts> \ No newline at end of file From b4af458bbc21d59ab8ab9a7550387161aa7d2d7a Mon Sep 17 00:00:00 2001 From: Korben_CHY <korben.chy@gmail.com> Date: Sat, 1 Apr 2017 15:22:07 +0800 Subject: [PATCH 095/287] 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<String> clzPaths = new ArrayList<String>(); 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 <korben.chy@gmail.com> Date: Sat, 1 Apr 2017 15:29:21 +0800 Subject: [PATCH 096/287] 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<String, StrutsAction> 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 097/287] 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<String> clzPaths = new ArrayList<String>(); + 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()){ + int len=fis.read(buffer); + if(len<0){ + break; + } + baos.write(buffer, 0, len); + } + if(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<clzPaths.size();i++){ + if(i==0){ + sb.append(clzPaths.get(i)); + }else{ + sb.append(";").append(clzPaths.get(i)); + } + + } + return sb.toString(); + } + + + + + +} diff --git a/group11/542194147/myDataStructure/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group11/542194147/myDataStructure/src/com/coderising/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..8adb2b2448 --- /dev/null +++ b/group11/542194147/myDataStructure/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,94 @@ +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\\john\\Documents\\GitHub\\coding2017\\group11\\542194147\\myDataStructure\\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); + for(byte code:byteCodes){ + System.out.println(code); + } + // 注意:这个字节数可能和你的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/group11/542194147/myDataStructure/src/com/coderising/jvm/test/EmployeeV1.java b/group11/542194147/myDataStructure/src/com/coderising/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..12e3d7efdd --- /dev/null +++ b/group11/542194147/myDataStructure/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/group11/542194147/myDataStructure/src/com/coding/basic/LRUPageFrame.java b/group11/542194147/myDataStructure/src/com/coding/basic/LRUPageFrame.java new file mode 100644 index 0000000000..d37f41e4e4 --- /dev/null +++ b/group11/542194147/myDataStructure/src/com/coding/basic/LRUPageFrame.java @@ -0,0 +1,74 @@ +package com.coding.basic; + +/** + * 用双向链表实现LRU算法 + * @author liuxin + * + */ +public class LRUPageFrame { + + private static class Node { + + Node prev; + Node next; + int pageNum; + + Node() { + } + } + + private int capacity; + private int current; + + private Node first;// 链表头 + private Node last;// 链表尾 + + + public LRUPageFrame(int capacity) { + + this.capacity = capacity; + + } + + /** + * 获取缓存中对象 + * + * @param key + * @return + */ + public void access(int pageNum) { + if(current<capacity){ + current+=1; + if(current==0){ + Node node=new Node(); + node.pageNum=pageNum; + node.prev=null; + node.next=null; + first=node; + last=node; + }else{ + Node node=new Node(); + node.pageNum=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/group11/542194147/myDataStructure/src/com/coding/basic/LRUPageFrameTest.java b/group11/542194147/myDataStructure/src/com/coding/basic/LRUPageFrameTest.java new file mode 100644 index 0000000000..53db234945 --- /dev/null +++ b/group11/542194147/myDataStructure/src/com/coding/basic/LRUPageFrameTest.java @@ -0,0 +1,31 @@ +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()); + } + +} From defa485b9eeaf29a9af5318a42f997478a6c6e3d Mon Sep 17 00:00:00 2001 From: Korben_CHY <korben.chy@gmail.com> Date: Sat, 1 Apr 2017 17:40:44 +0800 Subject: [PATCH 098/287] 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 <wang_lxin@163.com> Date: Sat, 1 Apr 2017 17:44:59 +0800 Subject: [PATCH 099/287] 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<String> list = new ArrayList<String>(); + + 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 f2f1717fb999303e2b39fb01354b090b7a533724 Mon Sep 17 00:00:00 2001 From: GUK0 <1685605435@qq.com> Date: Sat, 1 Apr 2017 18:04:56 +0800 Subject: [PATCH 100/287] =?UTF-8?q?=E7=AC=AC=E4=BA=94=E5=91=A8=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A=EF=BC=8C=E9=A1=BA=E4=BE=BF=E4=BF=AE=E6=94=B9=E4=BA=86?= =?UTF-8?q?=E7=AC=AC=E4=BA=8C=E5=91=A8=E4=BD=9C=E4=B8=9A=E7=9A=84struts?= =?UTF-8?q?=E3=80=82xml=E4=B8=BA=E7=9B=B8=E5=AF=B9=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group12/247565311/week2/Struts.java | 2 +- group12/247565311/week5/ClassFileLoader.java | 63 ++++++++++++++++ .../247565311/week5/ClassFileLoaderTest.java | 72 +++++++++++++++++++ group12/247565311/week5/EmployeeV1.java | 5 ++ group12/247565311/week5/LRU.java | 67 +++++++++++++++++ group12/247565311/week5/LRUTest.java | 36 ++++++++++ 6 files changed, 244 insertions(+), 1 deletion(-) create mode 100644 group12/247565311/week5/ClassFileLoader.java create mode 100644 group12/247565311/week5/ClassFileLoaderTest.java create mode 100644 group12/247565311/week5/EmployeeV1.java create mode 100644 group12/247565311/week5/LRU.java create mode 100644 group12/247565311/week5/LRUTest.java diff --git a/group12/247565311/week2/Struts.java b/group12/247565311/week2/Struts.java index 45658881eb..9c8135be38 100644 --- a/group12/247565311/week2/Struts.java +++ b/group12/247565311/week2/Struts.java @@ -18,7 +18,7 @@ public static View runAction(String actionName,Map<String,String>parameters){ if(actionName == null || parameters == null) return null; List<Element> actions = null; try { - File xmlfile = new File("D:\\5Java\\coding2017\\group12\\247565311\\week2\\struts.xml"); + File xmlfile = new File(System.getProperty("user.dir")+"\\bin\\week2\\struts.xml"); Document doc = new SAXReader().read(xmlfile); Element root = doc.getRootElement(); actions = root.elements(); diff --git a/group12/247565311/week5/ClassFileLoader.java b/group12/247565311/week5/ClassFileLoader.java new file mode 100644 index 0000000000..fc5e920f19 --- /dev/null +++ b/group12/247565311/week5/ClassFileLoader.java @@ -0,0 +1,63 @@ +package week5; + +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<String> clzPaths = new ArrayList<String>(); + + public byte[] readBinaryCode(String className) throws Exception { + for(String s:clzPaths){ + String filename = s+className+".class"; + File file = new File(filename); + if(file.exists())return loadClassFile(filename); + } + return null; + } + + private byte[] loadClassFile(String clzFileName) throws Exception { + File file = new File(clzFileName); + long filelength = file.length(); + byte[]res = null; + if(filelength>Integer.MAX_VALUE)throw new IOException("ļ"); + try { + FileInputStream fileinput = new FileInputStream(file); + res = new byte[(int) filelength]; + int offset=0,length=0; + while(offset<res.length && ((length=fileinput.read(res,offset,res.length-offset))>-1)) + offset += length; + fileinput.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + return res; + } + + public void addClassPath(String path) { + clzPaths.add(path); + } + + public String getClassPath_V1(){ + String res = ""; + int size = clzPaths.size(); + for(int i=0;i<size-1;i++){ + res += clzPaths.get(i); + } + res += clzPaths.get(size-1); + return res; + } + + public String getClassPath(){ + String res = ""; + int size = clzPaths.size(); + for(int i=0;i<size-1;i++){ + res += clzPaths.get(i); + res += ";"; + } + res += clzPaths.get(size-1); + return res; + } +} diff --git a/group12/247565311/week5/ClassFileLoaderTest.java b/group12/247565311/week5/ClassFileLoaderTest.java new file mode 100644 index 0000000000..565203556a --- /dev/null +++ b/group12/247565311/week5/ClassFileLoaderTest.java @@ -0,0 +1,72 @@ +package week5; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class ClassFileLoaderTest { + static String path1 = "F:\\code_language\\demo\\Homework\\bin\\week5\\"; + 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 = "EmployeeV1"; + byte[] byteCodes = new byte[0]; + try { + byteCodes = loader.readBinaryCode(className); + } catch (Exception e) { + e.printStackTrace(); + } + // ע⣺ֽܺJVM汾йϵ Կõൽж + Assert.assertEquals(267, byteCodes.length); + } + + @Test + public void testMagicNumber(){ + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "EmployeeV1"; + byte[] byteCodes = new byte[0]; + try { + byteCodes = loader.readBinaryCode(className); + } catch (Exception e) { + e.printStackTrace(); + } + 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/group12/247565311/week5/EmployeeV1.java b/group12/247565311/week5/EmployeeV1.java new file mode 100644 index 0000000000..22949d2a0b --- /dev/null +++ b/group12/247565311/week5/EmployeeV1.java @@ -0,0 +1,5 @@ +package week5; + +public class EmployeeV1 { + +} diff --git a/group12/247565311/week5/LRU.java b/group12/247565311/week5/LRU.java new file mode 100644 index 0000000000..705b0b0c87 --- /dev/null +++ b/group12/247565311/week5/LRU.java @@ -0,0 +1,67 @@ +package week5; +import java.util.HashSet; + +import week1.ArrayList; +public class LRU { + int size; + Node head = new Node(0); + HashSet<Integer> lib = new HashSet<Integer>(); + class Node{ + int val; + Node next; + public Node(int _val){ + val = _val; + next = null; + } + } + public LRU(int _size){ + if(_size>0) { + this.size = _size; + } + } + public int[] getAll(){ + int length = lib.size(),index = 0; + int []res = new int[length]; + Node p = head.next; + while(p!=null){ + res[index] = p.val; + index += 1; + p = p.next; + } + return res; + } + public void add(int e){ + int index = 0; + if(lib.contains(e)){ + Node p = head; + while(p.next!= null){ + if(p.next.val == e){ + Node newn = p.next; + p.next = newn.next; + newn.next = head.next; + head.next = newn; + break; + } + p = p.next; + } + }else{ + if(lib.size() == size){ + lib.add(e); + Node newn = new Node(e); + newn.next = head.next; + head.next = newn; + Node p = head; + while(p.next.next != null) + p = p.next; + Node deln = p.next; + lib.remove(deln.val); + p.next = null; + }else{ + Node newn = new Node(e); + newn.next = head.next; + head.next = newn; + lib.add(e); + } + } + } +} diff --git a/group12/247565311/week5/LRUTest.java b/group12/247565311/week5/LRUTest.java new file mode 100644 index 0000000000..0ee0d95309 --- /dev/null +++ b/group12/247565311/week5/LRUTest.java @@ -0,0 +1,36 @@ +package week5; + +import static org.junit.Assert.*; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class LRUTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testAdd() { + LRU lru = new LRU(5); + lru.add(3); + lru.add(7); + lru.add(5); + lru.add(8); + lru.add(10); + Assert.assertArrayEquals(new int[]{10,8,5,7,3}, lru.getAll()); + lru.add(5); + lru.add(3); + Assert.assertArrayEquals(new int[]{3,5,10,8,7}, lru.getAll()); + lru.add(8); + lru.add(11); + Assert.assertArrayEquals(new int[]{11,8,3,5,10}, lru.getAll()); + } +} From a5c157639f81ca67b5272daf562ebfa5ccbfe119 Mon Sep 17 00:00:00 2001 From: RalfNick <wang_lxin@163.com> Date: Sat, 1 Apr 2017 18:10:09 +0800 Subject: [PATCH 101/287] 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 102/287] 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<String> clzPaths = new ArrayList<String>(); + 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 <wang_lxin@163.com> Date: Sat, 1 Apr 2017 23:43:17 +0800 Subject: [PATCH 103/287] =?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 12c5a2a026ac6a30d30a54c12451c4ad165d92ce Mon Sep 17 00:00:00 2001 From: earliest <earliest@hotmail.com> Date: Sun, 2 Apr 2017 01:13:03 -0700 Subject: [PATCH 104/287] add jvm homework --- group17/1282579502/src/com/coding/basic/LinkedList.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/group17/1282579502/src/com/coding/basic/LinkedList.java b/group17/1282579502/src/com/coding/basic/LinkedList.java index 55db7e97bc..8f6ce0a9d3 100644 --- a/group17/1282579502/src/com/coding/basic/LinkedList.java +++ b/group17/1282579502/src/com/coding/basic/LinkedList.java @@ -2,9 +2,9 @@ public class LinkedList implements List { - private Node head = null; - private Node tail = null; - private int size = 0; + protected Node head = null; + protected Node tail = null; + protected int size = 0; public void add(Object o){ if(head == null){ @@ -109,7 +109,7 @@ public Iterator iterator(){ return new LinkedListIterator(this); } - private class Node{ + protected class Node{ public Object data = null; public Node next = null; public Node(Object o){ From 459904fd14482ada91f91cc32dd9567baa276c99 Mon Sep 17 00:00:00 2001 From: earliest <earliest@hotmail.com> Date: Sun, 2 Apr 2017 01:13:57 -0700 Subject: [PATCH 105/287] add jvm --- .../jvm/loader/ClassFileLoader.java | 86 +++++++++++++++ .../jvm/test/ClassFileloaderTest.java | 103 ++++++++++++++++++ .../com/coderising/jvm/test/EmployeeV1.java | 28 +++++ 3 files changed, 217 insertions(+) create mode 100644 group17/1282579502/src/com/coderising/jvm/loader/ClassFileLoader.java create mode 100644 group17/1282579502/src/com/coderising/jvm/test/ClassFileloaderTest.java create mode 100644 group17/1282579502/src/com/coderising/jvm/test/EmployeeV1.java diff --git a/group17/1282579502/src/com/coderising/jvm/loader/ClassFileLoader.java b/group17/1282579502/src/com/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..6d669e294f --- /dev/null +++ b/group17/1282579502/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,86 @@ +package com.coderising.jvm.loader; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + + + +public class ClassFileLoader { + + private List<String> clzPaths = new ArrayList<String>(); + + public byte[] readBinaryCode(String className) { + String classPath = convertToFilePath(className); + File targetFile = null; + for(int i = 0; i< clzPaths.size(); i++){ + String fullPath = clzPaths.get(i)+File.separator+classPath; + System.out.println("path: " + fullPath); + File temp = new File(fullPath); + if(temp.exists()) { + targetFile = temp; + break; + } + } + + if(targetFile != null){ + System.out.println("targetFile: " + targetFile.getAbsolutePath()); + } + long fileLength = targetFile.length(); + System.out.println("File length: " + fileLength); + byte[] byteArray = new byte[(int)fileLength]; + FileInputStream is = null; + try { + is = new FileInputStream(targetFile); + is.read(byteArray); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + }finally{ + if(is != null){ + try { + is.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + + return byteArray; + + + } + + private String convertToFilePath(String className){ + return className.replaceAll("\\.", File.separator) + ".class"; + } + + public void addClassPath(String path) { + clzPaths.add(path); + } + + + + public String getClassPath(){ + StringBuilder sb = new StringBuilder(); + for(String item : clzPaths){ + sb.append(item + ";"); + } + return sb.substring(0, sb.length()-1); + } + + + + + +} \ No newline at end of file diff --git a/group17/1282579502/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group17/1282579502/src/com/coderising/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..4df3f4b529 --- /dev/null +++ b/group17/1282579502/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,103 @@ +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"; + static String path3 = "/Users/erlisuo/Documents/workspace/codeRising2017working/1282579502/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() { + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + loader.addClassPath(path2); + loader.addClassPath(path3); + 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); + 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); + } + + + @Test + public void testToHexString(){ + byte b1 = 'a'; + byte b2 = 'b'; + System.out.println("Binary: " + Integer.toBinaryString(b1) + " decimal: " + Integer.toString(b1) + " hex: " + Integer.toHexString(b1)); + System.out.println("Binary: " + Integer.toBinaryString(b2) + " decimal: " + Integer.toString(b2) + " hex: " + Integer.toHexString(b2)); + + byte[] bArray = new byte[]{b1, b2}; + System.out.println(byteToHexString(bArray)); + } + + + + 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/group17/1282579502/src/com/coderising/jvm/test/EmployeeV1.java b/group17/1282579502/src/com/coderising/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..12e3d7efdd --- /dev/null +++ b/group17/1282579502/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 From 940f6bfb87c22caa5297ef195669e5f47ed52c73 Mon Sep 17 00:00:00 2001 From: earliest <earliest@hotmail.com> Date: Sun, 2 Apr 2017 01:16:31 -0700 Subject: [PATCH 106/287] add LRU --- .../coding/basic/linklist/LRUPageFrame.java | 170 ++++++++++++++++++ .../basic/linklist/LRUPageFrameTest.java | 55 ++++++ 2 files changed, 225 insertions(+) create mode 100644 group17/1282579502/src/com/coding/basic/linklist/LRUPageFrame.java create mode 100644 group17/1282579502/src/com/coding/basic/linklist/LRUPageFrameTest.java diff --git a/group17/1282579502/src/com/coding/basic/linklist/LRUPageFrame.java b/group17/1282579502/src/com/coding/basic/linklist/LRUPageFrame.java new file mode 100644 index 0000000000..7e8a8a531a --- /dev/null +++ b/group17/1282579502/src/com/coding/basic/linklist/LRUPageFrame.java @@ -0,0 +1,170 @@ +package com.coding.basic.linklist; + +import java.util.HashMap; + +/** + * 用双向链表实现LRU算法 + * @author liuxin + * + */ +public class LRUPageFrame { + + public static void main(String[] args){ + LRUPageFrame frame = new LRUPageFrame(3); + frame.access(7); + frame.access(0); + frame.access(1); + System.out.println("array: " + frame.toString()); + frame.access(2); + System.out.println("array: " + frame.toString()); + + frame.access(0); + System.out.println("array: " + frame.toString()); + frame.access(0); + System.out.println("array: " + frame.toString()); + frame.access(3); + System.out.println("array: " + frame.toString()); + //frame.printList(); + frame.access(0); + //frame.printList(); + System.out.println("array: " + frame.toString()); + System.out.println(); + frame.access(4); + //frame.printList(); + System.out.println(frame); + } + + private static class Node { + + Node prev; + Node next; + int pageNum; + + Node() { + } + } + + private int capacity; + + private int count; + private Node first;// 链表头 + private Node last;// 链表尾 + + private HashMap<Integer, Node> keyHash; + + public LRUPageFrame(int capacity) { + + this.capacity = capacity; + this.count = 0; + keyHash = new HashMap<Integer, Node>(); + first = new Node(); + first.pageNum = -99; + last = new Node(); + last.pageNum = -99; + first.next = last; + } + + /** + * 获取缓存中对象 + * + * @param key + * @return + */ + public void access(int pageNum) { + Node targetPageNode = keyHash.get(new Integer(pageNum)); + + if(targetPageNode == null){ + targetPageNode = new Node(); + targetPageNode.pageNum = pageNum; + addNewPage(targetPageNode); + } + else{ + moveToTop(targetPageNode); + } + + } + /* + * null - first - f1 - f2 -f3 + */ + private void moveToTop(Node targetNode){ + if(targetNode != first.next){ + targetNode.prev.next = targetNode.next; + if(targetNode.next != null){ + targetNode.next.prev = targetNode.prev; + } + + targetNode.next = first.next; + if(first.next != null){ + first.next.prev = targetNode; + } + + first.next = targetNode; + targetNode.prev = first; + } + } + + private void addNewPage(Node targetPageNode){ + //first.next ?= null + // + targetPageNode.next = first.next; + if(first.next != null){ + first.next.prev = targetPageNode; + } + + first.next = targetPageNode; + targetPageNode.prev = first; + + keyHash.put(targetPageNode.pageNum, targetPageNode); + count++; + if(count > capacity){ + popOutLast(); + } + } + /* + * t3 - t2 - t1 - last - null + */ + private void popOutLast(){ + Node tailNode = last.prev; //t1 + if(tailNode != null){ + Node preTailNode = tailNode.prev; //t2 + if(preTailNode != null){ + keyHash.remove(preTailNode.pageNum); + preTailNode.next = last; //t2 -> last + last.prev = preTailNode; + count --; + } + } + } + public void printList(){ + int tmpcount = 0; + Node node = first.next; + while(node != last && tmpcount++<20){ + System.out.println("current: "+node.pageNum+ " parent: " + node.prev.pageNum); + node = node.next; + } + } + + public String toString(){ + StringBuilder buffer = new StringBuilder(); + Node node = first.next; + while(node != null){ + if(node == last) break; + buffer.append(node.pageNum); + + node = node.next; + if(node != null){ + buffer.append(","); + } + + } + + String returnStr = null; + if(buffer.charAt(buffer.length() -1 ) == ','){ + returnStr = buffer.substring(0, buffer.length() -1); + }else{ + returnStr = buffer.toString(); + } + return returnStr; + } + +} \ No newline at end of file diff --git a/group17/1282579502/src/com/coding/basic/linklist/LRUPageFrameTest.java b/group17/1282579502/src/com/coding/basic/linklist/LRUPageFrameTest.java new file mode 100644 index 0000000000..0bfbe14fd0 --- /dev/null +++ b/group17/1282579502/src/com/coding/basic/linklist/LRUPageFrameTest.java @@ -0,0 +1,55 @@ +package com.coding.basic.linklist; + +import org.junit.Assert; + +import org.junit.Test; + + +public class LRUPageFrameTest { + +// @Test +// public void toStringTest(){ +// LRUPageFrame frame = new LRUPageFrame(3); +// frame.access(7); +// frame.access(0); +// frame.access(1); +// System.out.println("array: " + frame.toString()); +// frame.access(2); +// System.out.println("array: " + frame.toString()); +// +// frame.access(0); +// System.out.println("array: " + frame.toString()); +// frame.access(0); +// System.out.println("array: " + frame.toString()); +// frame.access(3); +// System.out.println("array: " + frame.toString()); +// +// frame.access(0); +// System.out.println("array: " + frame.toString()); +// +// frame.access(4); +// System.out.println("array: " + frame.toString()); +// } + + @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()); + } + +} \ No newline at end of file From 4d40a1a530550580443cf64cb49047fe8b6899f8 Mon Sep 17 00:00:00 2001 From: Kimi <zhoushuiqing05@hotmail.com> Date: Sun, 2 Apr 2017 17:05:47 +0800 Subject: [PATCH 107/287] add LRU also --- group12/349166103/LRUPageFrame.java | 108 ++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 group12/349166103/LRUPageFrame.java diff --git a/group12/349166103/LRUPageFrame.java b/group12/349166103/LRUPageFrame.java new file mode 100644 index 0000000000..4dda68632d --- /dev/null +++ b/group12/349166103/LRUPageFrame.java @@ -0,0 +1,108 @@ + + +public class LRUPageFrame { + + private static class Node { + + Node prev; + Node next; + int pageNum; + + Node(int Num) { + pageNum=Num; + } + } + + private int capacity; + + + private Node first;// 链表头 + private Node last;// 链表尾 + + private int nodeNum = 0; + + public LRUPageFrame(int capacity) { + + this.capacity = capacity; + + } + + /** + * 获取缓存中对象 + * + * @param key + * @return + */ + public void access(int pageNum) { + int isPageNum = isContained(pageNum); + if(isPageNum!=-1){ + int index = 0; + Node node = first; + while(index!=isPageNum){ // move to the Node + node=node.next; + index++; + } + if(index != 0){ + if(node.next == null){ + node.prev.next = null; + }else{ + node.prev.next = node.next; + } + node.next = first; + first = node; + } + }else{ + if(first != null){ + Node tmp = new Node(pageNum); + tmp.next = first; + first.prev = tmp; + first = tmp; + nodeNum++; + if(nodeNum > capacity){ + Node node = first; + for(int i=0;i<capacity-1;i++){ + node=node.next; + } + node.next.prev = null; + node.next = null; + } + }else{ + first = new Node(pageNum); + nodeNum++; + } + } + + } + + private int isContained(int pageNum){ + Node node = first; + int result = 0; + while(node != null){ + if(node.pageNum == pageNum){ + return result; + }else{ + node = node.next; + result++; + } + } + result = -1; + return result; + } + + + + 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(); + } + +} From ad9f5357d165dd14e82d9471a5185e51f6b1c3a2 Mon Sep 17 00:00:00 2001 From: xukai <xukai@raycloud.com> Date: Sun, 2 Apr 2017 22:09:42 +0800 Subject: [PATCH 108/287] =?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<String> clzPaths = new ArrayList<String>(); + + 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<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/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/test/EmployeeV1.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..0dcfd18b96 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/test/EmployeeV1.java @@ -0,0 +1,28 @@ +package org.xukai.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 db9e1f90a2f9440c574040a970b5226f31239717 Mon Sep 17 00:00:00 2001 From: ZhaoHongxin <zhaohongxin621@126.com> Date: Mon, 3 Apr 2017 10:15:18 +0800 Subject: [PATCH 109/287] LRU complete --- .../src/com/coding/lru/LRUPageFrame.java | 71 ++++++++++++++++++- .../src/com/coding/lru/LRUPageFrameTest.java | 7 ++ 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/group05/1094051862/test01/src/com/coding/lru/LRUPageFrame.java b/group05/1094051862/test01/src/com/coding/lru/LRUPageFrame.java index 19b17e49e5..3788724596 100644 --- a/group05/1094051862/test01/src/com/coding/lru/LRUPageFrame.java +++ b/group05/1094051862/test01/src/com/coding/lru/LRUPageFrame.java @@ -38,7 +38,75 @@ public LRUPageFrame(int capacity) { */ public void access(int pageNum) { - + if (first == null) { + accessFirst(pageNum); + return; + } + if (capacity > 0) { + accessNormally(pageNum); + capacity --; + } else { + Node node = first; + while(node != null) { + + if (node.pageNum == pageNum) { + accessNodeExisting(node); + return; + } + + node = node.next; + } + + accessNormally(pageNum); + + removeLast(); + } + + } + + private void accessNodeExisting(Node node) { + if (node.next == null) { //最后一个元素为要添加的元素 + removeLast(); + exchangeFirstWithNode(node); + } else if (node.prev != null) { //要添加的元素在中间 + Node n = node.next; + Node p = node.prev; + p.next = n; + n.prev = p; + + exchangeFirstWithNode(node); + } + } + + private void exchangeFirstWithNode(Node node) { + node.next = first; + first.prev = node; + node.prev = null; //忘记这个就会导致找不到第一个添加的元素,测试出现堆溢出 + first = node; + } + + private void removeLast() { + last = last.prev; + last.next = null; + } + + private void accessNormally(int pageNum) { + + Node temp = first; + first = new Node(); + first.pageNum = pageNum; + first.next = temp; + temp.prev = first; + + } + + private void accessFirst(int pageNum) { + + first = new Node(); + first.pageNum = pageNum; + last = first; + capacity --; + } @@ -53,6 +121,7 @@ public String toString(){ if(node != null){ buffer.append(","); } + } return buffer.toString(); } diff --git a/group05/1094051862/test01/src/com/coding/lru/LRUPageFrameTest.java b/group05/1094051862/test01/src/com/coding/lru/LRUPageFrameTest.java index 75220cc9c1..5f56d9483f 100644 --- a/group05/1094051862/test01/src/com/coding/lru/LRUPageFrameTest.java +++ b/group05/1094051862/test01/src/com/coding/lru/LRUPageFrameTest.java @@ -14,18 +14,25 @@ public void testAccess() { frame.access(0); frame.access(1); Assert.assertEquals("1,0,7", frame.toString()); + System.out.println(frame.toString()); frame.access(2); Assert.assertEquals("2,1,0", frame.toString()); + System.out.println(frame.toString()); frame.access(0); Assert.assertEquals("0,2,1", frame.toString()); + System.out.println(frame.toString()); frame.access(0); Assert.assertEquals("0,2,1", frame.toString()); + System.out.println(frame.toString()); frame.access(3); Assert.assertEquals("3,0,2", frame.toString()); + System.out.println(frame.toString()); frame.access(0); Assert.assertEquals("0,3,2", frame.toString()); + System.out.println(frame.toString()); frame.access(4); Assert.assertEquals("4,0,3", frame.toString()); + System.out.println(frame.toString()); } } From 2d1be53c667bd41ef2f8a373883c46cc1c8df701 Mon Sep 17 00:00:00 2001 From: zhanglei <383117348@qq.com> Date: Mon, 3 Apr 2017 11:35:41 +0800 Subject: [PATCH 110/287] =?UTF-8?q?383117348LRU=E7=AE=97=E6=B3=95=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coding/basic/linklist/LRUPageFrame.java | 139 ++++++++++ .../basic/linklist/LRUPageFrameTest.java | 30 +++ .../basic/{ => linklist}/LinkedList.java | 246 ++++++++---------- 3 files changed, 276 insertions(+), 139 deletions(-) create mode 100644 group27/383117348/src/com/coding/basic/linklist/LRUPageFrame.java create mode 100644 group27/383117348/src/com/coding/basic/linklist/LRUPageFrameTest.java rename group27/383117348/src/com/coding/basic/{ => linklist}/LinkedList.java (61%) diff --git a/group27/383117348/src/com/coding/basic/linklist/LRUPageFrame.java b/group27/383117348/src/com/coding/basic/linklist/LRUPageFrame.java new file mode 100644 index 0000000000..20b393843e --- /dev/null +++ b/group27/383117348/src/com/coding/basic/linklist/LRUPageFrame.java @@ -0,0 +1,139 @@ +package com.coding.basic.linklist; + + +/** + * 用双向链表实现LRU算法 + * + * @author liuxin + * + */ +public class LRUPageFrame { + + private static class Node { + + Node prev; + Node next; + int pageNum; + + Node() { + } + } + /** + * LRU算法: + */ + private int capacity; + private int size; + + private Node first;// 链表头 + private Node last;// 链表尾 + + public LRUPageFrame(int capacity) { + + this.capacity = capacity; + + } + + /** + * 获取缓存中对象 + * + * @param key + * @return + */ + public void access(int pageNum) { + Node node = checkExist(pageNum); + //如果这个页面在缓存中存在 + if (node != null) { + // 将当前节点移动至第一个 + moveTofirst(node); + } else { + //不存在后比较当前是否已经满队列了 + if (size < capacity) { + //如果还有空闲队列 + // 添加一个节点在栈顶 + final Node n = first; + final Node firstNode = new Node(); + firstNode.next = n; + firstNode.pageNum = pageNum; + firstNode.prev = null; + this.first = firstNode; + if (n == null) { + last = firstNode; + } else { + n.prev = firstNode; + } + size++; + } else { + //否则,添加一个节点在栈顶,栈底的节点移除 + addNode(pageNum); + } + } + } + //如果超出了缓存范围,则添加到栈顶,栈底的节点移除 + private void addNode(int pageNum) { + Node node = new Node(); + node.pageNum = pageNum; + node.next = first; + first.prev = node; + first = node; + last = last.prev; + last.next = null; + } + /** + * 如果在队列中存在,则移动至首位 + * @param node + */ + private void moveTofirst(Node node) { + if(node==first){ + return; + } + if(node==last){ + first.prev = node; + node.next = first; + first = node; + last = node.prev; + last.next = null; + first.prev = null; + + }else{ + node.prev.next = node.next; + node.next.prev = node.prev; + node.prev = null; + node.next = first; + first.prev = node; + first = node; + } + + } + + /** + * 检查是否在队列中存在页数 + * @param pageNum + * @return + */ + private Node checkExist(int pageNum) { + Node node = first; + for(int i=0;i<size;i++){ + if(pageNum==node.pageNum){ + return node; + } + node=node.next; + } + 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(); + } + +} \ No newline at end of file diff --git a/group27/383117348/src/com/coding/basic/linklist/LRUPageFrameTest.java b/group27/383117348/src/com/coding/basic/linklist/LRUPageFrameTest.java new file mode 100644 index 0000000000..ef7b599e58 --- /dev/null +++ b/group27/383117348/src/com/coding/basic/linklist/LRUPageFrameTest.java @@ -0,0 +1,30 @@ +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()); + } + +} \ No newline at end of file diff --git a/group27/383117348/src/com/coding/basic/LinkedList.java b/group27/383117348/src/com/coding/basic/linklist/LinkedList.java similarity index 61% rename from group27/383117348/src/com/coding/basic/LinkedList.java rename to group27/383117348/src/com/coding/basic/linklist/LinkedList.java index 56cead0c67..7a36a83263 100644 --- a/group27/383117348/src/com/coding/basic/LinkedList.java +++ b/group27/383117348/src/com/coding/basic/linklist/LinkedList.java @@ -1,10 +1,13 @@ -package com.coding.basic; +package com.coding.basic.linklist; import java.util.Arrays; import java.util.NoSuchElementException; import org.junit.Test; +import com.coding.basic.Iterator; +import com.coding.basic.List; + public class LinkedList implements List { private Node first; @@ -75,26 +78,19 @@ public Object get(int index) { */ public Object remove(int index) { checkIndex(index); - Node current = getNodeByIndex(index); - final Node node = current; - final Node prev = node.prev; - final Node next = node.next; - if (prev == null) { - first = next; - } else { - prev.next = next; - next.prev = prev; - current = null; - } - if (next == null) { - last = prev; + Node element = first; + if (index == 0) { + first = first.next; } else { - prev.next = next; - next.prev = prev; - current = null; + Node pos = first; + for (int i = 0; i < index - 1; i++) { + pos = pos.next; + } + element = pos.next; + pos.next = pos.next.next; } size--; - return node.data; + return element.data; } /** @@ -267,171 +263,143 @@ private Node() { } } + /** - * 把该链表逆置 - * 例如链表为 3->7->10 , 逆置后变为 10->7->3 + * 把该链表逆置 例如链表为 3->7->10 , 逆置后变为 10->7->3 */ - public void reverse(){ - Node head = first; - Node reverse = null; - while (head != null) { - Node second = head.next; - head.next = reverse; - reverse = head; - head = second; - } - first = reverse; - } - //有问题 + public void reverse() { + if (size == 0) + return; + + for (int i = 1; i < size; i++) { + addFirst(get(i)); + remove(i + 1); + } + + } + @Test - public void testReverse(){ + public void testReverse() { LinkedList list = getList(); Iterator ite = list.iterator(); - while(ite.hasNext()){ - System.out.print(ite.next()+" "); + while (ite.hasNext()) { + System.out.print(ite.next() + " "); } list.reverse(); Iterator it = list.iterator(); - while(it.hasNext()){ - System.out.println("----"); - System.out.print(it.next()+" "); + while (it.hasNext()) { + System.out.print("----"); + System.out.print(it.next() + " "); } } - + /** - * 删除一个单链表的前半部分 - * 例如: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(){ - int mid = (int) Math.ceil(size/2.0); - for(int x=0;x<mid;x++){ - Node node =getNodeByIndex(x); - node = null; + public void removeFirstHalf() { + if (size == 0) + return; + + int removeNum = size / 2; + for (int i = 0; i < removeNum; i++) { + removeFirst(); } - Node node = getNodeByIndex(mid); - first = node; - first.prev = null; } - + /** * 从第i个元素开始, 删除length 个元素 , 注意i从0开始 + * * @param i * @param length */ - public void remove(int i, int length){ - if(i>0){ - - Node prev = getNodeByIndex(i-1); - Node next = getNodeByIndex(i+length); - for(int x=i;x<i+length;x++){ - Node node = getNodeByIndex(x); - node = null; - } - prev.next = next; - next.prev = prev; - }else if(i==0){ - Node [] nodes = new Node[length]; - for(int x = i;x<i+length;x++){ - nodes[x] = getNodeByIndex(x); - } - first = getNodeByIndex(i+length); - first.prev = null; - for(int x=0;x<nodes.length;x++){ - nodes[x] = null; - } - }else{ - throw new IndexOutOfBoundsException(); + public void remove(int i, int length) { + if (length + i > size || i < 0 || i >= size) + return; + + for (int k = i; k < (length + i); k++) { + remove(i); } } + /** - * 假定当前链表和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 int[] getElements(LinkedList list){ - int[] array = new int[list.size]; - for (int i = 0; i < array.length; i++) { - int element = (int) list.get(i); - array[i] = ((Integer) get(element)); - } - - System.out.println(Arrays.toString(array)); + public int[] getElements(LinkedList list) { + int[] array = new int[list.size]; + for (int i = 0; i < array.length; i++) { + int element = (int) list.get(i); + array[i] = ((Integer) get(element)); + } - return array; + return array; } - + /** - * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 - * 从当前链表中中删除在list中出现的元素 + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 从当前链表中中删除在list中出现的元素 + * * @param list */ - - public void subtract(LinkedList list){ + + public void subtract(LinkedList list) { int length = list.size(); - for (int i = size - 1; i >= 0; i--) { - for (int j = 0; j < length; j++) { - if (get(i) == list.get(j)) { - remove(i); - break; - } - } - } - } - + for (int i = size - 1; i >= 0; i--) { + for (int j = 0; j < length; j++) { + if (get(i) == list.get(j)) { + remove(i); + break; + } + } + } + } + /** - * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 - * 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) + * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) */ - public void removeDuplicateValues(){ + public void removeDuplicateValues() { for (int i = size - 1; i > 0; i--) { - if (get(i) == get(i - 1)) { - remove(i); - } - } + if (get(i) == get(i - 1)) { + remove(i); + } + } } - + /** - * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 - * 试写一高效的算法,删除表中所有值大于min且小于max的元素(若表中存在这样的元素) + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 试写一高效的算法,删除表中所有值大于min且小于max的元素(若表中存在这样的元素) + * * @param min * @param max */ - public void removeRange(int min, int max){ + public void removeRange(int min, int max) { for (int i = size - 1; i >= 0; i--) { - int element = ((int) get(i)); - if ((element > min) && element < max) { - remove(i); - } - } + int element = ((int) get(i)); + if ((element > min) && element < max) { + remove(i); + } + } } - + /** * 假设当前链表和参数list指定的链表均以元素依值递增有序排列(同一表中的元素值各不相同) * 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列 + * * @param list */ - public LinkedList intersection( LinkedList list){ + public LinkedList intersection(LinkedList list) { LinkedList newList = new LinkedList(); - int length = list.size(); - for (int i = 0; i < size; i++) { - for (int j = 0; j < length; j++) { - if (get(i) == list.get(j)) { - newList.add(get(i)); - break; - } - } - } - - Iterator it = newList.iterator(); - while (it.hasNext()) { - System.out.print(it.next() + " "); - } - System.out.println(); - return newList; + for (int i = 0; i < size; i++) { + for (int j = 0; j < list.size; j++) { + if (get(i).equals(list.get(j))) { + newList.add(list.get(j)); + break; + } + } + } + return newList; } /*------------------------------------------------------单元测试----------------------------------------------------*/ @@ -542,8 +510,8 @@ public void TestIterator() { System.out.println(ite.next()); } } - - private LinkedList getList(){ + + private LinkedList getList() { LinkedList list = new LinkedList(); for (int i = 0; i < 10; i++) { list.add(i); From e64be7c6e9e0b4aa691135e4a6d51802ec5437db Mon Sep 17 00:00:00 2001 From: JayXu <xuweijay@163.com> Date: Mon, 3 Apr 2017 12:41:45 +0800 Subject: [PATCH 111/287] 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 @@ <component name="ChangeListManager"> <list default="true" id="d338ed3a-e900-486a-89a5-3e8b0a3835ed" name="Default" comment=""> <change type="MODIFICATION" beforePath="$PROJECT_DIR$/.idea/workspace.xml" afterPath="$PROJECT_DIR$/.idea/workspace.xml" /> - <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/com/coding/basic/BinarySearchTree.java" afterPath="$PROJECT_DIR$/src/com/coding/basic/BinarySearchTree.java" /> - <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/com/coding/basic/ReConstructBST.java" afterPath="$PROJECT_DIR$/src/com/coding/basic/ReConstructBST.java" /> </list> <ignored path="$PROJECT_DIR$/out/" /> <option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" /> @@ -30,7 +28,7 @@ <favorites_list name="1511_714512544" /> </component> <component name="FileEditorManager"> - <leaf SIDE_TABS_SIZE_LIMIT_KEY="375" /> + <leaf /> </component> <component name="FileTemplateManagerImpl"> <option name="RECENT_TEMPLATES"> @@ -100,6 +98,9 @@ <foldersAlwaysOnTop value="true" /> </navigator> <panes> + <pane id="Scope" /> + <pane id="Scratches" /> + <pane id="PackagesPane" /> <pane id="ProjectPane"> <subPane> <PATH> @@ -172,9 +173,6 @@ </PATH> </subPane> </pane> - <pane id="Scratches" /> - <pane id="PackagesPane" /> - <pane id="Scope" /> </panes> </component> <component name="PropertiesComponent"> @@ -199,6 +197,18 @@ <recent name="D:\AlgorithmsIDEA\coding2017\group15\1511_714512544\src\com\coderising\download" /> </key> </component> + <component name="RunDashboard"> + <option name="ruleStates"> + <list> + <RuleState> + <option name="name" value="ConfigurationTypeDashboardGroupingRule" /> + </RuleState> + <RuleState> + <option name="name" value="StatusDashboardGroupingRule" /> + </RuleState> + </list> + </option> + </component> <component name="RunManager" selected="JUnit.ReConstructBSTTest.construct"> <configuration default="false" name="FileDownloaderTest.testDownload" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true"> <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea"> @@ -770,6 +780,7 @@ <workItem from="1489647273393" duration="3740000" /> <workItem from="1489654640274" duration="1134000" /> <workItem from="1489658627416" duration="365000" /> + <workItem from="1491137983322" duration="25000" /> </task> <task id="LOCAL-00001" summary="xuweijay"> <created>1488937445293</created> @@ -877,7 +888,7 @@ </history-entry> </component> <component name="TimeTrackingManager"> - <option name="totallyTimeSpent" value="66350000" /> + <option name="totallyTimeSpent" value="66375000" /> </component> <component name="TodoView"> <todo-panel id="selected-file"> @@ -890,7 +901,6 @@ </component> <component name="ToolWindowManager"> <frame x="-9" y="-9" width="1938" height="1048" extended-state="6" /> - <editor active="false" /> <layout> <window_info id="Palette" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" /> <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3295583" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" /> @@ -900,20 +910,20 @@ <window_info id="Capture Analysis" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" /> <window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3295583" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" /> <window_info id="Maven Projects" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> - <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3295583" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3295583" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" /> + <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3295583" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> <window_info id="Properties" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="8" side_tool="false" content_ui="tabs" /> <window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> <window_info id="Capture Tool" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> <window_info id="Designer" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" /> - <window_info id="Project" active="true" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.22800429" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" /> + <window_info id="Project" active="true" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.22961374" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" /> <window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="9" side_tool="false" content_ui="tabs" /> <window_info id="Structure" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.23444206" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" /> <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" /> <window_info id="UI Designer" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" /> <window_info id="Theme Preview" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="10" side_tool="false" content_ui="tabs" /> - <window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="true" content_ui="tabs" /> <window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3997735" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> + <window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="true" content_ui="tabs" /> <window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" /> <window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" /> <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" /> @@ -1215,24 +1225,6 @@ <provider selected="true" editor-type-id="text-editor"> <state relative-caret-position="379"> <caret line="65" column="5" lean-forward="true" selection-start-line="65" selection-start-column="5" selection-end-line="65" selection-end-column="5" /> - <folding> - <element signature="e#600#601#0" expanded="false" /> - <element signature="e#641#642#0" expanded="false" /> - <element signature="e#679#680#0" expanded="false" /> - <element signature="e#713#714#0" expanded="false" /> - <element signature="e#766#767#0" expanded="false" /> - <element signature="e#803#804#0" expanded="false" /> - <element signature="e#841#842#0" expanded="false" /> - <element signature="e#875#876#0" expanded="false" /> - <element signature="e#928#929#0" expanded="false" /> - <element signature="e#965#966#0" expanded="false" /> - <element signature="e#1004#1005#0" expanded="false" /> - <element signature="e#1039#1040#0" expanded="false" /> - <element signature="e#1093#1094#0" expanded="false" /> - <element signature="e#1131#1132#0" expanded="false" /> - <element signature="e#1171#1172#0" expanded="false" /> - <element signature="e#1212#1213#0" expanded="false" /> - </folding> </state> </provider> </entry> 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 112/287] =?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 @@ -<?xml version="1.0" encoding="UTF-8"?> -<struts> - <action name="login" class="org.wsc.litestruts.LoginAction"> - <result name="success">/jsp/homepage.jsp</result> - <result name="fail">/jsp/showLogin.jsp</result> - </action> - <action name="logout" class="org.wsc.litestruts.LogoutAction"> - <result name = "success">/jsp/welcome.jsp</result> - <result name = "error">/jsp/error.jsp</result> - </action> -</struts> \ 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; + +/** + * <h3>LRU算法</h3> + * <p> + * 最近最少使用 + * </p> + * + * @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<String> clzPaths = new ArrayList<String>(); + /** 默认缓冲大小 */ + 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 3e7a31a1bea24c7481aa0e36764e58955d40bad7 Mon Sep 17 00:00:00 2001 From: qilei <qilei@wepiao.com> Date: Mon, 3 Apr 2017 19:08:46 +0800 Subject: [PATCH 113/287] mini jvm --- .../example/jvm/loader/ClassFileLoader.java | 70 +++++++++++++++++ .../jvm/loader/ClassFileLoaderTest.java | 78 +++++++++++++++++++ .../com/example/jvm/loader/EmployeeV1.java | 28 +++++++ 3 files changed, 176 insertions(+) create mode 100644 group04/916758663/minijvm/src/main/java/com/example/jvm/loader/ClassFileLoader.java create mode 100644 group04/916758663/minijvm/src/test/java/com/example/jvm/loader/ClassFileLoaderTest.java create mode 100644 group04/916758663/minijvm/src/test/java/com/example/jvm/loader/EmployeeV1.java diff --git a/group04/916758663/minijvm/src/main/java/com/example/jvm/loader/ClassFileLoader.java b/group04/916758663/minijvm/src/main/java/com/example/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..cb860bf053 --- /dev/null +++ b/group04/916758663/minijvm/src/main/java/com/example/jvm/loader/ClassFileLoader.java @@ -0,0 +1,70 @@ +package com.example.jvm.loader; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + + + +public class ClassFileLoader { + + private List<String> clzPaths = new ArrayList<String>(); + + public byte[] readBinaryCode(String className) { + String filePartPath = className.replace(".", "/") + ".class"; + for (String clzPath : clzPaths) { + String filePath = clzPath + "/" + filePartPath; + File file = new File(filePath); + if (file.exists()) { + try { + FileInputStream inputStream = new FileInputStream(file); + int bytesRead = 0; + int len = inputStream.available(); + byte[] buffer = new byte[len]; + while (bytesRead < len) { + int result = inputStream.read(buffer, bytesRead, len - bytesRead); + if (result == -1){ + break; + } + bytesRead += result; + } + inputStream.close(); + return buffer; + } catch (FileNotFoundException e) { + e.printStackTrace(); + }catch (IOException e) { + e.printStackTrace(); + } + } + } + throw new RuntimeException("未找到类"); + } + + + public void addClassPath(String path) { + clzPaths.add(path); + } + + public String getClassPath(){ + String result = ""; + StringBuilder sb = new StringBuilder(); + for(String path : clzPaths){ + sb.append(path + ";"); + } + result = sb.toString(); + if (result != "") { + result = result.substring(0, result.length() - 1); + } + return result; + } + + + + + +} diff --git a/group04/916758663/minijvm/src/test/java/com/example/jvm/loader/ClassFileLoaderTest.java b/group04/916758663/minijvm/src/test/java/com/example/jvm/loader/ClassFileLoaderTest.java new file mode 100644 index 0000000000..04bb301b5e --- /dev/null +++ b/group04/916758663/minijvm/src/test/java/com/example/jvm/loader/ClassFileLoaderTest.java @@ -0,0 +1,78 @@ +package com.example.jvm.loader; + + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * Created by qilei on 17/4/3. + */ +public class ClassFileLoaderTest { + + static String path1 = "/Users/qilei/idea/coding2017/coding2017/group04/916758663/minijvm/target/test-classes"; + static String path2 = "/Users/qilei/idea/coding2017/coding2017/group04/916758663/minijvm/target/classes"; + + @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.example.jvm.loader.EmployeeV1"; + + byte[] byteCodes = loader.readBinaryCode(className); + + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + Assert.assertEquals(1054, byteCodes.length); + + } + + @Test + public void testMagicNumber(){ + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "com.example.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<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/group04/916758663/minijvm/src/test/java/com/example/jvm/loader/EmployeeV1.java b/group04/916758663/minijvm/src/test/java/com/example/jvm/loader/EmployeeV1.java new file mode 100644 index 0000000000..91d629e922 --- /dev/null +++ b/group04/916758663/minijvm/src/test/java/com/example/jvm/loader/EmployeeV1.java @@ -0,0 +1,28 @@ +package com.example.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(); + + } +} \ No newline at end of file From 46d1bb6d8b2aeb1219300b0456feb60c792719c0 Mon Sep 17 00:00:00 2001 From: ZhaoHongxin <zhaohongxin621@126.com> Date: Mon, 3 Apr 2017 22:40:21 +0800 Subject: [PATCH 114/287] =?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 92fda2317d18eb1482cbd884c387f68690c756d9 Mon Sep 17 00:00:00 2001 From: Administrator <Administrator@win-10> Date: Tue, 4 Apr 2017 10:37:23 +0800 Subject: [PATCH 115/287] add miniJvm --- .../jvm/loader/ClassFileLoader.java | 83 +++++++++++++++++ .../jvm/test/ClassFileloaderTest.java | 93 +++++++++++++++++++ .../com/coderising/jvm/test/EmployeeV1.java | 28 ++++++ 3 files changed, 204 insertions(+) create mode 100644 group04/498654356/mini-jvm/jvm/src/main/java/com/coderising/jvm/loader/ClassFileLoader.java create mode 100644 group04/498654356/mini-jvm/jvm/src/test/java/com/coderising/jvm/test/ClassFileloaderTest.java create mode 100644 group04/498654356/mini-jvm/jvm/src/test/java/com/coderising/jvm/test/EmployeeV1.java diff --git a/group04/498654356/mini-jvm/jvm/src/main/java/com/coderising/jvm/loader/ClassFileLoader.java b/group04/498654356/mini-jvm/jvm/src/main/java/com/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..d4e0f52537 --- /dev/null +++ b/group04/498654356/mini-jvm/jvm/src/main/java/com/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,83 @@ +package com.coderising.jvm.loader; + +import java.io.ByteArrayOutputStream; +import java.io.Closeable; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; + + + +public class ClassFileLoader { + + private static final String CLASS_SUFFIX = ".class"; + private static final byte[] EMPTY_BYTES = new byte[0]; + private List<String> clzPaths = new ArrayList<String>(); + + public byte[] readBinaryCode(String className) { + if(StringUtils.isEmpty(className)) { + return EMPTY_BYTES; + } + String child = className.replaceAll("\\.", "\\\\") + CLASS_SUFFIX; + for (String parent: clzPaths) { + File file = new File(parent, child); + if(file.exists()) { + return doReadBinaryCode(file); + } + } + return EMPTY_BYTES; + } + + + private byte[] doReadBinaryCode(File file) { + FileInputStream fis = null; + ByteArrayOutputStream baos = null; + try { + fis = new FileInputStream(file); + baos = new ByteArrayOutputStream(); + byte[] b = new byte[1024]; + int len = 0; + while((len = fis.read(b)) > 0) { + baos.write(b, 0, len); + } + return baos.toByteArray(); + } catch (Exception e) { + new RuntimeException(e); + } finally { + close(baos); + close(fis); + } + return EMPTY_BYTES; + } + + + private void close(Closeable stream) { + if(stream != null ) { + try { + stream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public void addClassPath(String path) { + clzPaths.add(path); + } + + public String getClassPath(){ + StringBuilder builder = new StringBuilder(); + for (String path : clzPaths) { + builder.append(path).append(";"); + } + if(builder.length() > 0) { + builder = builder.deleteCharAt(builder.length() - 1); + } + return builder.toString(); + } + +} diff --git a/group04/498654356/mini-jvm/jvm/src/test/java/com/coderising/jvm/test/ClassFileloaderTest.java b/group04/498654356/mini-jvm/jvm/src/test/java/com/coderising/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..3f4a585db7 --- /dev/null +++ b/group04/498654356/mini-jvm/jvm/src/test/java/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 { + + + private static final String CAFEBABE = "cafebabe"; + static String path1 = "D:\\Dev\\git_repository\\coding2017\\group04\\498654356\\mini-jvm\\jvm\\target\\test-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 = "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/group04/498654356/mini-jvm/jvm/src/test/java/com/coderising/jvm/test/EmployeeV1.java b/group04/498654356/mini-jvm/jvm/src/test/java/com/coderising/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..9a36573dd3 --- /dev/null +++ b/group04/498654356/mini-jvm/jvm/src/test/java/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 From 403c94e530938d741b5762e7822595d02647efb0 Mon Sep 17 00:00:00 2001 From: Administrator <Administrator@win-10> Date: Tue, 4 Apr 2017 11:20:41 +0800 Subject: [PATCH 116/287] add LRU --- .../src/org/coding/four/lru/LRUPageFrame.java | 134 ++++++++++++++++++ .../org/coding/four/lru/LRUPageFrameTest.java | 31 ++++ 2 files changed, 165 insertions(+) create mode 100644 group04/498654356/one/src/org/coding/four/lru/LRUPageFrame.java create mode 100644 group04/498654356/one/test/org/coding/four/lru/LRUPageFrameTest.java diff --git a/group04/498654356/one/src/org/coding/four/lru/LRUPageFrame.java b/group04/498654356/one/src/org/coding/four/lru/LRUPageFrame.java new file mode 100644 index 0000000000..1113e39e7a --- /dev/null +++ b/group04/498654356/one/src/org/coding/four/lru/LRUPageFrame.java @@ -0,0 +1,134 @@ +package org.coding.four.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) { + if(first == null) { + first = new Node(); + first.pageNum = pageNum; + last = first; + } else { + if(isFull()) { + Node node = findNode(pageNum); + if(node == null) { // not found + removeLastNode(); + push(pageNum); + } else { + if(node == first) { + return ; + } + if(node == last) { + removeLastNode(); + node.next = first; + first.prev = node; + first = node; + return; + } + node.prev.next = node.next; + node.next.prev = node.prev; + node.prev = null; + node.next = first; + first = node; + } + } else { + push(pageNum); + } + } + + } + + private boolean isFull() { + return getSize() == capacity; + } + + private void removeLastNode() { + last = last.prev; + last.next = null; + } + + private void push(int pageNum) { + Node node = new Node(); + node.pageNum = pageNum; + node.next = first; + first.prev = node; + first = node; + } + + + + private Node findNode(int pageNum) { + if(first.pageNum == pageNum) { + return first; + } + Node node = first; + while(node.next != null) { + node = node.next; + if(node.pageNum == pageNum) { + return node; + } + } + return null; + } + + private int getSize() { + if(first == null) { + return 0; + } + Node node = first; + int size = 1; + while(node.next != null) { + size++; + node = node.next; + } + return 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/group04/498654356/one/test/org/coding/four/lru/LRUPageFrameTest.java b/group04/498654356/one/test/org/coding/four/lru/LRUPageFrameTest.java new file mode 100644 index 0000000000..0d08db77e9 --- /dev/null +++ b/group04/498654356/one/test/org/coding/four/lru/LRUPageFrameTest.java @@ -0,0 +1,31 @@ +package org.coding.four.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()); + } + +} From 61c419248bc228e27df49af56a3de22427e3c1e7 Mon Sep 17 00:00:00 2001 From: '1299310140' <'13437282785@163.com'> Date: Tue, 4 Apr 2017 22:04:04 +0800 Subject: [PATCH 117/287] jvm --- .../jvm/loader/ClassFileLoader.java | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 group04/1299310140/src/com/coderising/jvm/loader/ClassFileLoader.java diff --git a/group04/1299310140/src/com/coderising/jvm/loader/ClassFileLoader.java b/group04/1299310140/src/com/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..3b0b086ee4 --- /dev/null +++ b/group04/1299310140/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,56 @@ +package com.coderising.jvm.loader; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.util.ArrayList; +import java.util.List; + +public class ClassFileLoader { + + private List<String> clzPaths = new ArrayList<String>(); + + public byte[] readBinaryCode(String className) throws Exception{ + //com.coderising.jvm.test.EmployeeV1 + //"com\\coderising\\jvm\\test\\EmployeeV1" + String clzFileName = this.getClassPath() + "\\" + className.replace(".", "\\") + ".class"; + //FileInputStream BufferedInputStream ByteArrayOutputStream + File file = new File(clzFileName); + + BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + byte[] buffer = new byte[1024]; + + int length = -1; + + while((length = bis.read(buffer)) != -1){ + bos.write(buffer,0,length); + } + + byte[] result = bos.toByteArray(); + bis.close(); + bos.close(); + + return result; + } + + public void addClassPath(String path) { + clzPaths.add(path); + } + + public String getClassPath(){ + String result = ""; + for(int i = 0;i < clzPaths.size();i++){ + result = result + clzPaths.get(i); + if(i == clzPaths.size() - 1){ + break; + } + result = result + ";"; + } + return result; + } + +} From c9b213b8b4c88adfe4667551d51d8416571ccd9b Mon Sep 17 00:00:00 2001 From: liuxianan// <1264835468@qq.com> Date: Tue, 4 Apr 2017 22:16:09 +0800 Subject: [PATCH 118/287] lru classloader --- .../src/assignment0226/ArrayUtil.java | 1 - .../jvm/loader/ClassFileLoader.java | 59 ++++++++++++ .../jvm/test/ClassFileLoaderTest.java | 95 +++++++++++++++++++ .../{lru => jvm/test}/EmployeeV1.java | 7 +- .../src/assignment0326/lru/Clock.java | 73 +++++++++++--- .../src/assignment0326/lru/LRUPageFrame.java | 4 +- 6 files changed, 219 insertions(+), 20 deletions(-) create mode 100644 group17/1264835468/src/assignment0326/jvm/loader/ClassFileLoader.java create mode 100644 group17/1264835468/src/assignment0326/jvm/test/ClassFileLoaderTest.java rename group17/1264835468/src/assignment0326/{lru => jvm/test}/EmployeeV1.java (86%) diff --git a/group17/1264835468/src/assignment0226/ArrayUtil.java b/group17/1264835468/src/assignment0226/ArrayUtil.java index 8b279dca28..f8be858ad9 100644 --- a/group17/1264835468/src/assignment0226/ArrayUtil.java +++ b/group17/1264835468/src/assignment0226/ArrayUtil.java @@ -180,5 +180,4 @@ public static String join(int[] array, String seperator) { return stringBuilder.toString(); } - } diff --git a/group17/1264835468/src/assignment0326/jvm/loader/ClassFileLoader.java b/group17/1264835468/src/assignment0326/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..a5add91113 --- /dev/null +++ b/group17/1264835468/src/assignment0326/jvm/loader/ClassFileLoader.java @@ -0,0 +1,59 @@ +package assignment0326.jvm.loader; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Administrator on 2017/3/30. + */ +public class ClassFileLoader { + + + private List<String> clzPaths = new ArrayList<String>(); + + public byte[] readBinaryCode(String className) { + String path = className.replace(".", File.separator); + File classFile=null; + for (String p: clzPaths) { + classFile=new File(p+File.separator+path+".class"); + if(classFile.exists()) + break; + } + if(classFile==null) + throw new RuntimeException("no such class file"); + + byte[] bytes=new byte[(int)classFile.length()]; + try (BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(classFile))){ + bufferedInputStream.read(bytes, 0, bytes.length); + + } catch (IOException e) { + e.printStackTrace(); + } + return bytes; + } + + + public void addClassPath(String path) { + clzPaths.add(path); + } + + + + public String getClassPath(){ + StringBuilder stringBuilder=new StringBuilder(); + for (int i = 0; i <clzPaths.size()-1; i++) { + stringBuilder.append(clzPaths.get(i) + ";"); + } + stringBuilder.append(clzPaths.get(clzPaths.size()-1)); + return stringBuilder.toString(); + } + + + + + +} diff --git a/group17/1264835468/src/assignment0326/jvm/test/ClassFileLoaderTest.java b/group17/1264835468/src/assignment0326/jvm/test/ClassFileLoaderTest.java new file mode 100644 index 0000000000..5ebb4075a6 --- /dev/null +++ b/group17/1264835468/src/assignment0326/jvm/test/ClassFileLoaderTest.java @@ -0,0 +1,95 @@ +package assignment0326.jvm.test; + +/** + * Created by Administrator on 2017/3/30. + */ + +import assignment0326.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 = "D:\\GitHub\\group17\\1264835468\\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 = "assignment0326.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 = "assignment0326.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/group17/1264835468/src/assignment0326/lru/EmployeeV1.java b/group17/1264835468/src/assignment0326/jvm/test/EmployeeV1.java similarity index 86% rename from group17/1264835468/src/assignment0326/lru/EmployeeV1.java rename to group17/1264835468/src/assignment0326/jvm/test/EmployeeV1.java index bad73de115..72b3febb92 100644 --- a/group17/1264835468/src/assignment0326/lru/EmployeeV1.java +++ b/group17/1264835468/src/assignment0326/jvm/test/EmployeeV1.java @@ -1,8 +1,5 @@ -package assignment0326.lru; +package assignment0326.jvm.test; -/** - * Created by Administrator on 2017/3/29. - */ public class EmployeeV1 { @@ -28,4 +25,4 @@ public static void main(String[] args){ p.sayHello(); } -} +} \ No newline at end of file diff --git a/group17/1264835468/src/assignment0326/lru/Clock.java b/group17/1264835468/src/assignment0326/lru/Clock.java index 23198886fe..1e515af5d2 100644 --- a/group17/1264835468/src/assignment0326/lru/Clock.java +++ b/group17/1264835468/src/assignment0326/lru/Clock.java @@ -1,5 +1,8 @@ package assignment0326.lru; +import java.util.*; +import java.util.stream.Collectors; + /** * Created by Administrator on 2017/3/29. */ @@ -7,44 +10,90 @@ public class Clock { private PageFrame[] pages; private int capacity; private int accessPtr; + private int size; public Clock(int capacity) { this.capacity = capacity; pages = new PageFrame[capacity]; - accessPtr=0; + accessPtr = 0; + size=0; } - private void access(int pageNum){ - if (pages[accessPtr] == null) { - pages[accessPtr] = new PageFrame(pageNum); - }else{ - int indexToReplace=findLRUIndex(); - pages[indexToReplace].pageNum=pageNum; + private void access(int pageNum) { + int index = search(pageNum); + if(index==-1){ + if(size<capacity){ + add(new PageFrame(pageNum)); + }else{ + pages[findLRUIndex()].pageNum=pageNum; + } + }else { + pages[findLRUIndex()].accessFlag=true; } accessPtr = (accessPtr + 1) % capacity; } + private int search(int pageNum) { + for (int i = 0; i <size; i++) { + if(pages[i].pageNum==pageNum) + return i; + } + return -1; + } + + private void add(PageFrame pageFrame) { + pages[size++]=pageFrame; + } + private int findLRUIndex() { - while(pages[accessPtr].shouldGiveAnotherChance()){ + while (pages[accessPtr].shouldGiveAnotherChance()) { accessPtr = (accessPtr + 1) % capacity; } return accessPtr; } - private static class PageFrame{ + private static class PageFrame { int pageNum; boolean accessFlag; public PageFrame(int pageNum) { this.pageNum = pageNum; - accessFlag=true; + accessFlag = true; } public boolean shouldGiveAnotherChance() { - if(accessFlag){ - accessFlag=false; + if (accessFlag) { + accessFlag = false; return true; } return false; } } + + public static void main(String[] args) { + + List<String> strings=new ArrayList<>(); + for (int i = 0; i <10; i++) { + strings.add(String.valueOf(new Random().nextInt(3000))); + } + System.out.println(strings); + System.out.println(strings.stream().map(s-> s.charAt(0)).sorted().distinct().limit(5).collect(Collectors.toList())); + } + + public int findMinDifference(List<String> timePoints) { + List<Integer> list=new ArrayList<>(); + + for (String s:timePoints) { + list.add(parse(s)); + } + Collections.sort(list); + int min=Integer.MAX_VALUE; + for (int i = 0; i < list.size()-1; i++) { + min=Math.min(min,Math.min(Math.abs(list.get(i+1)-list.get(i)),24*60-Math.abs(list.get(i+1)-list.get(i)))); + } + return min; + } + + private Integer parse(String s) { + return Integer.parseInt(s.substring(0, 2)) * 60 + Integer.parseInt(s.substring(3, 5)); + } } diff --git a/group17/1264835468/src/assignment0326/lru/LRUPageFrame.java b/group17/1264835468/src/assignment0326/lru/LRUPageFrame.java index 542075129f..fd2f2693c4 100644 --- a/group17/1264835468/src/assignment0326/lru/LRUPageFrame.java +++ b/group17/1264835468/src/assignment0326/lru/LRUPageFrame.java @@ -8,7 +8,6 @@ public class LRUPageFrame { private static class Node { - Node prev; Node next; int pageNum; @@ -29,7 +28,7 @@ public Node(int pageNum) { private int size; public LRUPageFrame(int capacity) { if(capacity<=0) - throw new IllegalArgumentException("capacity:"+capacity+" < 0"); + throw new IllegalArgumentException("capacity:"+capacity+" <= 0"); this.capacity = capacity; first=null; last=null; @@ -82,6 +81,7 @@ private void moveToFirst(Node target) { if(target==first){ return; } + Node prevOfTarget=target.prev; prevOfTarget.next=target.next; From 282b6265e85e05266ced2946853831fd9dc8742e Mon Sep 17 00:00:00 2001 From: Ren650119726 <102228177@qq.com> Date: Tue, 4 Apr 2017 22:36:05 +0800 Subject: [PATCH 119/287] =?UTF-8?q?=E6=96=87=E7=AB=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group17/article/template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/group17/article/template.md b/group17/article/template.md index 09c7951d71..f8f2e4414a 100644 --- a/group17/article/template.md +++ b/group17/article/template.md @@ -12,7 +12,7 @@ 1204187480 http://blog.leanote.com/post/luoziyihao/js%E9%97%AD%E5%8C%85 -102228177 +102228177 http://note.youdao.com/noteshare?id=1f8f4a9d861e24948cdf0219a0d39f4e 876385982 From a4afcfe0fcaf7bd3bdfaa855ae465d33bd55c88c Mon Sep 17 00:00:00 2001 From: HaoSong <hao_song@anfcorp.com> Date: Wed, 5 Apr 2017 11:44:26 +0800 Subject: [PATCH 120/287] 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?7Jr<AY& literal 234626 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%0A{3_1 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 From 437e2cada5b54728063cfd79dfc569810af514f3 Mon Sep 17 00:00:00 2001 From: "wangxg922@chinaunincom.cn" <996108220@qq.com> Date: Wed, 5 Apr 2017 16:21:39 +0800 Subject: [PATCH 121/287] =?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<String> clzPaths = new ArrayList<String>(); + + 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<Byte> list=new ArrayList<Byte>(); + 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<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/group11/996108220/src/com/coderising/jvm/test/EmployeeV1.java b/group11/996108220/src/com/coderising/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..9a36573dd3 --- /dev/null +++ b/group11/996108220/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/group11/996108220/src/com/coding/basic/linklist/LRUPageFrame.java b/group11/996108220/src/com/coding/basic/linklist/LRUPageFrame.java new file mode 100644 index 0000000000..f9ee1e68fa --- /dev/null +++ b/group11/996108220/src/com/coding/basic/linklist/LRUPageFrame.java @@ -0,0 +1,139 @@ +package com.coding.basic.linklist; + + +/** + * 用双向链表实现LRU算法 + * @author 996108220 + * + */ +public class LRUPageFrame { + + private static class Node { + + Node prev; + Node next; + int pageNum; + + Node() { + } + + public Node(int pageNum2) { + this.pageNum=pageNum2; + this.next=null; + this.prev=null; + } + + } + + private int capacity; + private int size; + private Node first;// 链表头 + private Node last;// 链表尾 + + + public LRUPageFrame(int capacity) { + + this.capacity = capacity; + this.size=0; + + } + + /** + * 获取缓存中对象 + * + * @param key + * @return + */ + public void access(int pageNum) { + Node node=remove(pageNum); + if (node==null) { + node=new Node(pageNum); + push(node); + } + else { + addTail(node); + } + + + } + + + private void push(Node node) { + if (this.size()==capacity) { + removeFirst(); + } + addTail(node); + } + + private void addTail(Node node) { + if (size==0) { + first=node; + last=node; + } + else { + node.prev=last; + last.next=node; + last=node; + + } + size++; + + } + + private void removeFirst() { + + Node node=this.first; + first=first.next; + node.next=null; + first.prev=null; + size--; + } + + private int size() { + + return size; + } + + private Node remove(int pageNum) { + Node node=first; + while(node!=null){ + if (node.pageNum==pageNum) { + if (node==first) { + first=node.next; + node.next=null; + first.prev=null; + } + else if (node==last) { + last=node.prev; + last.next=null; + node.prev=null; + } + else { + node.prev.next=node.next; + node.next.prev=node.prev; + node.next=null; + node.prev=null; + } + size--; + break; + } + node=node.next; + } + return node; + } + + public String toString(){ + 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/group11/996108220/src/com/coding/basic/linklist/LRUPageFrameTest.java b/group11/996108220/src/com/coding/basic/linklist/LRUPageFrameTest.java new file mode 100644 index 0000000000..67cf36067b --- /dev/null +++ b/group11/996108220/src/com/coding/basic/linklist/LRUPageFrameTest.java @@ -0,0 +1,31 @@ +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()); + } + +} From a6781e39fc5c848483edf5ece7513885a76a76e7 Mon Sep 17 00:00:00 2001 From: luoziyihao <wangyiraoxiang@163.com> Date: Wed, 5 Apr 2017 21:19:06 +0800 Subject: [PATCH 122/287] com --- group17/count/reward.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 group17/count/reward.md diff --git a/group17/count/reward.md b/group17/count/reward.md new file mode 100644 index 0000000000..4a0fe7ea81 --- /dev/null +++ b/group17/count/reward.md @@ -0,0 +1,16 @@ +## 17组 201703 获奖 + +### 代码坚持奖 + +82427129 +1282579502 +102228177 +1264835468 + +### 博客坚持奖 + +82427129 +1282579502 +102228177 +1264835468 + From 0d7544454649d723203c221d312e58b49e1f96d8 Mon Sep 17 00:00:00 2001 From: luoziyihao <wangyiraoxiang@163.com> Date: Wed, 5 Apr 2017 21:35:39 +0800 Subject: [PATCH 123/287] add 20170326-20170402.md --- group17/article/20170326-20170402.md | 56 ++++++++++++++++++++++++++++ group17/article/template.md | 6 +-- 2 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 group17/article/20170326-20170402.md diff --git a/group17/article/20170326-20170402.md b/group17/article/20170326-20170402.md new file mode 100644 index 0000000000..3d45ad0516 --- /dev/null +++ b/group17/article/20170326-20170402.md @@ -0,0 +1,56 @@ +# 自由写作 + +## 须知 +--- + +交作业时请在QQ 号后面填上各自的文章链接, 比如: + +51075907 http://m.blog.csdn.net/article/details?id=57083764 + +## 文章 +--- + +1204187480 + +102228177 + +876385982 + +785396327 + +1059107701 + +240094626 + +82427129 + +296910598 + +1264835468 + +516886559 + +1282579502 + +614982500 + +865797761 + +1540186032 + +176653813 + +116665530 + +51075907 + +1158154002 + +345450234 + +919764878 + +1368331120 + +517970312 + diff --git a/group17/article/template.md b/group17/article/template.md index 09c7951d71..3d45ad0516 100644 --- a/group17/article/template.md +++ b/group17/article/template.md @@ -10,7 +10,7 @@ ## 文章 --- -1204187480 http://blog.leanote.com/post/luoziyihao/js%E9%97%AD%E5%8C%85 +1204187480 102228177 @@ -26,11 +26,11 @@ 296910598 -1264835468 http://www.jianshu.com/p/634ca8cdd6e3 +1264835468 516886559 -1282579502 https://www.evernote.com/shard/s413/sh/142601dd-edc3-4e37-871e-37a7489d7634/a092bf080e1aefbaeab96d34edac8cf0 +1282579502 614982500 From bbfef7b85a3d0c352bfdc04eaf38a2006e5b192d Mon Sep 17 00:00:00 2001 From: luoziyihao <wangyiraoxiang@163.com> Date: Wed, 5 Apr 2017 21:37:26 +0800 Subject: [PATCH 124/287] add 20170326-20170402.md --- group17/count/homework.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/group17/count/homework.md b/group17/count/homework.md index e474336779..a0abf5cadd 100644 --- a/group17/count/homework.md +++ b/group17/count/homework.md @@ -17,3 +17,5 @@ * [20170305-20170312](https://github.com/luoziyihao/coding2017/blob/master/group17/article/20170305-20170312.md) + * [20170305-20170312](https://github.com/luoziyihao/coding2017/blob/master/group17/article/20170326-20170402.md) + From 500a40868b713940f9e1b8886d90ec262f6da811 Mon Sep 17 00:00:00 2001 From: liuxianan// <1264835468@qq.com> Date: Wed, 5 Apr 2017 22:04:57 +0800 Subject: [PATCH 125/287] Merge branch 'master' of https://github.com/luoziyihao/coding2017.git # Conflicts: # group17/240094626/.gitignore --- group17/LearnProject/src/CodeAssistance.java | 27 ++++++++++++++ group17/LearnProject/src/Navigation.java | 37 ++++++++++++++++++++ group17/LearnProject/src/Refactorings.java | 30 ++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 group17/LearnProject/src/CodeAssistance.java create mode 100644 group17/LearnProject/src/Navigation.java create mode 100644 group17/LearnProject/src/Refactorings.java diff --git a/group17/LearnProject/src/CodeAssistance.java b/group17/LearnProject/src/CodeAssistance.java new file mode 100644 index 0000000000..adf5369ed5 --- /dev/null +++ b/group17/LearnProject/src/CodeAssistance.java @@ -0,0 +1,27 @@ +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; + +class CodeAssistance { + + public static final String EXT = "txt"; + + public static void main(String[] args) throws IOException { + FileReader fileReader = new FileReader("input." + EXT); + try { + BufferedReader reader = new BufferedReader(fileReader); + ArrayList<String> lines = new ArrayList<String>(); + String line; + while ((line = reader.readLine()) != null) { + lines.add(line); + } + String[] array = lines.toArray(new String[lines.size()]); + Arrays.sort(array); + for (String s : array) System.out.println(s); + } finally { + fileReader.close(); + } + } +} \ No newline at end of file diff --git a/group17/LearnProject/src/Navigation.java b/group17/LearnProject/src/Navigation.java new file mode 100644 index 0000000000..f767faf5bd --- /dev/null +++ b/group17/LearnProject/src/Navigation.java @@ -0,0 +1,37 @@ +class FileStructureDemo{ + + + final private String DATABASE = "MyDataBase"; + DataEntry myPerson; + + FileStructureDemo(String name, int age, String cellphone){ + myPerson = new Person(name, age, cellphone); + } + + interface DataEntry{ + String getCellphone(); + String getName(); + } + + class Person implements DataEntry { + + public Person(String name, int age, String cellphone) { + this.name = name; + this.age = age; + this.cellphone = cellphone; + } + + private String name; + private int age; + private String cellphone; + + public String getCellphone() { + return cellphone; + } + + public String getName() { + return name; + } + + } +} \ No newline at end of file diff --git a/group17/LearnProject/src/Refactorings.java b/group17/LearnProject/src/Refactorings.java new file mode 100644 index 0000000000..3422b59877 --- /dev/null +++ b/group17/LearnProject/src/Refactorings.java @@ -0,0 +1,30 @@ +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; + +class Refactorings { + public static final String TXT = "txt"; + + public static void main(String[] args) throws IOException { + FileReader in = new FileReader("input." + TXT); + String[] array = getStrings( + in); + Arrays.sort(array); + for (String s : array) { + System.out.println(s); + } + } + + private static String[] getStrings(FileReader in) throws IOException { + BufferedReader reader = new BufferedReader(in); + ArrayList<String> lines = new ArrayList<String>(); + String line; + while ((line = reader.readLine()) != null) { + lines.add(line); + } + reader.close(); + return lines.toArray(new String[lines.size()]); + } +} \ No newline at end of file From 7e3076fb3f8bbde73da1decc9c2b9fdb074a9abb Mon Sep 17 00:00:00 2001 From: liuxianan// <1264835468@qq.com> Date: Wed, 5 Apr 2017 22:05:28 +0800 Subject: [PATCH 126/287] 12 --- group17/LearnProject/src/CodeAssistance.java | 27 -------------- group17/LearnProject/src/Navigation.java | 37 -------------------- group17/LearnProject/src/Refactorings.java | 30 ---------------- 3 files changed, 94 deletions(-) delete mode 100644 group17/LearnProject/src/CodeAssistance.java delete mode 100644 group17/LearnProject/src/Navigation.java delete mode 100644 group17/LearnProject/src/Refactorings.java diff --git a/group17/LearnProject/src/CodeAssistance.java b/group17/LearnProject/src/CodeAssistance.java deleted file mode 100644 index adf5369ed5..0000000000 --- a/group17/LearnProject/src/CodeAssistance.java +++ /dev/null @@ -1,27 +0,0 @@ -import java.io.BufferedReader; -import java.io.FileReader; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; - -class CodeAssistance { - - public static final String EXT = "txt"; - - public static void main(String[] args) throws IOException { - FileReader fileReader = new FileReader("input." + EXT); - try { - BufferedReader reader = new BufferedReader(fileReader); - ArrayList<String> lines = new ArrayList<String>(); - String line; - while ((line = reader.readLine()) != null) { - lines.add(line); - } - String[] array = lines.toArray(new String[lines.size()]); - Arrays.sort(array); - for (String s : array) System.out.println(s); - } finally { - fileReader.close(); - } - } -} \ No newline at end of file diff --git a/group17/LearnProject/src/Navigation.java b/group17/LearnProject/src/Navigation.java deleted file mode 100644 index f767faf5bd..0000000000 --- a/group17/LearnProject/src/Navigation.java +++ /dev/null @@ -1,37 +0,0 @@ -class FileStructureDemo{ - - - final private String DATABASE = "MyDataBase"; - DataEntry myPerson; - - FileStructureDemo(String name, int age, String cellphone){ - myPerson = new Person(name, age, cellphone); - } - - interface DataEntry{ - String getCellphone(); - String getName(); - } - - class Person implements DataEntry { - - public Person(String name, int age, String cellphone) { - this.name = name; - this.age = age; - this.cellphone = cellphone; - } - - private String name; - private int age; - private String cellphone; - - public String getCellphone() { - return cellphone; - } - - public String getName() { - return name; - } - - } -} \ No newline at end of file diff --git a/group17/LearnProject/src/Refactorings.java b/group17/LearnProject/src/Refactorings.java deleted file mode 100644 index 3422b59877..0000000000 --- a/group17/LearnProject/src/Refactorings.java +++ /dev/null @@ -1,30 +0,0 @@ -import java.io.BufferedReader; -import java.io.FileReader; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; - -class Refactorings { - public static final String TXT = "txt"; - - public static void main(String[] args) throws IOException { - FileReader in = new FileReader("input." + TXT); - String[] array = getStrings( - in); - Arrays.sort(array); - for (String s : array) { - System.out.println(s); - } - } - - private static String[] getStrings(FileReader in) throws IOException { - BufferedReader reader = new BufferedReader(in); - ArrayList<String> lines = new ArrayList<String>(); - String line; - while ((line = reader.readLine()) != null) { - lines.add(line); - } - reader.close(); - return lines.toArray(new String[lines.size()]); - } -} \ No newline at end of file From e5f94d81113a1ba092858e1f64f148f8763c076c Mon Sep 17 00:00:00 2001 From: liuxianan// <1264835468@qq.com> Date: Wed, 5 Apr 2017 22:08:52 +0800 Subject: [PATCH 127/287] article --- group17/article/20170326-20170402.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/group17/article/20170326-20170402.md b/group17/article/20170326-20170402.md index 3d45ad0516..7882e2b171 100644 --- a/group17/article/20170326-20170402.md +++ b/group17/article/20170326-20170402.md @@ -26,7 +26,7 @@ 296910598 -1264835468 +1264835468 http://www.jianshu.com/p/848fd6be5247 516886559 From 362e7371e6559cbf8f6a2dd79161287414eb0ce5 Mon Sep 17 00:00:00 2001 From: liuxianan// <1264835468@qq.com> Date: Wed, 5 Apr 2017 22:11:09 +0800 Subject: [PATCH 128/287] article. --- group17/1264835468/src/assignment0326/lru/Clock.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/group17/1264835468/src/assignment0326/lru/Clock.java b/group17/1264835468/src/assignment0326/lru/Clock.java index 1e515af5d2..274b6ebc80 100644 --- a/group17/1264835468/src/assignment0326/lru/Clock.java +++ b/group17/1264835468/src/assignment0326/lru/Clock.java @@ -4,7 +4,7 @@ import java.util.stream.Collectors; /** - * Created by Administrator on 2017/3/29. + * Created by Administrator on 2017/3/29. */ public class Clock { private PageFrame[] pages; From 00c94d2632c23284578e41e06fa8566bd9a47662 Mon Sep 17 00:00:00 2001 From: wubingyang <120549547@qq.com> Date: Wed, 5 Apr 2017 23:01:11 +0800 Subject: [PATCH 129/287] =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=BA=8C=E5=91=A8?= =?UTF-8?q?=E4=BD=9C=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group04/120549547/base/buil.bat | 5 - .../base/src/com/coding/basic/ArrayList.java | 93 ----- .../base/src/com/coding/basic/Iterator.java | 7 - .../base/src/com/coding/basic/LinkedList.java | 127 ------ .../base/src/com/coding/basic/List.java | 10 - .../base/src/com/coding/basic/Main.java | 85 ---- .../base/src/com/coding/basic/Queue.java | 29 -- .../base/src/com/coding/basic/Stack.java | 37 -- .../com/coding/basic/BinaryTreeNode.java | 0 .../main/java/com/coding/basic/Iterator.java | 8 + .../src/main/java/com/coding/basic/List.java | 31 ++ .../src/main/java/com/coding/basic/Stack.java | 24 ++ .../com/coding/basic/array/ArrayList.java | 155 ++++++++ .../com/coding/basic/array/ArrayUtil.java | 269 +++++++++++++ .../coding/basic/linklist/LRUPageFrame.java | 60 +++ .../basic/linklist/LRUPageFrameTest.java | 31 ++ .../com/coding/basic/linklist/LinkedList.java | 369 ++++++++++++++++++ .../com/coding/basic/queue/ArrayQueue.java | 97 +++++ .../java/com/coding/basic/queue/Queue.java | 16 + .../com/coding/download/DownloadThread.java | 21 + .../com/coding/download/FileDownloader.java | 73 ++++ .../coding/download/FileDownloaderTest.java | 59 +++ .../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 | 28 ++ .../download/impl/ConnectionManagerImpl.java | 16 + .../com/coding/litestruts/Configuration.java | 124 ++++++ .../com/coding/litestruts/LoginAction.java | 39 ++ .../com/coding/litestruts/ReflectionUtil.java | 85 ++++ .../java/com/coding/litestruts/Struts.java | 67 ++++ .../com/coding/litestruts/StrutsTest.java | 47 +++ .../main/java/com/coding/litestruts/View.java | 23 ++ .../com/coding/basic/array/ArrayListTest.java | 122 ++++++ .../com/coding/basic/array/ArrayUtilTest.java | 94 +++++ .../coding/basic/linklist/LinkedListTest.java | 155 ++++++++ .../coding/basic/queue/ArrayQueueTest.java | 68 ++++ .../coding/litestruts/ConfigurationTest.java | 45 +++ .../coding/litestruts/ReflectionUtilTest.java | 124 ++++++ group04/120549547/my.txt | 1 - 41 files changed, 2293 insertions(+), 394 deletions(-) delete mode 100644 group04/120549547/base/buil.bat delete mode 100644 group04/120549547/base/src/com/coding/basic/ArrayList.java delete mode 100644 group04/120549547/base/src/com/coding/basic/Iterator.java delete mode 100644 group04/120549547/base/src/com/coding/basic/LinkedList.java delete mode 100644 group04/120549547/base/src/com/coding/basic/List.java delete mode 100644 group04/120549547/base/src/com/coding/basic/Main.java delete mode 100644 group04/120549547/base/src/com/coding/basic/Queue.java delete mode 100644 group04/120549547/base/src/com/coding/basic/Stack.java rename group04/120549547/{base/src => code2017/src/main/java}/com/coding/basic/BinaryTreeNode.java (100%) create mode 100644 group04/120549547/code2017/src/main/java/com/coding/basic/Iterator.java create mode 100644 group04/120549547/code2017/src/main/java/com/coding/basic/List.java create mode 100644 group04/120549547/code2017/src/main/java/com/coding/basic/Stack.java create mode 100644 group04/120549547/code2017/src/main/java/com/coding/basic/array/ArrayList.java create mode 100644 group04/120549547/code2017/src/main/java/com/coding/basic/array/ArrayUtil.java create mode 100644 group04/120549547/code2017/src/main/java/com/coding/basic/linklist/LRUPageFrame.java create mode 100644 group04/120549547/code2017/src/main/java/com/coding/basic/linklist/LRUPageFrameTest.java create mode 100644 group04/120549547/code2017/src/main/java/com/coding/basic/linklist/LinkedList.java create mode 100644 group04/120549547/code2017/src/main/java/com/coding/basic/queue/ArrayQueue.java create mode 100644 group04/120549547/code2017/src/main/java/com/coding/basic/queue/Queue.java create mode 100644 group04/120549547/code2017/src/main/java/com/coding/download/DownloadThread.java create mode 100644 group04/120549547/code2017/src/main/java/com/coding/download/FileDownloader.java create mode 100644 group04/120549547/code2017/src/main/java/com/coding/download/FileDownloaderTest.java create mode 100644 group04/120549547/code2017/src/main/java/com/coding/download/api/Connection.java create mode 100644 group04/120549547/code2017/src/main/java/com/coding/download/api/ConnectionException.java create mode 100644 group04/120549547/code2017/src/main/java/com/coding/download/api/ConnectionManager.java create mode 100644 group04/120549547/code2017/src/main/java/com/coding/download/api/DownloadListener.java create mode 100644 group04/120549547/code2017/src/main/java/com/coding/download/impl/ConnectionImpl.java create mode 100644 group04/120549547/code2017/src/main/java/com/coding/download/impl/ConnectionManagerImpl.java create mode 100644 group04/120549547/code2017/src/main/java/com/coding/litestruts/Configuration.java create mode 100644 group04/120549547/code2017/src/main/java/com/coding/litestruts/LoginAction.java create mode 100644 group04/120549547/code2017/src/main/java/com/coding/litestruts/ReflectionUtil.java create mode 100644 group04/120549547/code2017/src/main/java/com/coding/litestruts/Struts.java create mode 100644 group04/120549547/code2017/src/main/java/com/coding/litestruts/StrutsTest.java create mode 100644 group04/120549547/code2017/src/main/java/com/coding/litestruts/View.java create mode 100644 group04/120549547/code2017/src/test/java/com/coding/basic/array/ArrayListTest.java create mode 100644 group04/120549547/code2017/src/test/java/com/coding/basic/array/ArrayUtilTest.java create mode 100644 group04/120549547/code2017/src/test/java/com/coding/basic/linklist/LinkedListTest.java create mode 100644 group04/120549547/code2017/src/test/java/com/coding/basic/queue/ArrayQueueTest.java create mode 100644 group04/120549547/code2017/src/test/java/com/coding/litestruts/ConfigurationTest.java create mode 100644 group04/120549547/code2017/src/test/java/com/coding/litestruts/ReflectionUtilTest.java delete mode 100644 group04/120549547/my.txt diff --git a/group04/120549547/base/buil.bat b/group04/120549547/base/buil.bat deleted file mode 100644 index 7164a42ac0..0000000000 --- a/group04/120549547/base/buil.bat +++ /dev/null @@ -1,5 +0,0 @@ -javac -sourcepath src -d classes -encoding utf-8 src\com\coding\basic\*.java - -java -cp classes com.coding.basic.Main - -pause \ No newline at end of file diff --git a/group04/120549547/base/src/com/coding/basic/ArrayList.java b/group04/120549547/base/src/com/coding/basic/ArrayList.java deleted file mode 100644 index 56e7aa4c26..0000000000 --- a/group04/120549547/base/src/com/coding/basic/ArrayList.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.coding.basic; -import java.util.Arrays; - -public class ArrayList implements List { - /*默认数组容量*/ - public static final int DEFAULT_CAPCATITY = 10; - - /*数组元素个数*/ - private int size; - - private Object[] elementData; - - public ArrayList(){ - this(DEFAULT_CAPCATITY); - } - - public ArrayList(int capacity){ - if (capacity<0 || capacity>Integer.MAX_VALUE) - throw new IllegalArgumentException("非法容量: " + capacity); - elementData = new Object[capacity]; - } - - - public void add(Object o){ - /*判断是否需要扩容*/ - ensureCapacity(size + 1); - elementData[size++] = o; - } - - public void add(int index, Object o){ - checkIndex(index); - /*判断是否需要扩容*/ - ensureCapacity(size + 1); - /*将index->size的元素依次向右移一个位置*/ - System.arraycopy(elementData, index, elementData, index+1, size-index); - /*插入o的值*/ - elementData[index] = o; - size++; - } - - - public Object get(int index){ - - checkIndex(index); - return elementData[index]; - } - - public Object remove(int index){ - - checkIndex(index); - Object value = elementData[index]; - /*将index+1 -> size的元素依次向左移一个位置*/ - System.arraycopy(elementData,index+1, elementData, index, size-index-1); - elementData[--size]=null; //释放最后一个元素,同时size减一; - return value; - } - - public int size(){ - return this.size; - } - - public Iterator iterator(){ - return null; - } - /* 确认容量是否足够,也可以直接调用手动扩容*/ - public void ensureCapacity(int minCapacity){ - int oldCapacity = elementData.length; - /*容量不足需要扩容*/ - if(oldCapacity < minCapacity){ - int newCapacity = oldCapacity * 2; //扩大2倍 - if (newCapacity < minCapacity){ - newCapacity = minCapacity; //扩容后仍不足,取最大值 - } - System.out.println("数据扩容至: " + newCapacity); - elementData = Arrays.copyOf(elementData, newCapacity); - } - - } - - private void checkIndex(int index){ - if (index<0 || index>= size) - throw new IndexOutOfBoundsException ("index非法: " + index); - } - @Override - public String toString(){ - - StringBuffer sb = new StringBuffer(""); - for(int i=0; i<size; i++){ - sb.append("["+ i +"]"+ elementData[i] + "-> "); - } - return sb.toString(); - } -} diff --git a/group04/120549547/base/src/com/coding/basic/Iterator.java b/group04/120549547/base/src/com/coding/basic/Iterator.java deleted file mode 100644 index 06ef6311b2..0000000000 --- a/group04/120549547/base/src/com/coding/basic/Iterator.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.coding.basic; - -public interface Iterator { - public boolean hasNext(); - public Object next(); - -} diff --git a/group04/120549547/base/src/com/coding/basic/LinkedList.java b/group04/120549547/base/src/com/coding/basic/LinkedList.java deleted file mode 100644 index edfbcc1007..0000000000 --- a/group04/120549547/base/src/com/coding/basic/LinkedList.java +++ /dev/null @@ -1,127 +0,0 @@ -package com.coding.basic; - -public class LinkedList implements List { - - private Node head; - private int size; - /*创建一个带头节点的单链表*/ - public LinkedList(){ - head = new Node(null); - } - - /*添加一个元素(尾插法)*/ - public void add(Object o){ - - Node node = new Node(o); - Node pos = head; - //找到最后一个元素位置 - while(pos.next != null){ - pos = pos.next; - } - pos.next = node; - size++; - - } - - /*在index位置插入*/ - public void add(int index , Object o){ - //判断索引是否合法 - checkIndex(index); - Node node = new Node(o); - Node pos = head; - //找到插入位置 - while(index-- != 0){ - pos = pos.next; - } - node.next = pos.next; - pos.next = node; - size++; - - } - public Object get(int index){ - checkIndex(index); - if(this.isEmpty()){ - throw new IllegalArgumentException ("链表为空"); - } - Node pos = head.next; //pos指向要获取的节点 - while(index-- !=0){ - pos = pos.next; - } - - return pos.data; - } - public Object remove(int index){ - checkIndex(index); - if(this.isEmpty()){ - throw new IllegalArgumentException ("链表为空"); - } - - Node pos = head; //pos指向要删除的前一个结点 - while(index-- != 0){ - pos = pos.next; - } - Node value = pos.next; //要删除的节点 - pos.next = value.next; - size--; - return value.data; - - - } - - public int size(){ - return size; - } - - public void addFirst(Object o){ - - } - public void addLast(Object o){ - this.add(o); - } - public Object removeFirst(){ - if(this.isEmpty()){ - throw new IllegalArgumentException ("链表为空"); - } - return remove(0); - } - public Object removeLast(){ - if(this.isEmpty()){ - throw new IllegalArgumentException ("链表为空"); - } - return remove(size-1); - } - - public boolean isEmpty(){ - return size == 0; - } - public Iterator iterator(){ - return null; - } - - private void checkIndex(int index){ - if (index<0 || index>=size ){ - throw new IllegalArgumentException ("index不合法: " + index ); - } - } - - @Override - public String toString(){ - - StringBuffer sb = new StringBuffer(""); - for(int i=0; i<size; i++){ - sb.append( this.get(i) + "-> "); - } - return sb.toString(); - } - - private static class Node{ - public Object data; - public Node next; - - public Node(Object data){ - this.data = data; - this.next = null; - } - - } -} diff --git a/group04/120549547/base/src/com/coding/basic/List.java b/group04/120549547/base/src/com/coding/basic/List.java deleted file mode 100644 index d47df585d9..0000000000 --- a/group04/120549547/base/src/com/coding/basic/List.java +++ /dev/null @@ -1,10 +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/group04/120549547/base/src/com/coding/basic/Main.java b/group04/120549547/base/src/com/coding/basic/Main.java deleted file mode 100644 index de8a0b0990..0000000000 --- a/group04/120549547/base/src/com/coding/basic/Main.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.coding.basic; -import com.coding.basic.*; - -class Main{ - - public static void main(String[] args){ - System.out.println("数组测试开始"); - ArrayListTest(); - System.out.println("----------------分割线----------------"); - System.out.println("链表测试开始"); - LinkedListTest(); - System.out.println("----------------分割线----------------"); - System.out.println("栈测试开始"); - StatckTest(); - System.out.println("----------------分割线----------------"); - System.out.println("队测试开始"); - QueueTest(); - } - - public static void ArrayListTest(){ - ArrayList list = new ArrayList(2); - list.add("HelloBobi0"); - list.add("HelloBobi1"); - list.add("HelloBobi2"); - list.add("HelloBobi3"); - list.add("HelloBobi4"); - list.add("HelloBobi5"); - System.out.println((String)list.get(0)); - System.out.println((String)list.get(4)); - list.add(3, "Hei Man"); - list.remove(5); - System.out.println(list); - System.out.println("size:=" + list.size()); - } - - public static void LinkedListTest(){ - LinkedList ll = new LinkedList(); - - - ll.add("SingleDog0"); - ll.add("SingleDog1"); - ll.add("SingleDog2"); - ll.add("SingleDog3"); - ll.add("SingleDog4"); - ll.add("SingleDog5"); - - System.out.println((String)(ll.get(1))); - System.out.println(ll); - System.out.println("size:=" + ll.size()); - ll.remove(0); - ll.removeFirst(); - ll.removeLast(); - System.out.println(ll); - } - - public static void StatckTest(){ - Stack stack = new Stack(); - stack.push("虾师傅0"); - stack.push("虾师傅1"); - stack.push("虾师傅2"); - stack.push("虾师傅3"); - stack.push("虾师傅4"); - - stack.pop(); - System.out.println(stack.peek()); - System.out.println(stack); - - } - public static void QueueTest(){ - Queue queue = new Queue(); - queue.enQueue("龙师傅0"); - queue.enQueue("龙师傅1"); - queue.enQueue("龙师傅2"); - queue.enQueue("龙师傅3"); - queue.enQueue("龙师傅4"); - - System.out.println(queue.deQueue()); - System.out.println(queue.deQueue()); - System.out.println(queue.deQueue()); - System.out.println(queue.deQueue()); - System.out.println(queue.size()); - - - } -} \ No newline at end of file diff --git a/group04/120549547/base/src/com/coding/basic/Queue.java b/group04/120549547/base/src/com/coding/basic/Queue.java deleted file mode 100644 index 8f86f7492c..0000000000 --- a/group04/120549547/base/src/com/coding/basic/Queue.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.coding.basic; -import com.coding.basic.*; -public class Queue { - private LinkedList list; - - public Queue(){ - list = new LinkedList(); - } - /*入队*/ - public void enQueue(Object o){ - list.addLast(o); - } - - /*出队*/ - public Object deQueue(){ - if (isEmpty()){ - System.out.println("队空"); - } - return list.removeFirst(); - } - - public boolean isEmpty(){ - return list.isEmpty(); - } - - public int size(){ - return list.size(); - } -} diff --git a/group04/120549547/base/src/com/coding/basic/Stack.java b/group04/120549547/base/src/com/coding/basic/Stack.java deleted file mode 100644 index f7d3bba3db..0000000000 --- a/group04/120549547/base/src/com/coding/basic/Stack.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.coding.basic; -import com.coding.basic.LinkedList; - -public class Stack { - private LinkedList list; - - public Stack(){ - list = new LinkedList(); - } - - public void push(Object o){ - list.addLast(o); - } - - public Object pop(){ - if(isEmpty()){ - System.out.println("栈空"); - } - return list.removeLast(); - - } - - public Object peek(){ - return list.get(list.size()-1); - } - public boolean isEmpty(){ - return list.isEmpty(); - } - public int size(){ - return list.size(); - } - - @Override - public String toString(){ - return list.toString(); - } -} diff --git a/group04/120549547/base/src/com/coding/basic/BinaryTreeNode.java b/group04/120549547/code2017/src/main/java/com/coding/basic/BinaryTreeNode.java similarity index 100% rename from group04/120549547/base/src/com/coding/basic/BinaryTreeNode.java rename to group04/120549547/code2017/src/main/java/com/coding/basic/BinaryTreeNode.java diff --git a/group04/120549547/code2017/src/main/java/com/coding/basic/Iterator.java b/group04/120549547/code2017/src/main/java/com/coding/basic/Iterator.java new file mode 100644 index 0000000000..31d6470bef --- /dev/null +++ b/group04/120549547/code2017/src/main/java/com/coding/basic/Iterator.java @@ -0,0 +1,8 @@ +package com.coding.basic; + +public interface Iterator<T> { + boolean hasNext(); + + T next(); + +} diff --git a/group04/120549547/code2017/src/main/java/com/coding/basic/List.java b/group04/120549547/code2017/src/main/java/com/coding/basic/List.java new file mode 100644 index 0000000000..70a783968e --- /dev/null +++ b/group04/120549547/code2017/src/main/java/com/coding/basic/List.java @@ -0,0 +1,31 @@ +package com.coding.basic; + +public interface List<T>{ + int size(); + + boolean isEmpty(); + + boolean contains(Object o); + + Object[] toArray(); + + boolean add(T o); + + boolean remove(T o); + + void clear(); + + T get(int index); + + T set(int index, T o); + + void add(int index, T o); + + T remove(int index); + + int indexOf(T o); + + Iterator<T> iterator(); + + void printf(); +} diff --git a/group04/120549547/code2017/src/main/java/com/coding/basic/Stack.java b/group04/120549547/code2017/src/main/java/com/coding/basic/Stack.java new file mode 100644 index 0000000000..459ec560b4 --- /dev/null +++ b/group04/120549547/code2017/src/main/java/com/coding/basic/Stack.java @@ -0,0 +1,24 @@ +package com.coding.basic; + +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/group04/120549547/code2017/src/main/java/com/coding/basic/array/ArrayList.java b/group04/120549547/code2017/src/main/java/com/coding/basic/array/ArrayList.java new file mode 100644 index 0000000000..6c392a3618 --- /dev/null +++ b/group04/120549547/code2017/src/main/java/com/coding/basic/array/ArrayList.java @@ -0,0 +1,155 @@ +package com.coding.basic.array; + +import com.coding.basic.Iterator; +import com.coding.basic.List; + +import java.util.Objects; + +public class ArrayList<T> implements List<T> { + + private int size; + private Object[] dataArray = new Object[0]; + + public int size() { + return this.size; + } + + public boolean isEmpty() { + return this.size == 0; + } + + public boolean contains(Object o) { + for (Object obj : dataArray) { + if (Objects.equals(obj, o)){ + return true; + } + } + return false; + } + + public Object[] toArray() { + Object[] array = new Object[size]; + System.arraycopy(dataArray, 0, array, 0, size); + return array; + } + + public boolean add(T o) { + ensureCapacity(size+1); + dataArray[size] = o; + size++; + return true; + } + + + + public boolean remove(T o) { + int index = indexOf(o); + if (index < 0){ + return false; + } + + System.arraycopy(dataArray, index + 1, dataArray, index, size - 1 - index); + dataArray[size - 1] = null; + size--; + return true; + } + + public void clear() { + for (int i = 0; i < size; i++) { + dataArray[i] = null; + } + size = 0; + } + @SuppressWarnings("unchecked") + public T get(int index) { + if (index < 0 || index >= size){ + throw new IndexOutOfBoundsException(); + } + + return (T) dataArray[index]; + } + + public T set(int index, T o) { + if (index < 0 || index >= size){ + throw new IndexOutOfBoundsException(); + } + dataArray[index] = o; + return o; + } + + public void add(int index, T o) { + if (index < 0 || index > size) { + throw new IndexOutOfBoundsException(); + } + ensureCapacity(size + 1); + System.arraycopy(dataArray, index, dataArray, index + 1, size - index); + + dataArray[index] = o; + + size++; + } + + public T remove(int index) { + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException(); + } + T removeData = (T) dataArray[index]; + System.arraycopy(dataArray, index + 1, dataArray, index, size - index -1 ); + dataArray[size - 1] = null; + size--; + return removeData; + } + + public int indexOf(T o) { + for (int i = 0; i < size; i++) { + if (Objects.equals(o, dataArray[i])){ + return i; + } + } + return -1; + } + + public Iterator<T> iterator() { + return new ArrayListIterator(); + } + + @Override + public void printf() { + for (int i = 0; i < size; i++) { + if (i == size - 1){ + System.out.print(dataArray[i]); + }else { + System.out.print(dataArray[i] + "->"); + } + } + } + + private void ensureCapacity(int minCapacity) { + if (minCapacity > dataArray.length){ + int newCapacity = Math.max(minCapacity, dataArray.length * 2); + Object[] newDataArray = new Object[newCapacity]; + System.arraycopy(dataArray, 0, newDataArray, 0, dataArray.length); + dataArray = newDataArray; + } + + } + + + private class ArrayListIterator implements Iterator<T> { + + private int pos; + + @Override + public boolean hasNext() { + return pos < size(); + } + + @Override + public T next() { + if (hasNext()){ + return get(pos++); + } + return null; + } + } +} diff --git a/group04/120549547/code2017/src/main/java/com/coding/basic/array/ArrayUtil.java b/group04/120549547/code2017/src/main/java/com/coding/basic/array/ArrayUtil.java new file mode 100644 index 0000000000..411b60990b --- /dev/null +++ b/group04/120549547/code2017/src/main/java/com/coding/basic/array/ArrayUtil.java @@ -0,0 +1,269 @@ +package com.coding.basic.array; + +import java.util.Arrays; + +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 || origin.length == 0){ + return; + } + + int temp ; + for (int i = 0; i < (origin.length / 2); i++) { + temp = origin[i]; + origin[i] = origin[(origin.length - 1) - i]; + origin[(origin.length - 1)- 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 static int[] removeZero(int[] oldArray){ + if (oldArray == null ){ + return null; + } + + if (oldArray.length == 0){ + return oldArray; + } + + int count = 0; + int[] temp = new int[oldArray.length]; + + for (int i = 0; i < oldArray.length; i++) { + if (oldArray[i] != 0){ + temp[count++] = oldArray[i]; + } + } + + int[] result = new int[count]; + + System.arraycopy(temp, 0, result, 0, count); + return result; + } + + /** + * 给定两个已经排序好的整形数组, 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; + } + + if (array1 == null){ + return array2; + } + + if (array2 == null){ + return array1; + } + + int length1 = array1.length; + int length2 = array2.length; + int[] temp = new int[length1 + length2]; + int i,j,k; + for ( i = 0, j = 0, k = 0; i < length1 && j < length2 ;) { + + if (array1[i] < array2[j]){ + temp[k++] = array1[i++]; + }else if (array1[i] > array2[j]){ + temp[k++] = array2[j++]; + }else { + temp[k++] = array1[i]; + i++; + j++; + } + } + + while (i < length1){ + temp[k++] = array1[i++]; + } + + while (j < length2){ + temp[k++] = array2[j++]; + } + int[] result = new int[k]; + System.arraycopy(temp, 0, result, 0, k); + return result; + + } + /** + * 把一个已经存满数据的数组 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){ + + int oldSize = oldArray.length; + int[] newArray = new int[oldSize + size]; + + System.arraycopy(oldArray, 0, newArray, 0, oldSize); + + 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[] fibonacci1(int max){ + if (max == 1){ + return new int[0]; + } + + int[] temp = new int[max]; + int count = 0; +// for (int i = 1; i < max; i++) { +// int num = fibonacci(i); +// if (num < max){ +// temp[count++] = num; +// }else { +// break; +// } +// } + temp[0] = 1; + temp[1] = 2; + for (int i = 2; i < max; i++) { + temp[i] = temp[i-1] + temp[i-2]; //直接在数组中实现斐波那契数列 + if (temp[i] >= max){ + break; + }else { + count++; + } + } + + + + return Arrays.copyOf(temp, count); + } + + private static int fibonacci(int n){ + if (n <= 0){ + throw new IllegalArgumentException(); + } + + if (n == 1 || n == 2) { + return 1; + } + + return fibonacci(n - 1) + fibonacci(n - 2); + + } + /** + * 返回小于给定最大值max的所有素数数组 + * 例如max = 23, 返回的数组为[2,3,5,7,11,13,17,19] + * @param max + * @return + */ + public static int[] getPrimes(int max){ + + if (max <= 2){ + return new int[0]; + } + + int[] temp = new int[max]; + + int count = 0; + for (int i = 2; i < max; i++) { + int j; + for ( j = 2; j * j < i; j++) { + if (i % j == 0){ + break; + } + } + + if (j * j >= i){ + temp[count++] = i; + } + } + + return Arrays.copyOf(temp, count); + } + + /** + * 所谓“完数”, 是指这个数恰好等于它的因子之和,例如6=1+2+3 + * 给定一个最大值max, 返回一个数组, 数组中是小于max 的所有完数 + * @param max + * @return + */ + public static int[] getPerfectNumbers(int max){ + if ( max <= 1){ + return new int[0]; + } + + ArrayList<Integer> array = new ArrayList<>(); + for (int i = 2; i < max; i++) { + int sum = 0; //存储因子和 + for (int j = 1; j < i; j++) { + if (i % j == 0){ + sum += j; + } + } + + if (sum == i){ + array.add(i); + } + } + int[] result = new int[array.size()]; + + for (int i = 0; i < array.size(); i++) { + result[i] = array.get(i); + } + return result; + + + } + + /** + * 用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 || array.length == 0){ + return null; + } + + StringBuilder sb = new StringBuilder(""); + for (int i = 0; i < array.length-1; i++) { + sb.append(array[i]).append(seperator); + } + + sb.append(array[array.length-1]); + + return sb.toString(); + } + + +} diff --git a/group04/120549547/code2017/src/main/java/com/coding/basic/linklist/LRUPageFrame.java b/group04/120549547/code2017/src/main/java/com/coding/basic/linklist/LRUPageFrame.java new file mode 100644 index 0000000000..a4f2c14606 --- /dev/null +++ b/group04/120549547/code2017/src/main/java/com/coding/basic/linklist/LRUPageFrame.java @@ -0,0 +1,60 @@ +package com.coding.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(); + } + +} diff --git a/group04/120549547/code2017/src/main/java/com/coding/basic/linklist/LRUPageFrameTest.java b/group04/120549547/code2017/src/main/java/com/coding/basic/linklist/LRUPageFrameTest.java new file mode 100644 index 0000000000..67cf36067b --- /dev/null +++ b/group04/120549547/code2017/src/main/java/com/coding/basic/linklist/LRUPageFrameTest.java @@ -0,0 +1,31 @@ +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/group04/120549547/code2017/src/main/java/com/coding/basic/linklist/LinkedList.java b/group04/120549547/code2017/src/main/java/com/coding/basic/linklist/LinkedList.java new file mode 100644 index 0000000000..eb128c4b24 --- /dev/null +++ b/group04/120549547/code2017/src/main/java/com/coding/basic/linklist/LinkedList.java @@ -0,0 +1,369 @@ +package com.coding.basic.linklist; + +import com.coding.basic.Iterator; +import com.coding.basic.List; + +import java.util.Objects; + +public class LinkedList<T> implements List<T> { + private int size; + + private Node<T> head; + + private Node<T> last; + + + + private static class Node<T> { + T data; + Node pre; + Node next; + + Node(T data) { + this.data = data; + } + + + } + + public LinkedList(){ + this.head = new Node<>(null); + } + + @Override + public int size() { + return this.size; + } + + @Override + public boolean isEmpty() { + return this.size == 0; + } + + @Override + public boolean contains(Object o) { + Node node = this.head; + while (node.next != null){ + if (Objects.equals(node.data, o)){ + + return true; + } + node = node.next; + } + return false; + } + + @Override + public Object[] toArray() { + Object[] dataArray = new Object[size]; + Node node = head.next; + for (int i = 0; i < size&& node != null; i++, node = node.next) { + dataArray[i] = node.data; + + } + return dataArray; + } + + @Override + public boolean add(T o) { + if (this.last == null){ + this.last = new Node<>(o); + this.last.pre = this.head; + this.head.next = this.last; + }else { + Node oldLast = this.last; + this.last = new Node<>(o); + this.last.pre = oldLast; + oldLast.next = this.last; + + } + this.size++; + return true; + } + @SuppressWarnings("unchecked") + @Override + public boolean remove(T o) { + + + Node<T> curNode = head.next; + Node<T> preNode; + while (curNode != null){ + preNode = curNode.pre; //指向前一个节点 + + if (Objects.equals(curNode.data, o)){ + removeNode(preNode, curNode); + return true; + } + curNode = curNode.next; + } + + return false; + } + + private void removeNode(Node<T> preNode, Node<T> node) { + + if (this.last == node){ //如果删除的是last节点的情况 + if (preNode == this.head){ //如果只有一个节点的情况 + this.last = null; + }else { + this.last = preNode; + } + }else { + node.next.pre = node.pre; + + } + preNode.next = node.next; + + + + + this.size--; + } + + @Override + @SuppressWarnings("unchecked") + public void clear() { + for (Node x = head; x != null;){ + Node<T> next = x.next; + x.data = null; + x.pre = null; + x.next = null; + x = next; + } + head = last = null; + size = 0; + + } + + @Override + @SuppressWarnings("unchecked") + public T get(int index) { + return (T) getNode(index).data; + } + + + + @Override + public T set(int index, T o) { + Node node = getNode(index); + node.data = o; + return o; + } + + @SuppressWarnings("unchecked") + @Override + public void add(int index, T o) { + ensureIndex(index); + Node<T> newNode = new Node<>(o); + Node curNode = getNode(index); + Node pre = curNode.pre; + + newNode.next = curNode; + newNode.pre = pre; + curNode.pre = newNode; + pre.next = newNode; + + size++; + + } + + @Override + public T remove(int index) { + Node node = getNode(index); + Node pre = node.pre; + if (node == last){ //如果是最后一个节点 + if (pre != head){ //如果是唯一节点 + last = null; + }else { + last = node.pre; + } + } + + pre.next = node.next; + if (node.next != null){ + node.next.pre = pre; + } + size--; + return (T) node.data; + } + + @Override + public int indexOf(T o) { + Node node = head; + int index = 0; + + while (node.next != null){ + node = node.next; + if (Objects.equals(node.data, o)){ + return index; + } + index ++; + } + return index; + } + + @Override + public Iterator<T> iterator() { + return new LinkedListIterator(); + } + + @Override + public void printf() { + Node node = head.next; + while (node != null){ + if (node.next != null) { + System.out.print(node.data + " -> "); + }else { + System.out.print(node.data); + } + node = node.next; + } + System.out.println(); + System.out.println("head = " + head); + System.out.println("last = " + last); + + } + + + private Node getNode(int index) { + ensureIndex(index); + Node node = this.head; + for (int i = 0; i <= index; i++) { + node = node.next; + } + return node; + } + + private void ensureIndex(int index) { + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException(); + } + } + + /** + * 把该链表逆置 + * 例如链表为 3->7->10 , 逆置后变为 10->7->3 + */ + public void reverse(){ + if (head.next == null && head.next.next == null){ //如果链表为空或者只有一个元素,不做变换 + return; + } + + last = head.next; + + Node pre = head.next; + Node cur = pre.next; + Node next; + pre.next = null; + while (cur != null){ + next = cur.next; + cur.next = pre; + pre = cur; + cur = next; + } + head.next = pre; + } + + /** + * 删除一个单链表的前半部分 + * 例如:list = 2->5->7->8 , 删除以后的值为 7->8 + * 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10 + + */ + public void removeFirstHalf(){ + if (isEmpty()){ + return; + } + int halfIndex = size / 2; + + if (halfIndex >= 0){ + head.next = getNode(halfIndex); + } + + size = size - halfIndex; + } + + /** + * 从第i个元素开始, 删除length 个元素 , 注意i从0开始 + * @param i + * @param length + */ + public void remove(int i, int length){ + ensureIndex(i); + ensureIndex(i + length - 1); + + for (int j = i; j < i + length; j++) { + remove(i); + } + } + /** + * 假定当前链表和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; + } + + private class LinkedListIterator implements Iterator<T> { + private Node node; + + LinkedListIterator(){ + node = head; + } + @Override + public boolean hasNext() { + return node.next != null; + } + + @Override + public T next() { + if (hasNext()){ + node = node.next; + return (T) node.data; + } + return null; + } + } +} diff --git a/group04/120549547/code2017/src/main/java/com/coding/basic/queue/ArrayQueue.java b/group04/120549547/code2017/src/main/java/com/coding/basic/queue/ArrayQueue.java new file mode 100644 index 0000000000..db2047f096 --- /dev/null +++ b/group04/120549547/code2017/src/main/java/com/coding/basic/queue/ArrayQueue.java @@ -0,0 +1,97 @@ +package com.coding.basic.queue; + +import java.util.NoSuchElementException; + +/** + * Created by bobi on 2017/4/1. + * at code2017 + */ +public class ArrayQueue<T> implements Queue<T> { + + private int size; + private Object[] dataArray; + private int front; + private int rear; + + public ArrayQueue(int Capacity) { + this.dataArray = new Object[Capacity]; + this.front = 0; + this.rear = 0; + this.size = 0; + } + + @Override + public boolean add(T t) { + if (offer(t)){ + return true; + }else { + throw new IllegalStateException(); + } + } + + @Override + public boolean offer(T t) { + if (size >= dataArray.length){ + return false; + } + + dataArray[rear++] = t; + + if (rear == dataArray.length){ + rear = 0; + } + + size++; + return true; + } + + @Override + public T remove() { + T value = poll(); + if (value != null){ + return value; + }else { + throw new NoSuchElementException(); + } + } + + @Override + public T poll() { + if (size == 0){ + return null; + } + + + T value = (T) dataArray[front++]; + if (front == dataArray.length){ + front = 0; + } + + size--; + return value; + + } + + @Override + public boolean isEmpty() { + return size == 0; + } + + + @Override + public T peek() { + if (size == 0){ + return null; + }else { + return (T) dataArray[front]; + } + } + + public void printf() { + for (int i = 0; i < size; i++) { + + System.out.print(dataArray[(front + i) % dataArray.length] + " "); + } + } + +} diff --git a/group04/120549547/code2017/src/main/java/com/coding/basic/queue/Queue.java b/group04/120549547/code2017/src/main/java/com/coding/basic/queue/Queue.java new file mode 100644 index 0000000000..64f86616f4 --- /dev/null +++ b/group04/120549547/code2017/src/main/java/com/coding/basic/queue/Queue.java @@ -0,0 +1,16 @@ +package com.coding.basic.queue; + +public interface Queue<T> { + + boolean add(T t); + + boolean offer(T t); + + T remove(); + + T poll(); + + boolean isEmpty(); + + T peek(); +} diff --git a/group04/120549547/code2017/src/main/java/com/coding/download/DownloadThread.java b/group04/120549547/code2017/src/main/java/com/coding/download/DownloadThread.java new file mode 100644 index 0000000000..9fc2c860d2 --- /dev/null +++ b/group04/120549547/code2017/src/main/java/com/coding/download/DownloadThread.java @@ -0,0 +1,21 @@ +package com.coding.download; + + +import com.coding.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/group04/120549547/code2017/src/main/java/com/coding/download/FileDownloader.java b/group04/120549547/code2017/src/main/java/com/coding/download/FileDownloader.java new file mode 100644 index 0000000000..ec975a9aae --- /dev/null +++ b/group04/120549547/code2017/src/main/java/com/coding/download/FileDownloader.java @@ -0,0 +1,73 @@ +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; + +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/group04/120549547/code2017/src/main/java/com/coding/download/FileDownloaderTest.java b/group04/120549547/code2017/src/main/java/com/coding/download/FileDownloaderTest.java new file mode 100644 index 0000000000..84fbc8afa2 --- /dev/null +++ b/group04/120549547/code2017/src/main/java/com/coding/download/FileDownloaderTest.java @@ -0,0 +1,59 @@ +package com.coding.download; + +import com.coding.download.api.ConnectionManager; +import com.coding.download.api.DownloadListener; +import com.coding.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/group04/120549547/code2017/src/main/java/com/coding/download/api/Connection.java b/group04/120549547/code2017/src/main/java/com/coding/download/api/Connection.java new file mode 100644 index 0000000000..65f3dae9c5 --- /dev/null +++ b/group04/120549547/code2017/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/group04/120549547/code2017/src/main/java/com/coding/download/api/ConnectionException.java b/group04/120549547/code2017/src/main/java/com/coding/download/api/ConnectionException.java new file mode 100644 index 0000000000..1db8b093ec --- /dev/null +++ b/group04/120549547/code2017/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/group04/120549547/code2017/src/main/java/com/coding/download/api/ConnectionManager.java b/group04/120549547/code2017/src/main/java/com/coding/download/api/ConnectionManager.java new file mode 100644 index 0000000000..1d1a83caf2 --- /dev/null +++ b/group04/120549547/code2017/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/group04/120549547/code2017/src/main/java/com/coding/download/api/DownloadListener.java b/group04/120549547/code2017/src/main/java/com/coding/download/api/DownloadListener.java new file mode 100644 index 0000000000..c41045b0e8 --- /dev/null +++ b/group04/120549547/code2017/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/group04/120549547/code2017/src/main/java/com/coding/download/impl/ConnectionImpl.java b/group04/120549547/code2017/src/main/java/com/coding/download/impl/ConnectionImpl.java new file mode 100644 index 0000000000..0ddbf36e1b --- /dev/null +++ b/group04/120549547/code2017/src/main/java/com/coding/download/impl/ConnectionImpl.java @@ -0,0 +1,28 @@ +package com.coding.download.impl; + +import com.coding.download.api.Connection; + +import java.io.IOException; + + +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/group04/120549547/code2017/src/main/java/com/coding/download/impl/ConnectionManagerImpl.java b/group04/120549547/code2017/src/main/java/com/coding/download/impl/ConnectionManagerImpl.java new file mode 100644 index 0000000000..0f1c658a60 --- /dev/null +++ b/group04/120549547/code2017/src/main/java/com/coding/download/impl/ConnectionManagerImpl.java @@ -0,0 +1,16 @@ +package com.coding.download.impl; + + +import com.coding.download.api.Connection; +import com.coding.download.api.ConnectionException; +import com.coding.download.api.ConnectionManager; + +public class ConnectionManagerImpl implements ConnectionManager { + + @Override + public Connection open(String url) throws ConnectionException { + + return null; + } + +} diff --git a/group04/120549547/code2017/src/main/java/com/coding/litestruts/Configuration.java b/group04/120549547/code2017/src/main/java/com/coding/litestruts/Configuration.java new file mode 100644 index 0000000000..26799a83a4 --- /dev/null +++ b/group04/120549547/code2017/src/main/java/com/coding/litestruts/Configuration.java @@ -0,0 +1,124 @@ +package com.coding.litestruts; + + +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.Element; +import org.dom4j.io.SAXReader; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * Created by bobi on 2017/4/1. + * at code2017 + */ +public class Configuration { + Map<String, ActionConfig> actions = new HashMap<>(); + + + + public Configuration(String path) throws IOException { + + URL pathName = Configuration.class.getClassLoader().getResource(path); + + assert pathName != null; +// InputStream is = this.getClass().getClassLoader().getResourceAsStream(path); 默认则是从ClassPath根下获取,path不能以’/'开头 +// InputStream is = this.getClass().getResourceAsStream("/" + path); // path 不以’/'开头时默认是从此类所在的包下取资源,以’/'开头则是从ClassPath根下获取 +// InputStream is = pathName.openStream(); + InputStream is = new FileInputStream(pathName.getPath()); + + parseXML(is); + + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void parseXML(InputStream is) { + + SAXReader reader = new SAXReader(); + + try { + + Document doc = reader.read(is); + Element root = doc.getRootElement(); + Iterator it = root.elementIterator("action"); + + while (it.hasNext()){ + + Element ActionElement = (Element) it.next(); + + String actionName = ActionElement.attributeValue("name"); + String className = ActionElement.attributeValue("class"); + + ActionConfig ac = new ActionConfig(actionName, className); + + Iterator it2 = ActionElement.elementIterator(); + + while (it2.hasNext()){ + + Element resultElement = (Element) it2.next(); + + String resultName = resultElement.attributeValue("name"); + String viewName = resultElement.getTextTrim(); + + ac.addViewResult(resultName, viewName); + } + + this.actions.put(actionName, ac); + } + } catch (DocumentException e) { + e.printStackTrace(); + } + } + + public String getClassName(String actionName) { + ActionConfig ac = actions.get(actionName); + if (ac == null) { + return null; + } + return ac.getClassName(); + } + + public String getResultView(String actionName, String resultName) { + ActionConfig ac = actions.get(actionName); + if (ac == null) { + return null; + } + return ac.getViewName(resultName); + + } + + + private static class ActionConfig{ + String name; + String clzName; + Map<String, String> viewResult = new HashMap<>(); + + public ActionConfig(String name, String clzName) { + this.name = name; + 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/group04/120549547/code2017/src/main/java/com/coding/litestruts/LoginAction.java b/group04/120549547/code2017/src/main/java/com/coding/litestruts/LoginAction.java new file mode 100644 index 0000000000..39354518df --- /dev/null +++ b/group04/120549547/code2017/src/main/java/com/coding/litestruts/LoginAction.java @@ -0,0 +1,39 @@ +package com.coding.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/group04/120549547/code2017/src/main/java/com/coding/litestruts/ReflectionUtil.java b/group04/120549547/code2017/src/main/java/com/coding/litestruts/ReflectionUtil.java new file mode 100644 index 0000000000..6b761355b1 --- /dev/null +++ b/group04/120549547/code2017/src/main/java/com/coding/litestruts/ReflectionUtil.java @@ -0,0 +1,85 @@ +package com.coding.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; + +/** + * Created by bobi on 2017/4/1. + * at code2017 + */ +public class ReflectionUtil { + + public static List<Method> getSetterMethods(Class clz) { + + return getMethods(clz, "set"); + } + + public static void setParameters(Object o, Map<String, String> params) { + + List<Method> methods = getSetterMethods(o.getClass()); + + for (String name : params.keySet()) { + + String methodName = "set" + name; + + for (Method method : methods) { + + if (method.getName().equalsIgnoreCase(methodName)){ + try { + method.invoke(o,params.get(name)); + + + + + + + } catch (IllegalAccessException | InvocationTargetException e) { + + e.printStackTrace(); + } + } + } + } + } + + public static List<Method> getGetterMethods(Class clz) { + return getMethods(clz, "get"); + } + + private static List<Method> getMethods(Class clz, String startWithName) { + List<Method> methods = new ArrayList<>(); + + for (Method method : clz.getDeclaredMethods()) { + + if (method.getName().startsWith(startWithName)) { + methods.add(method); + } + } + return methods; + } + + public static Map<String,Object> getParamterMap(Object o) { + Map<String, Object> params = new HashMap<>(); + + List<Method> methods = getGetterMethods(o.getClass()); //获得"getXXX"方法 + + for (Method method : methods) { + + String methodName = method.getName(); + String name = methodName.replaceFirst("get", "").toLowerCase(); //获得属性名 + + try { + params.put(name,method.invoke(o)); //将属性名 和属性值添加进去 + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + } + + return params; + + } +} diff --git a/group04/120549547/code2017/src/main/java/com/coding/litestruts/Struts.java b/group04/120549547/code2017/src/main/java/com/coding/litestruts/Struts.java new file mode 100644 index 0000000000..f446bec31c --- /dev/null +++ b/group04/120549547/code2017/src/main/java/com/coding/litestruts/Struts.java @@ -0,0 +1,67 @@ +package com.coding.litestruts; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Map; + + + +public class Struts { + + + + public static View runAction(String actionName, Map<String,String> parameters) throws NoSuchMethodException, IOException, InstantiationException, IllegalAccessException, InvocationTargetException, ClassNotFoundException { + + /* + + 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中的 <result> 配置,以及execute的返回值, 确定哪一个jsp, + 放到View对象的jsp字段中。 + + */ + try { + Configuration cfg = new Configuration("struts.xml"); + + String clzName = cfg.getClassName(actionName); + if (clzName == null) { + return null; + } + String classPath = Struts.class.getClassLoader().getResource("").getPath(); + + System.out.println("clzName = " + clzName); + System.out.println("classPath = " + classPath); + Class<?> clz = Class.forName(clzName); + + Object o = clz.newInstance(); + ReflectionUtil.setParameters(o, parameters); //将参数注入属性 + Method m = clz.getDeclaredMethod("execute"); + String resultName = (String) m.invoke(o); //执行execute方法 + + Map<String, Object> params = ReflectionUtil.getParamterMap(o); //根据action获取model参数 + + String jsp = cfg.getResultView(actionName, resultName); //通过返回结果去拿视图名 + + View view = new View(); + view.setJsp(jsp); + view.setParameters(params); + return view; + } catch (IOException | InstantiationException | NoSuchMethodException | InvocationTargetException | ClassNotFoundException | IllegalAccessException e) { + e.printStackTrace(); + throw e; + } + } + +} diff --git a/group04/120549547/code2017/src/main/java/com/coding/litestruts/StrutsTest.java b/group04/120549547/code2017/src/main/java/com/coding/litestruts/StrutsTest.java new file mode 100644 index 0000000000..041fa4d889 --- /dev/null +++ b/group04/120549547/code2017/src/main/java/com/coding/litestruts/StrutsTest.java @@ -0,0 +1,47 @@ +package com.coding.litestruts; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; + + + + + +public class StrutsTest { + + @Test + public void testLoginActionSuccess() throws IllegalAccessException, InvocationTargetException, IOException, InstantiationException, NoSuchMethodException, ClassNotFoundException { + + String actionName = "login"; + + Map<String,String> params = new HashMap<String,String>(); + 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() throws IllegalAccessException, InvocationTargetException, IOException, InstantiationException, NoSuchMethodException, ClassNotFoundException { + String actionName = "login"; + Map<String,String> params = new HashMap<String,String>(); + 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/group04/120549547/code2017/src/main/java/com/coding/litestruts/View.java b/group04/120549547/code2017/src/main/java/com/coding/litestruts/View.java new file mode 100644 index 0000000000..b6e795aa4a --- /dev/null +++ b/group04/120549547/code2017/src/main/java/com/coding/litestruts/View.java @@ -0,0 +1,23 @@ +package com.coding.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/group04/120549547/code2017/src/test/java/com/coding/basic/array/ArrayListTest.java b/group04/120549547/code2017/src/test/java/com/coding/basic/array/ArrayListTest.java new file mode 100644 index 0000000000..abd49e98e3 --- /dev/null +++ b/group04/120549547/code2017/src/test/java/com/coding/basic/array/ArrayListTest.java @@ -0,0 +1,122 @@ +package com.coding.basic.array; + +import com.coding.basic.Iterator; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Created by bobi on 2017/4/1. + * at code2017 + */ +public class ArrayListTest { + + private ArrayList<Integer> arrayList; + @Before + public void init() { + arrayList = new ArrayList<>(); + for (int i = 0; i < 5; i++) { + arrayList.add(i); + } + } + + @Test + public void size() throws Exception { + Assert.assertEquals(5, arrayList.size()); + arrayList.add(6); + Assert.assertEquals(6, arrayList.size()); + + } + + @Test + public void isEmpty() throws Exception { + arrayList.clear(); + Assert.assertEquals(0, arrayList.size()); + Assert.assertTrue(arrayList.isEmpty()); + } + + @Test + public void contains() throws Exception { + Assert.assertTrue(arrayList.contains(0)); + Assert.assertTrue(arrayList.contains(4)); + Assert.assertFalse(arrayList.contains(5)); + } + + @Test + public void toArray() throws Exception { + Integer[] integers = new Integer[]{0, 1, 2, 3, 4}; + Assert.assertArrayEquals(integers, arrayList.toArray()); + } + + @Test + public void add() throws Exception { + arrayList.add(5); + Assert.assertEquals(5, arrayList.get(arrayList.size() - 1).intValue()); + arrayList.add(0, 6); + arrayList.add(3, 7); + arrayList.add(arrayList.size(), 8); + + Assert.assertEquals(9, arrayList.size()); + Assert.assertEquals(6, arrayList.get(0).intValue()); + Assert.assertEquals(8, arrayList.get(arrayList.size()-1).intValue()); + Assert.assertEquals(7, arrayList.get(3).intValue()); + } + + @Test + public void remove() throws Exception { + arrayList.remove(0); + arrayList.remove(3); + arrayList.add(5); + Assert.assertArrayEquals(arrayList.toArray(), new Integer[]{1,2,3,5}); + + arrayList.remove(new Integer(1)); + arrayList.remove(new Integer(2)); + arrayList.remove(new Integer(5)); + arrayList.add(6); + arrayList.add(7); + + Assert.assertArrayEquals(arrayList.toArray(), new Integer[]{3,6,7}); + + } + + + + @Test + public void get() throws Exception { + Assert.assertEquals(0, arrayList.get(0).intValue()); + Assert.assertEquals(3, arrayList.get(3).intValue()); + arrayList.add(5); + arrayList.remove(0); + Assert.assertEquals(5, arrayList.get(4).intValue()); + } + + @Test + public void set() throws Exception { + arrayList.set(0,100); + arrayList.set(arrayList.size() - 1, 50); + Assert.assertEquals(100, arrayList.get(0).intValue()); + Assert.assertEquals(50, arrayList.get(arrayList.size() - 1).intValue()); + + } + + + + + + @Test + public void indexOf() throws Exception { + Assert.assertEquals(0, arrayList.indexOf(0)); + Assert.assertEquals(1, arrayList.indexOf(1)); + } + + @Test + public void iterator() throws Exception { + Iterator iterator = arrayList.iterator(); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(0, iterator.next()); + Assert.assertEquals(1, iterator.next()); + } + +} \ No newline at end of file diff --git a/group04/120549547/code2017/src/test/java/com/coding/basic/array/ArrayUtilTest.java b/group04/120549547/code2017/src/test/java/com/coding/basic/array/ArrayUtilTest.java new file mode 100644 index 0000000000..f16a7ab5ab --- /dev/null +++ b/group04/120549547/code2017/src/test/java/com/coding/basic/array/ArrayUtilTest.java @@ -0,0 +1,94 @@ +package com.coding.basic.array; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +/** + * Created by bobi on 2017/4/4. + * at code2017 + */ +public class ArrayUtilTest { + + private static int[] arr; + + @Before + public void setUp() throws Exception { + + arr = new int[10]; + + for (int i = 0; i < arr.length; i++) { + arr[i] = i; + } + + } + + private static void arrPrint(int[] arr){ + for (int i : arr) { + System.out.print(i + " "); + } + System.out.println(); + } + + @Test + public void reverseArray() throws Exception { + ArrayUtil.reverseArray(arr); + for (int i = 0; i < arr.length; i++) { + Assert.assertEquals(9-i, arr[i]); + } + } + + @Test + public void removeZero() throws Exception { + int oldArr[]={1,3,4,5,0,0,6,6,0,5,4,7,6,7,0,5}; + oldArr = ArrayUtil.removeZero(oldArr); + + Assert.assertArrayEquals(new int[]{1,3,4,5,6,6,5,4,7,6,7,5}, oldArr); + + } + + @Test + public void merge() throws Exception { + int[] a1 = {3, 5, 7,8}; + int[] a2 = {4, 5, 6,7} ; + + int[] a3 = ArrayUtil.merge(a1, a2); + Assert.assertArrayEquals(new int[]{3,4,5,6,7,8}, a3); + } + + @Test + public void grow() throws Exception { + int[] a1 = {3, 5, 7,8}; + a1 = ArrayUtil.grow(a1, 3); + + Assert.assertArrayEquals(new int[]{3,5,7,8,0,0,0}, a1); + } + + @Test + public void fibonacci() throws Exception { + int[] arr = ArrayUtil.fibonacci1(100); + arrPrint(arr); + } + + @Test + public void getPrimes() throws Exception { + int[] a1 = ArrayUtil.getPrimes(100); + arrPrint(a1); + } + + @Test + public void getPerfectNumbers() throws Exception { + int[] a1 = ArrayUtil.getPerfectNumbers(10000); + arrPrint(a1); + } + + @Test + public void join() throws Exception { + int[] a1 = {3,4,5,6,7}; + String str = ArrayUtil.join(a1, "-"); + System.out.println("str = " + str); + + } + +} \ No newline at end of file diff --git a/group04/120549547/code2017/src/test/java/com/coding/basic/linklist/LinkedListTest.java b/group04/120549547/code2017/src/test/java/com/coding/basic/linklist/LinkedListTest.java new file mode 100644 index 0000000000..f020e64828 --- /dev/null +++ b/group04/120549547/code2017/src/test/java/com/coding/basic/linklist/LinkedListTest.java @@ -0,0 +1,155 @@ +package com.coding.basic.linklist; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +/** + * Created by bobi on 2017/3/31. + * at code2017 + */ +public class LinkedListTest { + + + @Before + public void init() { + linkedList = new LinkedList<>(); + for (int i = 0; i < 6; i++) { + linkedList.add(1<<i); + } + } + @Test + public void reverse() throws Exception { + linkedList.reverse(); + linkedList.printf(); + } + @Test + public void contains() throws Exception { + Assert.assertFalse(linkedList.contains(15)); + Assert.assertTrue(linkedList.contains(16)); + } + + @Test + public void clear() throws Exception { + linkedList.clear(); + Assert.assertTrue(linkedList.isEmpty()); + Assert.assertTrue(linkedList.size() == 0); + } + + @Test + public void get() throws Exception { + Assert.assertEquals(8, linkedList.get(3).intValue()); + linkedList.remove(3); + Assert.assertEquals(16, linkedList.get(3).intValue()); + + linkedList.set(3, 100); + + Assert.assertEquals(100, linkedList.get(3).intValue()); + + } + + + + + + private LinkedList<Integer> linkedList; + + @Test + public void remove() throws Exception { + //测试添加删除 + { + linkedList.printf(); + linkedList.remove(new Integer(1)); + linkedList.remove(new Integer(8)); + linkedList.remove(new Integer(32)); + linkedList.add(50); + linkedList.add(0, 100); + Assert.assertArrayEquals(linkedList.toArray(), new Integer[]{ 100, 2, 4, 16, 50}); + +// + linkedList.remove(new Integer(16)); + linkedList.add(linkedList.size() - 1, 25); + Assert.assertArrayEquals(linkedList.toArray(), new Integer[]{ 100,2, 4, 25, 50}); + } + + } + + + @Test + public void removeFirstHalf() throws Exception { + linkedList.removeFirstHalf(); + linkedList.removeFirstHalf(); + linkedList.printf(); + } + + @Test + public void getElements() throws Exception { + + } + + @Test + public void subtract() throws Exception { + + } + + @Test + public void removeDuplicateValues() throws Exception { + linkedList.removeFirstHalf(); + LinkedList list = new LinkedList<Integer>(); + list.add(8); + list.add(16); + list.add(32); + Assert.assertArrayEquals(linkedList.toArray(), list.toArray()); + linkedList.removeFirstHalf(); + list.remove(0); + Assert.assertArrayEquals(linkedList.toArray(), list.toArray()); + + } + + @Test + public void removeByLength() throws Exception { + // 测试删除开始节点 + { + linkedList.remove(0, 2); + Assert.assertEquals(linkedList.size(), 4); + for (int i = 0; i < 3; i++) { + Assert.assertEquals(linkedList.get(i).intValue(), 1<<(i+2)); + } + } + + // 测试删除中间节点 + { + init(); + linkedList.remove(1, 2); + Assert.assertEquals(linkedList.size(), 4); + Assert.assertEquals(linkedList.get(0).intValue(), 1); + Assert.assertEquals(linkedList.get(1).intValue(), 8); + Assert.assertEquals(linkedList.get(2).intValue(), 16); + } +// + // 测试删除末尾节点 + { + init(); + linkedList.remove(4, 2); + Assert.assertEquals(linkedList.size(), 4); + Assert.assertEquals(linkedList.get(0).intValue(), 1); + Assert.assertEquals(linkedList.get(1).intValue(), 2); + Assert.assertEquals(linkedList.get(2).intValue(), 4); + Assert.assertEquals(linkedList.get(3).intValue(), 8); + } +// + // 测试删除全部 + { + init(); + linkedList.remove(0, 6); + Assert.assertEquals(linkedList.size(), 0); + } + } + + @Test + public void intersection() throws Exception { + + } + +} \ No newline at end of file diff --git a/group04/120549547/code2017/src/test/java/com/coding/basic/queue/ArrayQueueTest.java b/group04/120549547/code2017/src/test/java/com/coding/basic/queue/ArrayQueueTest.java new file mode 100644 index 0000000000..cd0d8abcc8 --- /dev/null +++ b/group04/120549547/code2017/src/test/java/com/coding/basic/queue/ArrayQueueTest.java @@ -0,0 +1,68 @@ +package com.coding.basic.queue; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Created by bobi on 2017/4/1. + * at code2017 + */ +public class ArrayQueueTest { + private ArrayQueue<Integer> arrayQueue; + + @Before + public void init(){ + arrayQueue = new ArrayQueue<>(6); + for (int i = 0; i < 5; i++) { + arrayQueue.add(i); + } + + } + @Test + public void add() throws Exception { + Assert.assertTrue(arrayQueue.add(5)); + + + Assert.assertEquals(0, arrayQueue.peek().intValue()); + Assert.assertEquals(0, arrayQueue.poll().intValue()); + Assert.assertEquals(1, arrayQueue.poll().intValue()); + + for (int i = 0; i < 4; i++) { + arrayQueue.remove(); + } + Assert.assertTrue(arrayQueue.isEmpty()); + } + + @Test + public void offer() throws Exception { + Assert.assertTrue(arrayQueue.offer(5)); + Assert.assertFalse(arrayQueue.offer(6)); + } + + @Test + public void remove() throws Exception { + arrayQueue.remove(); + arrayQueue.remove(); + arrayQueue.remove(); + arrayQueue.remove(); + + arrayQueue.add(5); + arrayQueue.add(6); + arrayQueue.add(7); + arrayQueue.add(8); + arrayQueue.add(9); + + + Assert.assertEquals(4, arrayQueue.remove().intValue()); + Assert.assertEquals(5, arrayQueue.remove().intValue()); + Assert.assertEquals(6, arrayQueue.remove().intValue()); + Assert.assertEquals(7, arrayQueue.remove().intValue()); + Assert.assertEquals(8, arrayQueue.remove().intValue()); + Assert.assertEquals(9, arrayQueue.remove().intValue()); + } + + +} \ No newline at end of file diff --git a/group04/120549547/code2017/src/test/java/com/coding/litestruts/ConfigurationTest.java b/group04/120549547/code2017/src/test/java/com/coding/litestruts/ConfigurationTest.java new file mode 100644 index 0000000000..40a3013741 --- /dev/null +++ b/group04/120549547/code2017/src/test/java/com/coding/litestruts/ConfigurationTest.java @@ -0,0 +1,45 @@ +package com.coding.litestruts; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + + +/** + * Created by bobi on 2017/4/1. + * at code2017 + */ +public class ConfigurationTest { + private Configuration config; + @Before + public void setUp() throws Exception { + config = new Configuration("struts.xml"); + } + + @After + public void tearDown() throws Exception { + + } + + + @Test + public void testGetClassName(){ + String clzName = config.getClassName("login"); + Assert.assertEquals("com.coding.litestruts.LoginAction", clzName); + clzName = config.getClassName("logout"); + Assert.assertEquals("com.coding.litestruts.LogoutAction", clzName); + + } + + @Test + public void testGetResultView(){ + String jsp = config.getResultView("login", "success"); + Assert.assertEquals("jsp/homepage.jsp", jsp); + + jsp = config.getResultView("login", "fail"); + Assert.assertEquals("jsp/showLogin.jsp", jsp); + } + +} \ No newline at end of file diff --git a/group04/120549547/code2017/src/test/java/com/coding/litestruts/ReflectionUtilTest.java b/group04/120549547/code2017/src/test/java/com/coding/litestruts/ReflectionUtilTest.java new file mode 100644 index 0000000000..d66188988b --- /dev/null +++ b/group04/120549547/code2017/src/test/java/com/coding/litestruts/ReflectionUtilTest.java @@ -0,0 +1,124 @@ +package com.coding.litestruts; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +/** + * Created by bobi on 2017/4/1. + * at code2017 + */ +public class ReflectionUtilTest { + @Before + public void setUp() throws Exception { + + } + + @After + public void tearDown() throws Exception { + + } + + @Test + public void testGetSetterMethod() throws ClassNotFoundException { + String name = "com.coding.litestruts.LoginAction"; + + Class clz = Class.forName(name); + List<Method> methods = ReflectionUtil.getSetterMethods(clz); + + Assert.assertEquals(2, methods.size()); + + List<String> expectedNames = new ArrayList<>(); + expectedNames.add("setName"); + expectedNames.add("setPassword"); + + List<String> acctualNames = new ArrayList<>(); + for (Method method : methods) { + acctualNames.add(method.getName()); + } + + Assert.assertTrue(acctualNames.containsAll(expectedNames)); + + } + + @Test + public void testSetParameters() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException { + String name = "com.coding.litestruts.LoginAction"; + + Class clz = Class.forName(name); + Object o = clz.newInstance(); + + Map<String, String> 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)); + + } + + + @Test + public void testGetGetterMethod() throws ClassNotFoundException { + String name = "com.coding.litestruts.LoginAction"; + + Class clz = Class.forName(name); + List<Method> methods = ReflectionUtil.getGetterMethods(clz); + + Assert.assertEquals(3, methods.size()); + + List<String> expectedNames = new ArrayList<>(); + expectedNames.add("getName"); + expectedNames.add("getPassword"); + expectedNames.add("getMessage"); + + List<String> acctualNames = new ArrayList<>(); + + for (Method method : methods) { + acctualNames.add(method.getName()); + } + + Assert.assertTrue(acctualNames.containsAll(expectedNames)); + + } + + @Test + public void testGetParameters() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException { + String name = "com.coding.litestruts.LoginAction"; + Class clz = Class.forName(name); + + LoginAction o = (LoginAction) clz.newInstance(); + o.setName("test"); + o.setPassword("123456"); + + Map<String, Object> params; + params = ReflectionUtil.getParamterMap(o); + + Assert.assertEquals(3, params.size()); + Assert.assertEquals(null, params.get("message")); + Assert.assertEquals("test", params.get("name")); + Assert.assertEquals("123456", params.get("password")); + + + } + + @Test + public void testDouble(){ + double d = 6.02e23; + long i = (long) d; + System.out.println(i); + } +} \ No newline at end of file diff --git a/group04/120549547/my.txt b/group04/120549547/my.txt deleted file mode 100644 index 3da1ec26e9..0000000000 --- a/group04/120549547/my.txt +++ /dev/null @@ -1 +0,0 @@ -HelloWorld From e75f61bc6304fa2d7ac7fab3e77c257ec54e1e82 Mon Sep 17 00:00:00 2001 From: gongxun <gongxun@wesai.com> Date: Wed, 5 Apr 2017 23:15:19 +0800 Subject: [PATCH 130/287] =?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 --- .../785396327/3.12/jvm_1/ClassFileLoader.java | 50 +++++++++++ .../3.12/jvm_1/ClassFileloaderTest.java | 86 +++++++++++++++++++ group17/785396327/3.12/jvm_1/EmployeeV1.java | 32 +++++++ 3 files changed, 168 insertions(+) create mode 100644 group17/785396327/3.12/jvm_1/ClassFileLoader.java create mode 100644 group17/785396327/3.12/jvm_1/ClassFileloaderTest.java create mode 100644 group17/785396327/3.12/jvm_1/EmployeeV1.java diff --git a/group17/785396327/3.12/jvm_1/ClassFileLoader.java b/group17/785396327/3.12/jvm_1/ClassFileLoader.java new file mode 100644 index 0000000000..95f68a5a7f --- /dev/null +++ b/group17/785396327/3.12/jvm_1/ClassFileLoader.java @@ -0,0 +1,50 @@ +package jvm_1; + +import java.io.*; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by william on 2017/4/5. + */ +public class ClassFileLoader { + private List<String> clzPaths = new ArrayList<String>(); + + public byte[] readBinaryCode(String className) { + InputStream fis = null; + String filePath = clzPaths.get(0) + "\\\\" + className.replaceAll("\\.", "\\\\") + ".class"; + byte[] buffer = new byte[(int) new File(filePath).length()]; + try { + if (clzPaths.size() > 0 && className != null && !className.trim().equals("")) { + fis = new FileInputStream(filePath); + while (fis.read(buffer) != -1) ; + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (fis != null) + try { + fis.close(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + fis = null; + } + } + return buffer; + } + + + public void addClassPath(String path) { + clzPaths.add(path); + } + + + public String getClassPath() { + StringBuilder sb = new StringBuilder(); + for (String clzPath : clzPaths) { + sb.append(clzPath).append(";"); + } + return sb.substring(0, sb.length() - 1); + } +} diff --git a/group17/785396327/3.12/jvm_1/ClassFileloaderTest.java b/group17/785396327/3.12/jvm_1/ClassFileloaderTest.java new file mode 100644 index 0000000000..067cd93c2b --- /dev/null +++ b/group17/785396327/3.12/jvm_1/ClassFileloaderTest.java @@ -0,0 +1,86 @@ +package jvm_1; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * Created by william on 2017/4/5. + */ +public class ClassFileloaderTest { + static String path1 = "D:\\workspace\\IDEA\\homework\\coding2017\\group17\\785396327\\out\\production\\785396327"; + 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 = "jvm_1.EmployeeV1"; + + byte[] byteCodes = loader.readBinaryCode(className); + + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + Assert.assertEquals(1020, byteCodes.length); + + } + + + @Test + public void testMagicNumber(){ + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "jvm_1.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/group17/785396327/3.12/jvm_1/EmployeeV1.java b/group17/785396327/3.12/jvm_1/EmployeeV1.java new file mode 100644 index 0000000000..bb23d04390 --- /dev/null +++ b/group17/785396327/3.12/jvm_1/EmployeeV1.java @@ -0,0 +1,32 @@ +package jvm_1; + +/** + * Created by william on 2017/4/5. + */ +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 f878406cc1f94f5a31860c05916e8d723565f6f5 Mon Sep 17 00:00:00 2001 From: gongxun <gongxun@wesai.com> Date: Wed, 5 Apr 2017 23:18:14 +0800 Subject: [PATCH 131/287] =?UTF-8?q?=E5=AE=8C=E6=88=903=E6=9C=8826=E6=97=A5?= =?UTF-8?q?=E4=BD=9C=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group17/785396327/{3.12 => 3.26}/jvm_1/ClassFileLoader.java | 0 .../785396327/{3.12 => 3.26}/jvm_1/ClassFileloaderTest.java | 0 group17/785396327/{3.12 => 3.26}/jvm_1/EmployeeV1.java | 0 group17/785396327/3.26/{ => lru}/LRUPageFrame.java | 2 ++ group17/785396327/3.26/{ => lru}/LRUPageFrameTest.java | 4 +++- 5 files changed, 5 insertions(+), 1 deletion(-) rename group17/785396327/{3.12 => 3.26}/jvm_1/ClassFileLoader.java (100%) rename group17/785396327/{3.12 => 3.26}/jvm_1/ClassFileloaderTest.java (100%) rename group17/785396327/{3.12 => 3.26}/jvm_1/EmployeeV1.java (100%) rename group17/785396327/3.26/{ => lru}/LRUPageFrame.java (99%) rename group17/785396327/3.26/{ => lru}/LRUPageFrameTest.java (94%) diff --git a/group17/785396327/3.12/jvm_1/ClassFileLoader.java b/group17/785396327/3.26/jvm_1/ClassFileLoader.java similarity index 100% rename from group17/785396327/3.12/jvm_1/ClassFileLoader.java rename to group17/785396327/3.26/jvm_1/ClassFileLoader.java diff --git a/group17/785396327/3.12/jvm_1/ClassFileloaderTest.java b/group17/785396327/3.26/jvm_1/ClassFileloaderTest.java similarity index 100% rename from group17/785396327/3.12/jvm_1/ClassFileloaderTest.java rename to group17/785396327/3.26/jvm_1/ClassFileloaderTest.java diff --git a/group17/785396327/3.12/jvm_1/EmployeeV1.java b/group17/785396327/3.26/jvm_1/EmployeeV1.java similarity index 100% rename from group17/785396327/3.12/jvm_1/EmployeeV1.java rename to group17/785396327/3.26/jvm_1/EmployeeV1.java diff --git a/group17/785396327/3.26/LRUPageFrame.java b/group17/785396327/3.26/lru/LRUPageFrame.java similarity index 99% rename from group17/785396327/3.26/LRUPageFrame.java rename to group17/785396327/3.26/lru/LRUPageFrame.java index 35a7f1e8ca..d296335978 100644 --- a/group17/785396327/3.26/LRUPageFrame.java +++ b/group17/785396327/3.26/lru/LRUPageFrame.java @@ -1,3 +1,5 @@ +package lru; + /** * Created by william on 2017/3/31. * 1. 新数据插入到链表头部; diff --git a/group17/785396327/3.26/LRUPageFrameTest.java b/group17/785396327/3.26/lru/LRUPageFrameTest.java similarity index 94% rename from group17/785396327/3.26/LRUPageFrameTest.java rename to group17/785396327/3.26/lru/LRUPageFrameTest.java index 7b13e17815..ff619f5b6d 100644 --- a/group17/785396327/3.26/LRUPageFrameTest.java +++ b/group17/785396327/3.26/lru/LRUPageFrameTest.java @@ -1,3 +1,5 @@ +package lru; + import org.junit.Assert; import org.junit.Test; @@ -28,7 +30,7 @@ public void testAccess() { @Test public void testInnerMethod() { -// LRUPageFrame lruPageFrame = new LRUPageFrame(3); +// lru.LRUPageFrame lruPageFrame = new lru.LRUPageFrame(3); // lruPageFrame.access(1); // lruPageFrame.access(2); // lruPageFrame.access(3); From ffe1628f1907ad20e15c9bd0fb602328247460e9 Mon Sep 17 00:00:00 2001 From: 240094626 <michael-ketty@qq.com> Date: Thu, 6 Apr 2017 11:34:46 +0800 Subject: [PATCH 132/287] =?UTF-8?q?=E7=AC=AC=E5=9B=9B=E5=91=A8=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A=E2=80=94-=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jvm/loader/ClassFileLoader.java | 73 +++++++++++++++ .../jvm/test/ClassFileloaderTest.java | 92 +++++++++++++++++++ .../com/coderising/jvm/test/EmployeeV1.java | 28 ++++++ 3 files changed, 193 insertions(+) create mode 100644 group17/240094626/work_week_4/src/com/coderising/jvm/loader/ClassFileLoader.java create mode 100644 group17/240094626/work_week_4/src/com/coderising/jvm/test/ClassFileloaderTest.java create mode 100644 group17/240094626/work_week_4/src/com/coderising/jvm/test/EmployeeV1.java diff --git a/group17/240094626/work_week_4/src/com/coderising/jvm/loader/ClassFileLoader.java b/group17/240094626/work_week_4/src/com/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..b9d924a887 --- /dev/null +++ b/group17/240094626/work_week_4/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,73 @@ +package com.coderising.jvm.loader; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + + + +public class ClassFileLoader { + + private List<String> clzPaths = new ArrayList<String>(); + + public byte[] readBinaryCode(String className) { + if(null == className || "".equals(className)){ + return null; + } + className = className.replace(".", File.separator)+".class"; + Iterator<String> it = clzPaths.iterator(); + byte[] bytes = null; + while(it.hasNext() && bytes == null){ + String filePath = it.next()+File.separator+className; + bytes = getClassFile(filePath); + } + return bytes; + + } + + + private byte[] getClassFile(String filePath) { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + try { + InputStream is = new FileInputStream(new File(filePath)); + byte[] buffer = new byte[1024]; + int len = 0; + while((len=is.read(buffer)) > 0){ + bos.write(buffer,0, len); + } + } catch (Exception e) { + e.printStackTrace(); + } + return bos.toByteArray(); + } + + + public void addClassPath(String path) { + if(null != path && !"".equals(path)){ + clzPaths.add(path); + } + } + + + + public String getClassPath(){ + StringBuilder sb = new StringBuilder(); + Iterator<String> it = clzPaths.iterator(); + while(it.hasNext()){ + if(sb.length() > 0){ + sb.append(";"); + } + sb.append(it.next()); + } + return sb.toString(); + } + + + + + +} diff --git a/group17/240094626/work_week_4/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group17/240094626/work_week_4/src/com/coderising/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..a205045d2e --- /dev/null +++ b/group17/240094626/work_week_4/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,92 @@ +package com.coderising.jvm.test; + +import java.io.File; + +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 = "E:\\workspace-indigo-32-statsdb\\warm-up\\bin";//"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/group17/240094626/work_week_4/src/com/coderising/jvm/test/EmployeeV1.java b/group17/240094626/work_week_4/src/com/coderising/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..12e3d7efdd --- /dev/null +++ b/group17/240094626/work_week_4/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 From 88266ef48d585321f2e604856d00ddac4a55f01d Mon Sep 17 00:00:00 2001 From: earliest <earliest@hotmail.com> Date: Wed, 5 Apr 2017 21:54:19 -0700 Subject: [PATCH 133/287] add article link --- group17/article/20170326-20170402.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/group17/article/20170326-20170402.md b/group17/article/20170326-20170402.md index 3d45ad0516..6451f60f6b 100644 --- a/group17/article/20170326-20170402.md +++ b/group17/article/20170326-20170402.md @@ -30,7 +30,7 @@ 516886559 -1282579502 +1282579502 https://www.evernote.com/l/AZ2Rx5pxgf9I-JqkSpFANMwTK9fXR0KFV50 614982500 From 53f753cd966ff0764469de390ec1ce7fc7559826 Mon Sep 17 00:00:00 2001 From: 240094626 <michael-ketty@qq.com> Date: Thu, 6 Apr 2017 13:42:42 +0800 Subject: [PATCH 134/287] work_jvm_1_LRU --- .../coding/basic/linklist/LRUPageFrame.java | 126 ++++++++++++++++++ .../basic/linklist/LRUPageFrameTest.java | 31 +++++ .../com/coding/basic/linklist/LinkedList.java | 125 +++++++++++++++++ .../jvm/loader/ClassFileLoader.java | 0 .../jvm/test/ClassFileloaderTest.java | 0 .../com/coderising/jvm/test/EmployeeV1.java | 0 6 files changed, 282 insertions(+) create mode 100644 group17/240094626/work_jvm_1/data-structure/src/com/coding/basic/linklist/LRUPageFrame.java create mode 100644 group17/240094626/work_jvm_1/data-structure/src/com/coding/basic/linklist/LRUPageFrameTest.java create mode 100644 group17/240094626/work_jvm_1/data-structure/src/com/coding/basic/linklist/LinkedList.java rename group17/240094626/{work_week_4 => work_jvm_1}/src/com/coderising/jvm/loader/ClassFileLoader.java (100%) rename group17/240094626/{work_week_4 => work_jvm_1}/src/com/coderising/jvm/test/ClassFileloaderTest.java (100%) rename group17/240094626/{work_week_4 => work_jvm_1}/src/com/coderising/jvm/test/EmployeeV1.java (100%) diff --git a/group17/240094626/work_jvm_1/data-structure/src/com/coding/basic/linklist/LRUPageFrame.java b/group17/240094626/work_jvm_1/data-structure/src/com/coding/basic/linklist/LRUPageFrame.java new file mode 100644 index 0000000000..638cf181ae --- /dev/null +++ b/group17/240094626/work_jvm_1/data-structure/src/com/coding/basic/linklist/LRUPageFrame.java @@ -0,0 +1,126 @@ +package com.coding.basic.linklist; + +/** + * 用双向链表实现LRU算法 + * @author liuxin + * + */ +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.capacity = capacity; + currentSize = 0; + } + + /** + * 获取缓存中对象 + * + * @param key + * @return + */ + public void access(int pageNum) { + + // 判断缓存是否命中 + Node n = find(pageNum); + if(n != null){ + // 命中,则把节点提到表头 + moveNodeToHead(n); + }else{ + // 若未命中,新增节点放到表头,如果链表长度超过capacity,移除链表尾部节点 + n = new Node(); + n.pageNum = pageNum; + + if(currentSize >= capacity){ + removeLast(); + } + addNodeToHead(n); + } + } + + + + private void addNodeToHead(Node n) { + if(first == null){ + first = n; + last = n; + }else{ + n.next = first; + first.prev = n; + first = n; + } + currentSize++; + } + + private void removeLast() { + Node prevN = last.prev; + prevN.next = null; + last.prev = null; + last = prevN; + currentSize--; + } + + private void moveNodeToHead(Node n) { + if(n == first){ + return ; + }else if(n == last){ + Node preN = n.prev; + preN.next = null; + last.prev = null; + last = preN; + }else{ + // 中间节点 + Node preN = n.prev; + Node nextN = n.next; + preN.next = nextN; + nextN.prev = preN; + } + n.prev = null; + n.next = first; + first.prev = n; + first = n; + } + + private Node find(int pageNum) { + Node n = first; + while(n != null){ + if(n.pageNum == pageNum){ + return n; + } + n = n.next; + } + 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/group17/240094626/work_jvm_1/data-structure/src/com/coding/basic/linklist/LRUPageFrameTest.java b/group17/240094626/work_jvm_1/data-structure/src/com/coding/basic/linklist/LRUPageFrameTest.java new file mode 100644 index 0000000000..67cf36067b --- /dev/null +++ b/group17/240094626/work_jvm_1/data-structure/src/com/coding/basic/linklist/LRUPageFrameTest.java @@ -0,0 +1,31 @@ +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/group17/240094626/work_jvm_1/data-structure/src/com/coding/basic/linklist/LinkedList.java b/group17/240094626/work_jvm_1/data-structure/src/com/coding/basic/linklist/LinkedList.java new file mode 100644 index 0000000000..f4c7556a2e --- /dev/null +++ b/group17/240094626/work_jvm_1/data-structure/src/com/coding/basic/linklist/LinkedList.java @@ -0,0 +1,125 @@ +package com.coding.basic.linklist; + +import com.coding.basic.Iterator; +import com.coding.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/group17/240094626/work_week_4/src/com/coderising/jvm/loader/ClassFileLoader.java b/group17/240094626/work_jvm_1/src/com/coderising/jvm/loader/ClassFileLoader.java similarity index 100% rename from group17/240094626/work_week_4/src/com/coderising/jvm/loader/ClassFileLoader.java rename to group17/240094626/work_jvm_1/src/com/coderising/jvm/loader/ClassFileLoader.java diff --git a/group17/240094626/work_week_4/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group17/240094626/work_jvm_1/src/com/coderising/jvm/test/ClassFileloaderTest.java similarity index 100% rename from group17/240094626/work_week_4/src/com/coderising/jvm/test/ClassFileloaderTest.java rename to group17/240094626/work_jvm_1/src/com/coderising/jvm/test/ClassFileloaderTest.java diff --git a/group17/240094626/work_week_4/src/com/coderising/jvm/test/EmployeeV1.java b/group17/240094626/work_jvm_1/src/com/coderising/jvm/test/EmployeeV1.java similarity index 100% rename from group17/240094626/work_week_4/src/com/coderising/jvm/test/EmployeeV1.java rename to group17/240094626/work_jvm_1/src/com/coderising/jvm/test/EmployeeV1.java From ed148dd5e28410a93f0fa960b0c3766582437318 Mon Sep 17 00:00:00 2001 From: hejj <844028312@qq.com> Date: Thu, 6 Apr 2017 14:10:49 +0800 Subject: [PATCH 135/287] =?UTF-8?q?=E7=AC=AC=E5=9B=9B=E6=AC=A1=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../844028312/four/linklist/LRUPageFrame.java | 127 ++++++++++++++++++ .../four/linklist/LRUPageFrameTest.java | 31 +++++ .../844028312/four/linklist/LinkedList.java | 125 +++++++++++++++++ .../jvm/loader/ClassFileLoader.java | 92 +++++++++++++ .../jvm/test/ClassFileloaderTest.java | 92 +++++++++++++ .../com/coderising/jvm/test/EmployeeV1.java | 28 ++++ 6 files changed, 495 insertions(+) create mode 100644 group04/844028312/four/linklist/LRUPageFrame.java create mode 100644 group04/844028312/four/linklist/LRUPageFrameTest.java create mode 100644 group04/844028312/four/linklist/LinkedList.java create mode 100644 group04/844028312/four/min-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java create mode 100644 group04/844028312/four/min-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java create mode 100644 group04/844028312/four/min-jvm/src/com/coderising/jvm/test/EmployeeV1.java diff --git a/group04/844028312/four/linklist/LRUPageFrame.java b/group04/844028312/four/linklist/LRUPageFrame.java new file mode 100644 index 0000000000..0d305f7b06 --- /dev/null +++ b/group04/844028312/four/linklist/LRUPageFrame.java @@ -0,0 +1,127 @@ +package com.coding.basic.linklist; + +/** + * 用双向链表实现LRU算法 + * @author liuxin + * + */ +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) { + + this.capacity = capacity; + + } + + /** + * 获取缓存中对象 + * + * @param key + * @return + */ + public void access(int pageNum) { + if(this.first==null){ + first=new Node(null,null,pageNum); + return ; + } + else{ + if(last==null){ + if(!moveToFirst(pageNum)){ + Node nf=new Node(null,this.first,pageNum); + this.first.prev=nf; + this.first=nf; + //判断是否为最后一个 + Node cur=this.first; + int i=1; + while(cur!=null){ + cur=cur.next; + i++; + if(i==this.capacity){ + this.last=cur; + break; + } + } + } + } + else{ + if(!moveToFirst(pageNum)){ + Node nf=new Node(null,this.first,pageNum); + this.first.prev=nf; + this.first=nf; + this.last.prev.next=null; + this.last=this.last.prev; + } + } + } + + } + public boolean moveToFirst(int pageNum){ + Node indexOf=indexOf(pageNum); + if(indexOf!=null){ + if(indexOf==this.first){ + return true; + } + else if(indexOf==this.last){ + this.first.prev=indexOf; + this.last=indexOf.prev; + this.last.next=null; + indexOf.next=this.first; + this.first=indexOf; + } + else{ + indexOf.next.prev=indexOf.prev; + indexOf.prev.next=indexOf.next; + this.first.prev=indexOf; + indexOf.prev=null; + indexOf.next=this.first; + this.first=indexOf; + } + return true; + } + return false; + } + public Node indexOf(int pageNum){ + Node cur=this.first; + while(cur!=null){ + if(cur.pageNum==pageNum){ + return cur; + } + cur=cur.next; + } + 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/group04/844028312/four/linklist/LRUPageFrameTest.java b/group04/844028312/four/linklist/LRUPageFrameTest.java new file mode 100644 index 0000000000..67cf36067b --- /dev/null +++ b/group04/844028312/four/linklist/LRUPageFrameTest.java @@ -0,0 +1,31 @@ +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/group04/844028312/four/linklist/LinkedList.java b/group04/844028312/four/linklist/LinkedList.java new file mode 100644 index 0000000000..f4c7556a2e --- /dev/null +++ b/group04/844028312/four/linklist/LinkedList.java @@ -0,0 +1,125 @@ +package com.coding.basic.linklist; + +import com.coding.basic.Iterator; +import com.coding.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/group04/844028312/four/min-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java b/group04/844028312/four/min-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..d2bed45b48 --- /dev/null +++ b/group04/844028312/four/min-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,92 @@ +package com.coderising.jvm.loader; + +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + + +import javax.annotation.Resources; + + + + + +public class ClassFileLoader { + + private List<String> clzPaths = new ArrayList<String>(); + + public byte[] readBinaryCode(String className) { + InputStream ips = null; + ByteArrayOutputStream bao = null; + try { + String name=className.replace(".", "\\")+".class"; + for(int i=0;i<clzPaths.size();i++){ + String path=clzPaths.get(i)+"\\"+name; + File file =new File(path); + if(file.exists()){ + ips=new FileInputStream(file); + byte[] b=new byte[1024]; + bao=new ByteArrayOutputStream(); + while(ips.read(b, 0, b.length)!=-1){ + bao.write(b); + } + return bao.toByteArray(); + } + } + } catch (Exception e) { + e.printStackTrace(); + }finally{ + if(ips!=null){ + try { + ips.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + if(bao!=null){ + try { + bao.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + return null; + + + } + + + public void addClassPath(String path) { + clzPaths.add(path); + } + + + + public String getClassPath(){ + StringBuffer sb=new StringBuffer(); + 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(); + } + + + + + +} diff --git a/group04/844028312/four/min-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group04/844028312/four/min-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..6c617b54ce --- /dev/null +++ b/group04/844028312/four/min-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,92 @@ +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:\\workspace\\min-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); + int i=byteCodes.length; + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + Assert.assertEquals(2048, 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/group04/844028312/four/min-jvm/src/com/coderising/jvm/test/EmployeeV1.java b/group04/844028312/four/min-jvm/src/com/coderising/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..12e3d7efdd --- /dev/null +++ b/group04/844028312/four/min-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 From f1d441688ef24f69d0fe11874bd5262cbc898e90 Mon Sep 17 00:00:00 2001 From: zheng <765324639@qq.com> Date: Thu, 6 Apr 2017 15:39:13 +0800 Subject: [PATCH 136/287] =?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?= <zhang19921207@gmail.com> Date: Thu, 6 Apr 2017 15:55:58 +0800 Subject: [PATCH 137/287] 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?= <zhang19921207@gmail.com> Date: Thu, 6 Apr 2017 15:56:17 +0800 Subject: [PATCH 138/287] 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 139/287] =?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 @@ -<?xml version="1.0" encoding="UTF-8"?> -<struts> - <action name="login" class="zavier.week02.coderising.litestruts.LoginAction"> - <result name="success">/jsp/homepage.jsp</result> - <result name="fail">/jsp/showLogin.jsp</result> - </action> - <action name="logout" class="zavier.week02.coderising.litestruts.LogoutAction"> - <result name="success">/jsp/welcome.jsp</result> - <result name="error">/jsp/error.jsp</result> - </action> -</struts> \ 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 e2633d250070358a1541845bc54ab96e4229efed Mon Sep 17 00:00:00 2001 From: guodongym <guodongym@163.com> Date: Thu, 6 Apr 2017 20:54:17 +0800 Subject: [PATCH 140/287] =?UTF-8?q?=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group12/377401843/learning/pom.xml | 11 + .../{collection => array}/ArrayList.java | 15 +- .../java/com/zhaogd/collection/Queue.java | 2 + .../collection/linkedlist/LRUPageFrame.java | 164 ++++++++++++++ .../linkedlist/LRUPageFrameTest.java | 34 +++ .../{ => linkedlist}/LinkedList.java | 13 +- .../zhaogd/collection/{ => stack}/Stack.java | 4 +- .../zhaogd/collection/stack/StackUtil.java | 45 ++++ .../java/com/zhaogd/jvm/clz/AccessFlag.java | 25 +++ .../java/com/zhaogd/jvm/clz/ClassFile.java | 75 +++++++ .../java/com/zhaogd/jvm/clz/ClassIndex.java | 19 ++ .../com/zhaogd/jvm/constant/ClassInfo.java | 24 +++ .../com/zhaogd/jvm/constant/ConstantInfo.java | 29 +++ .../com/zhaogd/jvm/constant/ConstantPool.java | 29 +++ .../com/zhaogd/jvm/constant/FieldRefInfo.java | 54 +++++ .../zhaogd/jvm/constant/MethodRefInfo.java | 55 +++++ .../zhaogd/jvm/constant/NameAndTypeInfo.java | 45 ++++ .../zhaogd/jvm/constant/NullConstantInfo.java | 13 ++ .../com/zhaogd/jvm/constant/StringInfo.java | 26 +++ .../com/zhaogd/jvm/constant/UTF8Info.java | 32 +++ .../zhaogd/jvm/loader/ByteCodeIterator.java | 5 + .../zhaogd/jvm/loader/ClassFileLoader.java | 140 ++++++++++++ .../zhaogd/jvm/loader/ClassFileParser.java | 35 +++ .../zhaogd/jvm/test/ClassFileloaderTest.java | 202 ++++++++++++++++++ .../java/com/zhaogd/jvm/test/EmployeeV1.java | 28 +++ .../main/java/com/zhaogd/jvm/util/Util.java | 24 +++ .../com/zhaogd/collection/ArrayListTest.java | 2 + .../com/zhaogd/collection/LinkedListTest.java | 2 + .../java/com/zhaogd/collection/StackTest.java | 2 + 29 files changed, 1142 insertions(+), 12 deletions(-) rename group12/377401843/learning/src/main/java/com/zhaogd/{collection => array}/ArrayList.java (87%) create mode 100644 group12/377401843/learning/src/main/java/com/zhaogd/collection/linkedlist/LRUPageFrame.java create mode 100644 group12/377401843/learning/src/main/java/com/zhaogd/collection/linkedlist/LRUPageFrameTest.java rename group12/377401843/learning/src/main/java/com/zhaogd/collection/{ => linkedlist}/LinkedList.java (94%) rename group12/377401843/learning/src/main/java/com/zhaogd/collection/{ => stack}/Stack.java (80%) create mode 100644 group12/377401843/learning/src/main/java/com/zhaogd/collection/stack/StackUtil.java create mode 100644 group12/377401843/learning/src/main/java/com/zhaogd/jvm/clz/AccessFlag.java create mode 100644 group12/377401843/learning/src/main/java/com/zhaogd/jvm/clz/ClassFile.java create mode 100644 group12/377401843/learning/src/main/java/com/zhaogd/jvm/clz/ClassIndex.java create mode 100644 group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/ClassInfo.java create mode 100644 group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/ConstantInfo.java create mode 100644 group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/ConstantPool.java create mode 100644 group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/FieldRefInfo.java create mode 100644 group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/MethodRefInfo.java create mode 100644 group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/NameAndTypeInfo.java create mode 100644 group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/NullConstantInfo.java create mode 100644 group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/StringInfo.java create mode 100644 group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/UTF8Info.java create mode 100644 group12/377401843/learning/src/main/java/com/zhaogd/jvm/loader/ByteCodeIterator.java create mode 100644 group12/377401843/learning/src/main/java/com/zhaogd/jvm/loader/ClassFileLoader.java create mode 100644 group12/377401843/learning/src/main/java/com/zhaogd/jvm/loader/ClassFileParser.java create mode 100644 group12/377401843/learning/src/main/java/com/zhaogd/jvm/test/ClassFileloaderTest.java create mode 100644 group12/377401843/learning/src/main/java/com/zhaogd/jvm/test/EmployeeV1.java create mode 100644 group12/377401843/learning/src/main/java/com/zhaogd/jvm/util/Util.java diff --git a/group12/377401843/learning/pom.xml b/group12/377401843/learning/pom.xml index f252611284..447c5546ce 100644 --- a/group12/377401843/learning/pom.xml +++ b/group12/377401843/learning/pom.xml @@ -20,6 +20,17 @@ <version>1.6.1</version> </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + <version>3.0</version> + </dependency> + + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>2.4</version> + </dependency> </dependencies> <build> diff --git a/group12/377401843/learning/src/main/java/com/zhaogd/collection/ArrayList.java b/group12/377401843/learning/src/main/java/com/zhaogd/array/ArrayList.java similarity index 87% rename from group12/377401843/learning/src/main/java/com/zhaogd/collection/ArrayList.java rename to group12/377401843/learning/src/main/java/com/zhaogd/array/ArrayList.java index d3afc5e01a..d5c5fe04cc 100644 --- a/group12/377401843/learning/src/main/java/com/zhaogd/collection/ArrayList.java +++ b/group12/377401843/learning/src/main/java/com/zhaogd/array/ArrayList.java @@ -1,7 +1,10 @@ -package com.zhaogd.collection; +package com.zhaogd.array; import java.util.Arrays; +import com.zhaogd.collection.Iterator; +import com.zhaogd.collection.List; + public class ArrayList implements List { private int size = 0; @@ -13,7 +16,7 @@ public class ArrayList implements List { * * @Method add * @param o - * @see com.guodong.datastructure.List#add(java.lang.Object) + * @see com.zhaogd.collection.guodong.datastructure.List#add(java.lang.Object) */ public void add(Object o) { ensureCapacityInternal(size + 1); @@ -27,7 +30,7 @@ public void add(Object o) { * @Method add * @param index * @param o - * @see com.guodong.datastructure.List#add(int, java.lang.Object) + * @see com.zhaogd.collection.guodong.datastructure.List#add(int, java.lang.Object) */ public void add(int index, Object o) { checkRangeForAdd(index); @@ -46,7 +49,7 @@ public void add(int index, Object o) { * @Method get * @param index * @return - * @see com.guodong.datastructure.List#get(int) + * @see com.zhaogd.collection.guodong.datastructure.List#get(int) */ public Object get(int index) { checkRangeForGetOrRemove(index); @@ -60,7 +63,7 @@ public Object get(int index) { * @Method remove * @param index * @return - * @see com.guodong.datastructure.List#remove(int) + * @see com.zhaogd.collection.guodong.datastructure.List#remove(int) */ public Object remove(int index) { checkRangeForGetOrRemove(index); @@ -80,7 +83,7 @@ public Object remove(int index) { * * @Method size * @return - * @see com.guodong.datastructure.List#size() + * @see com.zhaogd.collection.guodong.datastructure.List#size() */ public int size() { return size; diff --git a/group12/377401843/learning/src/main/java/com/zhaogd/collection/Queue.java b/group12/377401843/learning/src/main/java/com/zhaogd/collection/Queue.java index d4a0647ab6..b81d015351 100644 --- a/group12/377401843/learning/src/main/java/com/zhaogd/collection/Queue.java +++ b/group12/377401843/learning/src/main/java/com/zhaogd/collection/Queue.java @@ -1,5 +1,7 @@ package com.zhaogd.collection; +import com.zhaogd.collection.linkedlist.LinkedList; + public class Queue { private LinkedList element = new LinkedList(); diff --git a/group12/377401843/learning/src/main/java/com/zhaogd/collection/linkedlist/LRUPageFrame.java b/group12/377401843/learning/src/main/java/com/zhaogd/collection/linkedlist/LRUPageFrame.java new file mode 100644 index 0000000000..39a4e4063d --- /dev/null +++ b/group12/377401843/learning/src/main/java/com/zhaogd/collection/linkedlist/LRUPageFrame.java @@ -0,0 +1,164 @@ +package com.zhaogd.collection.linkedlist; + + +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 key + * @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/group12/377401843/learning/src/main/java/com/zhaogd/collection/linkedlist/LRUPageFrameTest.java b/group12/377401843/learning/src/main/java/com/zhaogd/collection/linkedlist/LRUPageFrameTest.java new file mode 100644 index 0000000000..b2fc8c8323 --- /dev/null +++ b/group12/377401843/learning/src/main/java/com/zhaogd/collection/linkedlist/LRUPageFrameTest.java @@ -0,0 +1,34 @@ +package com.zhaogd.collection.linkedlist; + +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()); + + } + +} diff --git a/group12/377401843/learning/src/main/java/com/zhaogd/collection/LinkedList.java b/group12/377401843/learning/src/main/java/com/zhaogd/collection/linkedlist/LinkedList.java similarity index 94% rename from group12/377401843/learning/src/main/java/com/zhaogd/collection/LinkedList.java rename to group12/377401843/learning/src/main/java/com/zhaogd/collection/linkedlist/LinkedList.java index 136f53284e..78721b060a 100644 --- a/group12/377401843/learning/src/main/java/com/zhaogd/collection/LinkedList.java +++ b/group12/377401843/learning/src/main/java/com/zhaogd/collection/linkedlist/LinkedList.java @@ -1,7 +1,10 @@ -package com.zhaogd.collection; +package com.zhaogd.collection.linkedlist; import java.util.NoSuchElementException; +import com.zhaogd.collection.Iterator; +import com.zhaogd.collection.List; + public class LinkedList implements List { private int size; @@ -15,7 +18,7 @@ public class LinkedList implements List { * * @Method add * @param o - * @see com.guodong.datastructure.List#add(java.lang.Object) + * @see com.zhaogd.collection.guodong.datastructure.List#add(java.lang.Object) */ public void add(Object o) { linkLast(o); @@ -27,7 +30,7 @@ public void add(Object o) { * @Method add * @param index * @param o - * @see com.guodong.datastructure.List#add(int, java.lang.Object) + * @see com.zhaogd.collection.guodong.datastructure.List#add(int, java.lang.Object) */ public void add(int index, Object o) { checkIndexForAdd(index); @@ -54,7 +57,7 @@ public void add(int index, Object o) { * @Method get * @param index * @return - * @see com.guodong.datastructure.List#get(int) + * @see com.zhaogd.collection.guodong.datastructure.List#get(int) */ public Object get(int index) { checkIndexForGet(index); @@ -71,7 +74,7 @@ public Object getLast() { * @Method remove * @param index * @return - * @see com.guodong.datastructure.List#remove(int) + * @see com.zhaogd.collection.guodong.datastructure.List#remove(int) */ public Object remove(int index) { checkIndexForGet(index); diff --git a/group12/377401843/learning/src/main/java/com/zhaogd/collection/Stack.java b/group12/377401843/learning/src/main/java/com/zhaogd/collection/stack/Stack.java similarity index 80% rename from group12/377401843/learning/src/main/java/com/zhaogd/collection/Stack.java rename to group12/377401843/learning/src/main/java/com/zhaogd/collection/stack/Stack.java index afb01f5f92..85a8800f39 100644 --- a/group12/377401843/learning/src/main/java/com/zhaogd/collection/Stack.java +++ b/group12/377401843/learning/src/main/java/com/zhaogd/collection/stack/Stack.java @@ -1,4 +1,6 @@ -package com.zhaogd.collection; +package com.zhaogd.collection.stack; + +import com.zhaogd.collection.linkedlist.LinkedList; public class Stack { private LinkedList elementData = new LinkedList(); diff --git a/group12/377401843/learning/src/main/java/com/zhaogd/collection/stack/StackUtil.java b/group12/377401843/learning/src/main/java/com/zhaogd/collection/stack/StackUtil.java new file mode 100644 index 0000000000..ecf128b27e --- /dev/null +++ b/group12/377401843/learning/src/main/java/com/zhaogd/collection/stack/StackUtil.java @@ -0,0 +1,45 @@ +package com.zhaogd.collection.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; + } + + +} diff --git a/group12/377401843/learning/src/main/java/com/zhaogd/jvm/clz/AccessFlag.java b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..1557b0ead2 --- /dev/null +++ b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/clz/AccessFlag.java @@ -0,0 +1,25 @@ +package com.zhaogd.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/377401843/learning/src/main/java/com/zhaogd/jvm/clz/ClassFile.java b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..bf6abbe3fd --- /dev/null +++ b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/clz/ClassFile.java @@ -0,0 +1,75 @@ +package com.zhaogd.jvm.clz; + +import com.zhaogd.jvm.constant.ClassInfo; +import com.zhaogd.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/377401843/learning/src/main/java/com/zhaogd/jvm/clz/ClassIndex.java b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..0bdf47d002 --- /dev/null +++ b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/clz/ClassIndex.java @@ -0,0 +1,19 @@ +package com.zhaogd.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/377401843/learning/src/main/java/com/zhaogd/jvm/constant/ClassInfo.java b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..9851e063c0 --- /dev/null +++ b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/ClassInfo.java @@ -0,0 +1,24 @@ +package com.zhaogd.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/377401843/learning/src/main/java/com/zhaogd/jvm/constant/ConstantInfo.java b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..0afd79256b --- /dev/null +++ b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/ConstantInfo.java @@ -0,0 +1,29 @@ +package com.zhaogd.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/377401843/learning/src/main/java/com/zhaogd/jvm/constant/ConstantPool.java b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..4663d4d195 --- /dev/null +++ b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/ConstantPool.java @@ -0,0 +1,29 @@ +package com.zhaogd.jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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/377401843/learning/src/main/java/com/zhaogd/jvm/constant/FieldRefInfo.java b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..bba61aea27 --- /dev/null +++ b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/FieldRefInfo.java @@ -0,0 +1,54 @@ +package com.zhaogd.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/377401843/learning/src/main/java/com/zhaogd/jvm/constant/MethodRefInfo.java b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..61c965bc0a --- /dev/null +++ b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/MethodRefInfo.java @@ -0,0 +1,55 @@ +package com.zhaogd.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/377401843/learning/src/main/java/com/zhaogd/jvm/constant/NameAndTypeInfo.java b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..aef7f16d1e --- /dev/null +++ b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,45 @@ +package com.zhaogd.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/377401843/learning/src/main/java/com/zhaogd/jvm/constant/NullConstantInfo.java b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..1cb411bee2 --- /dev/null +++ b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/NullConstantInfo.java @@ -0,0 +1,13 @@ +package com.zhaogd.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo(){ + + } + @Override + public int getType() { + return -1; + } + +} diff --git a/group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/StringInfo.java b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..c58bcb59d7 --- /dev/null +++ b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/StringInfo.java @@ -0,0 +1,26 @@ +package com.zhaogd.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/377401843/learning/src/main/java/com/zhaogd/jvm/constant/UTF8Info.java b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..c8b2e6a4c0 --- /dev/null +++ b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/constant/UTF8Info.java @@ -0,0 +1,32 @@ +package com.zhaogd.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/377401843/learning/src/main/java/com/zhaogd/jvm/loader/ByteCodeIterator.java b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..7147060b84 --- /dev/null +++ b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,5 @@ +package com.zhaogd.jvm.loader; + +public class ByteCodeIterator { + +} diff --git a/group12/377401843/learning/src/main/java/com/zhaogd/jvm/loader/ClassFileLoader.java b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..6d04787a99 --- /dev/null +++ b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/loader/ClassFileLoader.java @@ -0,0 +1,140 @@ +package com.zhaogd.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.zhaogd.jvm.clz.ClassFile; + + + + + +public class ClassFileLoader { + + private List<String> clzPaths = new ArrayList<String>(); + + 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/group12/377401843/learning/src/main/java/com/zhaogd/jvm/loader/ClassFileParser.java b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..fe3a75c0f0 --- /dev/null +++ b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/loader/ClassFileParser.java @@ -0,0 +1,35 @@ +package com.zhaogd.jvm.loader; + +import com.zhaogd.jvm.clz.AccessFlag; +import com.zhaogd.jvm.clz.ClassFile; +import com.zhaogd.jvm.clz.ClassIndex; +import com.zhaogd.jvm.constant.ConstantPool; + +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/group12/377401843/learning/src/main/java/com/zhaogd/jvm/test/ClassFileloaderTest.java b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..0391dd86be --- /dev/null +++ b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,202 @@ +package com.zhaogd.jvm.test; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.zhaogd.jvm.clz.ClassFile; +import com.zhaogd.jvm.clz.ClassIndex; +import com.zhaogd.jvm.constant.ClassInfo; +import com.zhaogd.jvm.constant.ConstantPool; +import com.zhaogd.jvm.constant.MethodRefInfo; +import com.zhaogd.jvm.constant.NameAndTypeInfo; +import com.zhaogd.jvm.constant.UTF8Info; +import com.zhaogd.jvm.loader.ClassFileLoader; + + + + + +public class ClassFileloaderTest { + + + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + + static String path1 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\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 { + } + + @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(); + } + + /** + * ---------------------------------------------------------------------- + */ + + + @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("<init>", 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/377401843/learning/src/main/java/com/zhaogd/jvm/test/EmployeeV1.java b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..e9f656131b --- /dev/null +++ b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/test/EmployeeV1.java @@ -0,0 +1,28 @@ +package com.zhaogd.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/group12/377401843/learning/src/main/java/com/zhaogd/jvm/util/Util.java b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/util/Util.java new file mode 100644 index 0000000000..9c2fcc183e --- /dev/null +++ b/group12/377401843/learning/src/main/java/com/zhaogd/jvm/util/Util.java @@ -0,0 +1,24 @@ +package com.zhaogd.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/377401843/learning/src/test/java/com/zhaogd/collection/ArrayListTest.java b/group12/377401843/learning/src/test/java/com/zhaogd/collection/ArrayListTest.java index c54e99b4db..f051ffc521 100644 --- a/group12/377401843/learning/src/test/java/com/zhaogd/collection/ArrayListTest.java +++ b/group12/377401843/learning/src/test/java/com/zhaogd/collection/ArrayListTest.java @@ -8,6 +8,8 @@ import org.junit.Before; import org.junit.Test; +import com.zhaogd.array.ArrayList; + public class ArrayListTest { ArrayList arrayList; diff --git a/group12/377401843/learning/src/test/java/com/zhaogd/collection/LinkedListTest.java b/group12/377401843/learning/src/test/java/com/zhaogd/collection/LinkedListTest.java index 32cac4bc6d..144d7ab466 100644 --- a/group12/377401843/learning/src/test/java/com/zhaogd/collection/LinkedListTest.java +++ b/group12/377401843/learning/src/test/java/com/zhaogd/collection/LinkedListTest.java @@ -8,6 +8,8 @@ import org.junit.Before; import org.junit.Test; +import com.zhaogd.collection.linkedlist.LinkedList; + public class LinkedListTest { private LinkedList linkedList; diff --git a/group12/377401843/learning/src/test/java/com/zhaogd/collection/StackTest.java b/group12/377401843/learning/src/test/java/com/zhaogd/collection/StackTest.java index 510e4c45f6..f393481ef5 100644 --- a/group12/377401843/learning/src/test/java/com/zhaogd/collection/StackTest.java +++ b/group12/377401843/learning/src/test/java/com/zhaogd/collection/StackTest.java @@ -8,6 +8,8 @@ import org.junit.Before; import org.junit.Test; +import com.zhaogd.collection.stack.Stack; + public class StackTest { private Stack stack; From aa80caaa218f80059e779750587ca88cb1d0bbff Mon Sep 17 00:00:00 2001 From: ZhaoHongxin <zhaohongxin621@126.com> Date: Thu, 6 Apr 2017 22:32:33 +0800 Subject: [PATCH 141/287] 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<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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<String> clzPaths = new ArrayList<String>(); - 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("<init>", 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<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 c7283681cfbd8267d1a5af01ff7fc78f5a9dcead Mon Sep 17 00:00:00 2001 From: ZhaoHongxin <zhaohongxin621@126.com> Date: Thu, 6 Apr 2017 22:42:34 +0800 Subject: [PATCH 142/287] 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 @@ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/> <classpathentry kind="lib" path="lib/dom4j-1.6.1.jar"/> + <classpathentry kind="lib" path="lib/commons-io-2.5.jar" sourcepath="D:/官网下载/commons-io-2.5-src.zip"/> + <classpathentry kind="lib" path="lib/commons-lang3-3.5.jar" sourcepath="D:/官网下载/commons-lang3-3.5-bin/commons-lang3-3.5/commons-lang3-3.5-sources.jar"/> <classpathentry kind="output" path="bin"/> </classpath> 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 0d5165470073e10e0f769cce62d3c10aa81e0c7d Mon Sep 17 00:00:00 2001 From: luoziyihao <wangyiraoxiang@163.com> Date: Thu, 6 Apr 2017 23:08:13 +0800 Subject: [PATCH 143/287] half getElements --- .../java/com/coding/basic/LinkedList.java | 50 ++++++++++++++++--- .../java/com/coding/basic/LinkedListTest.java | 10 +++- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/group17/1204187480/code/homework/basic/src/main/java/com/coding/basic/LinkedList.java b/group17/1204187480/code/homework/basic/src/main/java/com/coding/basic/LinkedList.java index 3c3462637e..1f19ad1fa5 100644 --- a/group17/1204187480/code/homework/basic/src/main/java/com/coding/basic/LinkedList.java +++ b/group17/1204187480/code/homework/basic/src/main/java/com/coding/basic/LinkedList.java @@ -185,16 +185,21 @@ public void removeFirstSize(int firstSize) { * @param length */ public void remove(int i, int length) { - if (i == 0 ) {removeFirstSize(length); return;} - if (i >= size || length == 0) {return;} + if (i == 0) { + removeFirstSize(length); + return; + } + if (i >= size || length == 0) { + return; + } int lastLenth = size - i; - length = length <= lastLenth? length : lastLenth; - Node pre = node(i-1); + length = length <= lastLenth ? length : lastLenth; + Node pre = node(i - 1); int j = 0; Node next = pre; - while (j++ < length){ + while (j++ < length) { next = next.next; } pre.next = next.next; @@ -213,9 +218,42 @@ public void remove(int i, int length) { * @param list */ public int[] getElements(LinkedList list) { - return null; + if (size() == 0) { + return new int[0]; + } + Iterator iterator = list.iterator(); + Node fromNode = iterator().nextNode(); + int fromIndex = 0; + + int[] retArray = new int[list.size()]; + int retIndex = 0; + while (iterator.hasNext()) { + int index = (int) iterator.next(); + Node node = node(fromNode, fromIndex, index); + if (node == null) { + return retArray; + } else { + retArray[retIndex++] = (int)node.data; + } + } + return retArray; } + private Node node(Node fromNode, int fromIndex, int index) { + Node next = fromNode; + int nextIndex = fromIndex; + while (next != null && nextIndex < index) { + next = next.next; + nextIndex++; + } + if (nextIndex == index) { + return next; + } else { + return null; + } + } + + /** * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 * 从当前链表中中删除在listB中出现的元素 diff --git a/group17/1204187480/code/homework/basic/src/test/java/com/coding/basic/LinkedListTest.java b/group17/1204187480/code/homework/basic/src/test/java/com/coding/basic/LinkedListTest.java index baca03b06b..0424c2945e 100644 --- a/group17/1204187480/code/homework/basic/src/test/java/com/coding/basic/LinkedListTest.java +++ b/group17/1204187480/code/homework/basic/src/test/java/com/coding/basic/LinkedListTest.java @@ -3,6 +3,8 @@ import org.junit.Assert; import org.junit.Test; +import java.util.Arrays; + /** * Created by luoziyihao on 3/23/17. */ @@ -83,9 +85,12 @@ private LinkedList createAndFillLinkedList() { } private LinkedList createAndFillLinkedList(int length) { + return createAndFillLinkedList(1, length); + } + private LinkedList createAndFillLinkedList(int start, int length) { LinkedList linkedList = new LinkedList(); - for (int i = 1; i <= length; i++) { + for (int i = start; i <= length; i++) { linkedList.add(i); } return linkedList; @@ -136,6 +141,9 @@ public void remove7() throws Exception { @Test public void getElements() throws Exception { + LinkedList listA= createAndFillLinkedList(0,8); + LinkedList listB = createAndFillLinkedList(4, 4); + Assert.assertEquals("[4,5,6,7]", Arrays.toString(listA.getElements(listB))); } From 93ddb61908bdb60c3ebe594bb9dff12cfcdccbee Mon Sep 17 00:00:00 2001 From: johnChnia <zhouqiang847@gmail.com> Date: Fri, 7 Apr 2017 01:52:00 +0800 Subject: [PATCH 144/287] =?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 145/287] =?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<String> clzPaths = new ArrayList<String>(); + + 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 146/287] =?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 @@ <classpathentry kind="lib" path="lib/junit.jar"/> <classpathentry kind="lib" path="lib/org.hamcrest.core_1.3.0.v201303031735.jar"/> <classpathentry kind="lib" path="lib/dom4j-1.6.1.jar"/> + <classpathentry kind="lib" path="lib/commons-lang3-3.2.jar"/> + <classpathentry kind="lib" path="lib/commons-io-1.4.jar"/> <classpathentry kind="output" path="bin"/> </classpath> 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<String> clzPaths = new ArrayList<String>(); - + 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<this.clzPaths.size();i++){ + buffer.append(this.clzPaths.get(i)); + if(i<this.clzPaths.size()-1){ + buffer.append(";"); } } - ByteArrayOutputStream bos = new ByteArrayOutputStream((int) file.length()); - BufferedInputStream in = null; + return buffer.toString(); + } + + private byte[] loadClassFile_V1(String clzFileName) { + + BufferedInputStream bis = 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); + + 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); } - return bos.toByteArray(); - } catch (IOException e) { + + byte [] codes = bos.toByteArray(); + + return codes; + + } 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(); + + } finally{ + if(bis != null){ + try { + bis.close(); + } catch (IOException e) { + 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; - } + -} +} \ 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 <zhouqiang847@gmail.com> Date: Fri, 7 Apr 2017 14:40:47 +0800 Subject: [PATCH 147/287] =?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 7820046369fbc86b8088fa0d198876507e65deb7 Mon Sep 17 00:00:00 2001 From: guoqixuan <1016908591@qq.com> Date: Fri, 7 Apr 2017 20:48:58 +0800 Subject: [PATCH 148/287] week04 --- .../jvm/loader/ClassFileLoader.java | 180 ++++++++++++++++++ .../jvm/test/ClassFileloaderTest.java | 100 ++++++++++ .../com/coderising/jvm/test/EmployeeV1.java | 28 +++ .../coding/basic/linklist/LRUPageFrame.java | 152 +++++++++++++++ .../basic/linklist/LRUPageFrameTest.java | 31 +++ 5 files changed, 491 insertions(+) create mode 100644 group27/1016908591/week04/src/com/coderising/jvm/loader/ClassFileLoader.java create mode 100644 group27/1016908591/week04/src/com/coderising/jvm/test/ClassFileloaderTest.java create mode 100644 group27/1016908591/week04/src/com/coderising/jvm/test/EmployeeV1.java create mode 100644 group27/1016908591/week04/src/com/coding/basic/linklist/LRUPageFrame.java create mode 100644 group27/1016908591/week04/src/com/coding/basic/linklist/LRUPageFrameTest.java diff --git a/group27/1016908591/week04/src/com/coderising/jvm/loader/ClassFileLoader.java b/group27/1016908591/week04/src/com/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..b1b316dbeb --- /dev/null +++ b/group27/1016908591/week04/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,180 @@ +package com.coderising.jvm.loader; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +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.util.ArrayList; +import java.util.List; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; + + + +public class ClassFileLoader { + + private List<String> clzPaths = new ArrayList<String>(); + /* + 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.size()) + { + clzP = clzPathName+";"; + } + clzP = clzPathName; + } + return clzP; + } + + public byte[] readBinaryCode(String className) throws IOException { + className = className.replace('.', File.separatorChar); + for(String path:this.clzPaths){ + String clz = path+File.separatorChar+className; + byte[] codes = loadClassFile_V2(clz); + if(codes!=null){ + return codes; + } + + } + + + + + return null; + } + + private byte[] loadClassFile_V2(String clz) throws IOException { + BufferedInputStream in = null; + + try { + File f = new File(clz); + + in = new BufferedInputStream(new FileInputStream(f)); + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024] ; + int length = -1; + while((length = in.read(buffer))!=-1) + { + bos.write(buffer,0,length); + + } + byte[] codes = bos.toByteArray(); + return codes; + + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + + + return null; + } + + /* + + } + + + + public void addClassPath(String path) { + if (this.clzPaths.contains(path)) { + return; + } + this.clzPaths.add(path); + + } + + + + public String getClassPath(){ + 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(); + } + public String getClassPathV1(){ + return StringUtils.join(this.clzPaths,";"); + } +*/ + + + + +} diff --git a/group27/1016908591/week04/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group27/1016908591/week04/src/com/coderising/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..5801c7ca04 --- /dev/null +++ b/group27/1016908591/week04/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,100 @@ +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 = "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() throws IOException { + + ClassFileLoader loader = new ClassFileLoader(); + 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(); + } + + // 注意:这个字节数可能和你的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); + byte[] codes = new byte[]{byteCodes[0],byteCodes[1],byteCodes[2],byteCodes[3]}; + + //这个函数是关于16进制字符串 + 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/group27/1016908591/week04/src/com/coderising/jvm/test/EmployeeV1.java b/group27/1016908591/week04/src/com/coderising/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..12e3d7efdd --- /dev/null +++ b/group27/1016908591/week04/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/group27/1016908591/week04/src/com/coding/basic/linklist/LRUPageFrame.java b/group27/1016908591/week04/src/com/coding/basic/linklist/LRUPageFrame.java new file mode 100644 index 0000000000..b7206255b2 --- /dev/null +++ b/group27/1016908591/week04/src/com/coding/basic/linklist/LRUPageFrame.java @@ -0,0 +1,152 @@ +package com.coding.basic.linklist; + +/** + * 用双向链表实现LRU算法 + * @author liuxin + * + */ +public class LRUPageFrame { + + private static class Node { + + Node prev; + Node next; + int pageNum; + + Node() { + } + } + + private int capacity; + + private int curreantSize; + private Node first;// 链表头 + private Node last;// 链表尾 + public LRUPageFrame(){ + this.first = null; + this.last = first; + } + + public LRUPageFrame(int capacity) { + + this.capacity = capacity; + + } + + /** + * 获取缓存中对象 + * + * @param key + * @return + */ + public void access(int pageNum) { + Node node = find(pageNum); + //在该队列中存在 + if(node!= null){ + moveExistingNodeToHead(node); + } + else{ + node = new Node(); + node.pageNum = pageNum; + + //缓存容器是否已经超过大小 + if(curreantSize>=capacity){ + removeLast(); + } + addNewNodeAtHead(node); + + } + + } + + + + private void moveExistingNodeToHead(Node node) { + if(first.pageNum == node.pageNum ){ + return; + }else if(last.pageNum == node.pageNum) { + Node lastToHead = last; + last = last.prev; + last.next = null; + lastToHead.prev = null; + lastToHead.next = first; + first.prev = lastToHead; + first = lastToHead; + + + + }else { + Node MiddleNode = first.next; + first.next = last; + last.prev = first; + MiddleNode.next = first; + MiddleNode.prev = null; + first.prev = MiddleNode; + first = MiddleNode; + + + } + + } + + private void addNewNodeAtHead(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; + + + } + curreantSize++; + + + } + + private boolean isEmpty() { + // TODO Auto-generated method stub + return (curreantSize==0); + } + + private void removeLast() { + Node prev = last.prev; + prev.next = null; + last.prev = null; + last = prev ; + this.curreantSize--; + + } + + private Node find(int pageNum) { + Node node = first; + while(node!=null){ + if(node.pageNum==pageNum){ + return node; + } + node = node.next; + + + } + 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/group27/1016908591/week04/src/com/coding/basic/linklist/LRUPageFrameTest.java b/group27/1016908591/week04/src/com/coding/basic/linklist/LRUPageFrameTest.java new file mode 100644 index 0000000000..67cf36067b --- /dev/null +++ b/group27/1016908591/week04/src/com/coding/basic/linklist/LRUPageFrameTest.java @@ -0,0 +1,31 @@ +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()); + } + +} 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 149/287] 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 150/287] =?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<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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<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/765324639/src/test/java/datastructure/stack/StackUtilTest.java b/group01/765324639/src/test/java/datastructure/stack/StackUtilTest.java new file mode 100644 index 0000000000..cf0abfe487 --- /dev/null +++ b/group01/765324639/src/test/java/datastructure/stack/StackUtilTest.java @@ -0,0 +1,58 @@ +package datastructure.stack; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class StackUtilTest { + + private Stack stack = new Stack(); + + @Before + public void setUp() { + for (int i = 0; i < 10; i++) { + stack.push(i); + } + } + + @Test + public void testReverse() { + StackUtil.reverse(stack); + Assert.assertEquals(10, stack.size()); + for (int i = 0; i < 10; i++) { + Assert.assertEquals(i, (int)stack.pop()); + } + } + + @Test + public void testRemove() { + StackUtil.remove(stack, 5); + Assert.assertEquals("0,1,2,3,4,6,7,8,9", stack.toString()); + + for (int i = 3; i < 5; i++) { + stack.push(i); + } + StackUtil.remove(stack, 3); + Assert.assertEquals("0,1,2,4,6,7,8,9,4", stack.toString()); + + } + + @Test + public void testGetTop() { + Object[] top = StackUtil.getTop(stack, 5); + Assert.assertEquals("0,1,2,3,4,5,6,7,8,9", stack.toString()); + Assert.assertEquals(5, top.length); + for (int i = 0; i < 5; i++) { + Assert.assertEquals(9 - i, top[i]); + } + } + + @Test + public void testIsValidPairs() { + Assert.assertTrue(StackUtil.isValidPairs("([e{d}f])")); + Assert.assertFalse(StackUtil.isValidPairs("([b{x]y})")); + Assert.assertTrue(StackUtil.isValidPairs("ab([e{d}f(ef)])ghj")); + } + +} diff --git a/group01/765324639/src/test/java/download/FileDownloaderTest.java b/group01/765324639/src/test/java/download/FileDownloaderTest.java index 885bf46a7c..e9ea374cb2 100644 --- a/group01/765324639/src/test/java/download/FileDownloaderTest.java +++ b/group01/765324639/src/test/java/download/FileDownloaderTest.java @@ -47,14 +47,14 @@ public void run() { // 等待多线程下载程序执行完毕 while (!downloadFinished) { try { - System.out.println("还没有下载完成,休眠五秒"); + System.out.println("Downloaded not complete, sleep 5 second"); // 休眠5秒 Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } - System.out.println("下载完成!"); + System.out.println("download complete!"); } diff --git a/group01/765324639/src/test/java/minijvm/loader/ClassFileloaderTest.java b/group01/765324639/src/test/java/minijvm/loader/ClassFileloaderTest.java index f0a3f220bd..bc93fc112a 100644 --- a/group01/765324639/src/test/java/minijvm/loader/ClassFileloaderTest.java +++ b/group01/765324639/src/test/java/minijvm/loader/ClassFileloaderTest.java @@ -7,15 +7,38 @@ import org.junit.Before; import org.junit.Test; +import minijvm.clz.ClassFile; +import minijvm.clz.ClassIndex; +import minijvm.constant.ClassInfo; +import minijvm.constant.ConstantPool; +import minijvm.constant.MethodRefInfo; +import minijvm.constant.NameAndTypeInfo; +import minijvm.constant.UTF8Info; -public class ClassFileloaderTest { +public class ClassFileloaderTest { + + private static final String FULL_QUALIFIED_CLASS_NAME = "minijvm/loader/EmployeeV1"; - static String path1 = new File(".", "target\\classes").getAbsolutePath(); + static String path1 = new File(".", "target\\test-classes").getAbsolutePath(); static String path2 = "C:\\temp"; static String className = EmployeeV1.class.getName(); + + static ClassFile clzFile = null; + static { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "minijvm.loader.EmployeeV1"; + + try { + clzFile = loader.loadClass(className); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + clzFile.print(); + } @Before public void setUp() throws Exception {} @@ -84,5 +107,93 @@ 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("<init>", 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 151/287] =?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 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>com.zavier</groupId> + <artifactId>765324639Learning</artifactId> + <version>0.0.1-SNAPSHOT</version> + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + </dependency> + <dependency> + <groupId>dom4j</groupId> + <artifactId>dom4j</artifactId> + <version>1.6.1</version> + </dependency> + </dependencies> +</project> \ 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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<struts> + <action name="login" class="litestruts.LoginAction"> + <result name="success">/jsp/homepage.jsp</result> + <result name="fail">/jsp/showLogin.jsp</result> + </action> + <action name="logout" class="litestruts.LogoutAction"> + <result name="success">/jsp/welcome.jsp</result> + <result name="error">/jsp/error.jsp</result> + </action> +</struts> \ 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 152/287] 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<Integer> stack) { + if (stack.isEmpty()) { + return; + } + int i = getAndRemoveLastElement(stack); + reverse(stack); + stack.push(i); + } + + public static int getAndRemoveLastElement(Stack<Integer> 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<Character> s2 = new Stack<Character>(); + 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<Character> 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<Integer> s; + @Before + public void setUp() throws Exception { + s = new Stack<Integer>(); + } + + @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<Integer>(); + 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 <wa122as@qq.com> Date: Sat, 8 Apr 2017 20:42:40 +0800 Subject: [PATCH 153/287] =?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<String> clzPaths = new ArrayList<String>(); + + 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<clzPaths.size();i++){ + if(i == (clzPaths.size() - 1)){ + strBuffer.append(clzPaths.get(i)); + }else{ + strBuffer.append(clzPaths.get(i)+";"); + } + } + return strBuffer.toString(); + } + +} diff --git a/group15/1521_653895972/src/task4/jvm/test/ClassFileloaderTest.java b/group15/1521_653895972/src/task4/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..863fb85228 --- /dev/null +++ b/group15/1521_653895972/src/task4/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,84 @@ +package task4.jvm.test; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import task4.jvm.loader.ClassFileLoader; + + +public class ClassFileloaderTest { + + + static String path1 = "D:\\GitHub\\coding2017\\group01\\1814014897\\zhouhui\\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 Exception { + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + + String className = "week04.jvm.test.EmployeeV1"; + + byte[] byteCodes = loader.readBinaryCode(className); + + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + Assert.assertEquals(1040, byteCodes.length); + + } + + + @Test + public void testMagicNumber() throws Exception{ + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "week04.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/group15/1521_653895972/src/task4/jvm/test/EmployeeV1.java b/group15/1521_653895972/src/task4/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..3e11fe6ccb --- /dev/null +++ b/group15/1521_653895972/src/task4/jvm/test/EmployeeV1.java @@ -0,0 +1,28 @@ +package week04.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/task4/linklist/LRUPageFrame.java b/group15/1521_653895972/src/task4/linklist/LRUPageFrame.java new file mode 100644 index 0000000000..6c2a61eaca --- /dev/null +++ b/group15/1521_653895972/src/task4/linklist/LRUPageFrame.java @@ -0,0 +1,157 @@ +package task4.linklist; + + +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 key + * @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/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<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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<String> clzPaths = new ArrayList<String>(); + + 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/1521_653895972/src/task5/jvm/loader/ClassFileParser.java b/group15/1521_653895972/src/task5/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..95255100e9 --- /dev/null +++ b/group15/1521_653895972/src/task5/jvm/loader/ClassFileParser.java @@ -0,0 +1,38 @@ +package task5.jvm.loader; + +import task5.jvm.clz.AccessFlag; +import task5.jvm.clz.ClassFile; +import task5.jvm.clz.ClassIndex; +import task5.jvm.constant.ConstantPool; + +import java.io.UnsupportedEncodingException; + + +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/group15/1521_653895972/src/task5/jvm/test/ClassFileloaderTest.java b/group15/1521_653895972/src/task5/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..3a74f57474 --- /dev/null +++ b/group15/1521_653895972/src/task5/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,194 @@ +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 = "com/coderising/jvm/test/EmployeeV1"; + + static String path1 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\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 { + } + + @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(); + } + + /** + * ---------------------------------------------------------------------- + */ + + + @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("<init>", 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<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 c0ff00780cad4839c1ec59e7bf7c8d609c3d89ee Mon Sep 17 00:00:00 2001 From: x_zhaohu <x_zhaohu@163.com> Date: Sat, 8 Apr 2017 21:00:57 +0800 Subject: [PATCH 154/287] =?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_ifAF<D95A7<1hD~F7hqsc2?I!(U>D%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<jtIJe`b10jE!#htqC*^ z126ysFaQHE00S@p1N~?q4l;DcjSn=NA8+oNuD$sc8w|hz48Q;kzyJ)u01UtY48Q;k zz`z$YU{#2ohKOpzTs*)3Z~gy&_(62f+%nh91#`~0%m(v|S!br1L57$Y&bVW4n19S) z=88FBd`AC<%V5C(48Q;kzyJ)u01UtY48Q;kd~XAPD9fL0yyrwl)Cg4A9^4ko!qEfV zCCUbka?P<tQg<pMQt@Wz!Jj;lo*tbQCzJ+;DsF_n=!$Gd=|`&XliC6QE7F(G6tvZG zu17tcf$z%c%1Nu?iTlKg6?Yha)X$r{-RVtjww{F-Z~9<Kfn~c^RSCQ98R_V}v7dMb IkIt9q6}?5w^8f$< literal 0 HcmV?d00001 diff --git a/group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/AccessFlag.java b/group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..e74740aa3e --- /dev/null +++ b/group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/AccessFlag.java @@ -0,0 +1,25 @@ +package com.sprint.jvm.clz; + +public class AccessFlag { + private int flagValue; + + public AccessFlag(int value) { + this.flagValue = value; + } + + public int getFlagValue() { + return flagValue; + } + + public void setFlagValue(int flagValue) { + this.flagValue = flagValue; + } + + public boolean isPublicClass() { + return (this.flagValue & 0x0001) != 0; + } + + public boolean isFinalClass() { + return (this.flagValue & 0x0010) != 0; + } +} diff --git a/group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/ClassFile.java b/group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..637cd63592 --- /dev/null +++ b/group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/ClassFile.java @@ -0,0 +1,71 @@ +package com.sprint.jvm.clz; + +import com.sprint.jvm.constant.ConstantPool; +import com.sprint.jvm.constant.ClassInfo; +public class ClassFile { + private int minorVersion; + private int majorVersion; + + private AccessFlag accessFlag; + private ClassIndex clzIndex; + private ConstantPool 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 AccessFlag getAccessFlag() { + return accessFlag; + } + + public void setAccessFlag(AccessFlag accessFlag) { + this.accessFlag = accessFlag; + } + + public ClassIndex getClzIndex() { + return clzIndex; + } + + public void setClzIndex(ClassIndex clzIndex) { + this.clzIndex = clzIndex; + } + + public ConstantPool getConstantPool() { + return 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("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/group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/ClassIndex.java b/group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..46e7443d90 --- /dev/null +++ b/group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/ClassIndex.java @@ -0,0 +1,22 @@ +package com.sprint.jvm.clz; + +public class ClassIndex { + private int thisClassIndex; + private int superClassIndex; + + public int getThisClassIndex() { + return thisClassIndex; + } + + public void setThisClassIndex(int index) { + this.thisClassIndex = index; + } + + public int getSuperClassIndex() { + return superClassIndex; + } + + public void setSuperClassIndex(int index) { + this.superClassIndex = index; + } +} diff --git a/group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/ClassInfo.java b/group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..b8da3c656d --- /dev/null +++ b/group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/ClassInfo.java @@ -0,0 +1,28 @@ +package com.sprint.jvm.constant; + +public class ClassInfo extends ConstantInfo { + private int type = ConstantInfo.CLASS_INFO; + private int utf8Index; + + public ClassInfo(ConstantPool pool) { + super(pool); + } + + public void setUtf8Index(int index) { + this.utf8Index = index; + } + + public int getUtf8Index() { + return utf8Index; + } + + public int getType() { + return type; + } + + public String getClassName() { + int index = getUtf8Index(); + UTF8Info utf8Info = (UTF8Info)constantPool.getConstantInfo(index); + return utf8Info.getValue(); + } +} diff --git a/group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/ConstantInfo.java b/group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..a8db82689e --- /dev/null +++ b/group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/ConstantInfo.java @@ -0,0 +1,29 @@ +package com.sprint.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/group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/ConstantPool.java b/group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..3a35c22ce0 --- /dev/null +++ b/group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/ConstantPool.java @@ -0,0 +1,28 @@ +package com.sprint.jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + private List<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + 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<String> clzPaths = new ArrayList<String>(); + 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 <x_zhaohu@163.com> Date: Sat, 8 Apr 2017 21:01:44 +0800 Subject: [PATCH 155/287] 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_ifAF<D95A7<1hD~F7hqsc2?I!(U>D%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<jtIJe`b10jE!#htqC*^ z126ysFaQHE00S@p1N~?q4l;DcjSn=NA8+oNuD$sc8w|hz48Q;kzyJ)u01UtY48Q;k zz`z$YU{#2ohKOpzTs*)3Z~gy&_(62f+%nh91#`~0%m(v|S!br1L57$Y&bVW4n19S) z=88FBd`AC<%V5C(48Q;kzyJ)u01UtY48Q;kd~XAPD9fL0yyrwl)Cg4A9^4ko!qEfV zCCUbka?P<tQg<pMQt@Wz!Jj;lo*tbQCzJ+;DsF_n=!$Gd=|`&XliC6QE7F(G6tvZG zu17tcf$z%c%1Nu?iTlKg6?Yha)X$r{-RVtjww{F-Z~9<Kfn~c^RSCQ98R_V}v7dMb IkIt9q6}?5w^8f$< From 1e76584b0dcbbfd0a33b7224391422303b6f549d Mon Sep 17 00:00:00 2001 From: johnChnia <zhouqiang847@gmail.com> Date: Sat, 8 Apr 2017 22:02:30 +0800 Subject: [PATCH 156/287] =?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 <zhouqiang847@gmail.com> Date: Sat, 8 Apr 2017 22:08:52 +0800 Subject: [PATCH 157/287] =?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 4e61cbad10625eb1f4675edeb8b9ad66e69665de Mon Sep 17 00:00:00 2001 From: OnlyLYJ <382266293@qq.com> Date: Sat, 8 Apr 2017 22:55:31 +0800 Subject: [PATCH 158/287] 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<Integer> myList = new ArrayList<Integer>(); - 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<Integer> 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<Integer> t = new TreeSet<Integer>(); 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<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + 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<String> clzPaths = new ArrayList<String>(); @@ -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("<init>", 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<String,ActionCfg> actions = new HashMap<>(); + Map<String, ActionCfg> 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<String,String> viewResult = new HashMap<>(); + Map<String, String> viewResult = new HashMap<>(); public Map<String, String> 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<String,String> 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<String,String> readParamters = getReadParameters(actionObj, pd); - + + @SuppressWarnings("unchecked") + public static View runAction(String actionName, Map<String, String> 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<String, String> 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<String,String> viewParams = new HashMap<String,String>(); + Map<String, String> viewParams = new HashMap<String, String>(); - 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<String,String> params = new HashMap<String,String>(); - 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<String, String> params = new HashMap<String, String>(); + 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<String,String> params = new HashMap<String,String>(); - 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<String, String> params = new HashMap<String, String>(); + 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 159/287] =?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<String> clzPaths = new ArrayList<String>(); + + 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 <wa122as@qq.com> Date: Sun, 9 Apr 2017 11:34:25 +0800 Subject: [PATCH 160/287] =?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<String> clzPaths = new ArrayList<String>(); 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<clzPaths.size();i++){ - if(i == (clzPaths.size() - 1)){ - strBuffer.append(clzPaths.get(i)); - }else{ - strBuffer.append(clzPaths.get(i)+";"); - } - } - return strBuffer.toString(); + return StringUtils.join(clzPaths,";"); } } diff --git a/group15/1521_653895972/src/task4/jvm/test/ClassFileloaderTest.java b/group15/1521_653895972/src/task4/jvm/test/ClassFileloaderTest.java index 863fb85228..5b037ffe5d 100644 --- a/group15/1521_653895972/src/task4/jvm/test/ClassFileloaderTest.java +++ b/group15/1521_653895972/src/task4/jvm/test/ClassFileloaderTest.java @@ -10,7 +10,7 @@ public class ClassFileloaderTest { - static String path1 = "D:\\GitHub\\coding2017\\group01\\1814014897\\zhouhui\\bin"; + static String path1 = "D:\\oneces\\GitHub\\coding2017\\group15\\1521_653895972\\out\\production\\1521_653895972"; static String path2 = "C:\temp"; @@ -31,7 +31,6 @@ public void testClassPath(){ loader.addClassPath(path2); String clzPath = loader.getClassPath(); - Assert.assertEquals(path1+";"+path2,clzPath); } @@ -42,12 +41,12 @@ public void testClassFileLength() throws Exception { ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); - String className = "week04.jvm.test.EmployeeV1"; + String className = "task4.jvm.test.EmployeeV1"; byte[] byteCodes = loader.readBinaryCode(className); // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 - Assert.assertEquals(1040, byteCodes.length); + Assert.assertEquals(1038, byteCodes.length); } @@ -56,7 +55,7 @@ public void testClassFileLength() throws Exception { public void testMagicNumber() throws Exception{ ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); - String className = "week04.jvm.test.EmployeeV1"; + String className = "task4.jvm.test.EmployeeV1"; byte[] byteCodes = loader.readBinaryCode(className); byte[] codes = new byte[]{byteCodes[0],byteCodes[1],byteCodes[2],byteCodes[3]}; diff --git a/group15/1521_653895972/src/task4/jvm/test/EmployeeV1.java b/group15/1521_653895972/src/task4/jvm/test/EmployeeV1.java index 3e11fe6ccb..e8e8cd385a 100644 --- a/group15/1521_653895972/src/task4/jvm/test/EmployeeV1.java +++ b/group15/1521_653895972/src/task4/jvm/test/EmployeeV1.java @@ -1,4 +1,4 @@ -package week04.jvm.test; +package task4.jvm.test; public class EmployeeV1 { diff --git a/group15/1521_653895972/src/task4/linklist/LRUPageFrame.java b/group15/1521_653895972/src/task4/linklist/LRUPageFrame.java index 6c2a61eaca..daf58b1d74 100644 --- a/group15/1521_653895972/src/task4/linklist/LRUPageFrame.java +++ b/group15/1521_653895972/src/task4/linklist/LRUPageFrame.java @@ -29,7 +29,7 @@ public LRUPageFrame(int capacity) { /** * 获取缓存中对象 * - * @param key + * @param pageNum * @return */ public void access(int pageNum) { diff --git a/group15/1521_653895972/src/task5/jvm/test/ClassFileloaderTest.java b/group15/1521_653895972/src/task5/jvm/test/ClassFileloaderTest.java index 3a74f57474..3c6fa84151 100644 --- a/group15/1521_653895972/src/task5/jvm/test/ClassFileloaderTest.java +++ b/group15/1521_653895972/src/task5/jvm/test/ClassFileloaderTest.java @@ -13,16 +13,16 @@ public class ClassFileloaderTest { - private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + private static final String FULL_QUALIFIED_CLASS_NAME = "task5.jvm.test.EmployeeV1"; - static String path1 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\mini-jvm\\bin"; + static String path1 = "D:\\oneces\\GitHub\\coding2017\\group15\\1521_653895972\\out\\production\\1521_653895972"; static String path2 = "C:\temp"; static ClassFile clzFile = null; static { ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); - String className = "com.coderising.jvm.test.EmployeeV1"; + String className = "task5.jvm.test.EmployeeV1"; clzFile = loader.loadClass(className); clzFile.print(); @@ -56,7 +56,7 @@ public void testClassFileLength() { ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); - String className = "com.coderising.jvm.test.EmployeeV1"; + String className = "task5.jvm.test.EmployeeV1"; byte[] byteCodes = loader.readBinaryCode(className); @@ -70,7 +70,7 @@ public void testClassFileLength() { public void testMagicNumber(){ ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); - String className = "com.coderising.jvm.test.EmployeeV1"; + String className = "task5.jvm.test.EmployeeV1"; byte[] byteCodes = loader.readBinaryCode(className); byte[] codes = new byte[]{byteCodes[0],byteCodes[1],byteCodes[2],byteCodes[3]}; diff --git "a/\357\274\201" "b/\357\274\201" deleted file mode 100644 index 8e1902e358..0000000000 --- "a/\357\274\201" +++ /dev/null @@ -1,8 +0,0 @@ -Merge branch 'master' of https://github.com/jodie-zss/coding2017 into jodie-zss/master -update orgin - -# Please enter a commit message to explain why this merge is necessary, -# especially if it merges an updated upstream into a topic branch. -# -# Lines starting with '#' will be ignored, and an empty message aborts -# the commit. From 1696720b73d2d2da016d4b4d56aebb8c6cf8ff37 Mon Sep 17 00:00:00 2001 From: luoziyihao <wangyiraoxiang@163.com> Date: Sun, 9 Apr 2017 11:37:49 +0800 Subject: [PATCH 161/287] home --- .../basic/src/main/java/com/coding/basic/LinkedList.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/group17/1204187480/code/homework/basic/src/main/java/com/coding/basic/LinkedList.java b/group17/1204187480/code/homework/basic/src/main/java/com/coding/basic/LinkedList.java index 1f19ad1fa5..c0cce5af0a 100644 --- a/group17/1204187480/code/homework/basic/src/main/java/com/coding/basic/LinkedList.java +++ b/group17/1204187480/code/homework/basic/src/main/java/com/coding/basic/LinkedList.java @@ -230,6 +230,8 @@ public int[] getElements(LinkedList list) { while (iterator.hasNext()) { int index = (int) iterator.next(); Node node = node(fromNode, fromIndex, index); + fromIndex = index; + fromNode = node; if (node == null) { return retArray; } else { From 3fc2d0695afad9f8497621f8b95c5cdb26dc7f2c Mon Sep 17 00:00:00 2001 From: guoqixuan <1016908591@qq.com> Date: Sun, 9 Apr 2017 13:46:32 +0800 Subject: [PATCH 162/287] 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<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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<String> clzPaths = new ArrayList<String>(); + + 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.size()) + { + clzP = clzPathName+";"; + } + clzP = clzPathName; + } + return clzP; + } + + public byte[] readBinaryCode(String className) throws IOException { + className = className.replace('.', File.separatorChar); + for(String path:this.clzPaths){ + String clz = path+File.separatorChar+className; + byte[] codes = loadClassFile_V2(clz); + if(codes!=null){ + return codes; + } + + } + + + + + return null; + } + + + + private byte[] loadClassFile_V2(String clz) throws IOException { + BufferedInputStream in = null; + + try { + File f = new File(clz); + + in = new BufferedInputStream(new FileInputStream(f)); + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024] ; + int length = -1; + while((length = in.read(buffer))!=-1) + { + bos.write(buffer,0,length); + + } + byte[] codes = bos.toByteArray(); + return codes; + + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + + + return null; + } + + + /* + + } + + + + public void addClassPath(String path) { + if (this.clzPaths.contains(path)) { + return; + } + this.clzPaths.add(path); + + } + + + + public String getClassPath(){ + 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(); + } + 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); + + }*/ private List<String> clzPaths = new ArrayList<String>(); /* @@ -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<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()); + + } - 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); + @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()); } - return buffer.toString(); - } + { + 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("<init>", 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<len;count++){ + arr[count] = s.peek(); + newStack.push(s.pop()); + + } + while(newStack.isEmpty()){ + s.push(newStack.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){ + Stack newstack = new Stack(); + String str = "{[("; + String shr; + int len = 0; + for(int count = 0;count<s.length();count++){ + if(str.contains(s.substring(count, count++)) ){ + newstack.push(s.substring(count, count++)); + len++; + } + if(len/2!=0){ + return false; + } + + } + + + + + + + } + + } + + + From 642545a70070966b9d5699facdf1d638bfd1e528 Mon Sep 17 00:00:00 2001 From: RalfNick <wang_lxin@163.com> Date: Sun, 9 Apr 2017 13:47:21 +0800 Subject: [PATCH 163/287] 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<String, String> hashMap; + + public ReadXml(String filename) { + try { + document = new SAXReader().read((filename)); + hashMap = new HashMap<String, String>(); + } 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<String, String> hashMap = new HashMap<String, String>(); + 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<String, String> hashMap = new HashMap<String, String>(); + 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<String, String> 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);//ִsetterexcute + + 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<String, String> 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<String, String> setMapParameter() { + + Method[] getterMethods = actionClass.getMethods(); + HashMap<String, String> 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<String,String> params = new HashMap<String,String>(); + 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<String,String> params = new HashMap<String,String>(); + 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<String,String> params = new HashMap<String,String>(); + 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<Integer> list = new MyLinkedList<>(); + + MyLinkedList<Integer> listB = new MyLinkedList<>(); + MyLinkedList<Integer> 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<Integer>) list.intersection(listB); + + + System.out.println(listC.size()); + + MyIterator<Integer> 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<T extends Comparable<T>> implements MyList<T> { + + private Node<T> head;// ָͷʼΪ + // private Node<T> tail;// ָβĽڵ + private int size; + + public MyLinkedList() { + this.head = new Node<T>(null); + this.size = 0; + } + + private static class Node<T> { + Node<T> 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<T> newNode = new Node<T>(t); + if (index == 0) { + Node<T> oldNode = head.next; + head.next = newNode; + newNode.next = oldNode; + size++; + } + + else { + Node<T> 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<T> 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<T> 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<T> 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<T> getNode(int index) { + + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException(); + } + Node<T> 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<T> current = new Node<T>(t); + head.next = current; + current = null; + size++; + return true; + } else { + Node<T> current = new Node<T>(t); + current.next = head.next; + head.next = current; + size++; + return true; + } + } + + public boolean addLast(T t) { + + if (head.next == null) { + Node<T> current = new Node<T>(t); + head.next = current; + current.next = null; + size++; + return true; + } else { + Node<T> current = new Node<T>(t); + Node<T> 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<T> 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<T> 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<T> 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<T> reverseList(Node<T> mhead) { + + if (mhead == null || mhead.next == null) { + return mhead; + } + Node<T> 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<T> current = getNode(index - 1); + Node<T> 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<T> current = head; + while (index < maxIndex) { + current = current.next; + current.item = null; + index++; + size--; + } + //size = (size - 1) / 2 + 1; + head.next = current.next; + } + + /** + * ӵiԪؿʼ ɾlength Ԫ עi0ʼ + * + * @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<T> current; + if (i == 0) { + current = head; + } else { + current = getNode(i - 1); + } + Node<T> 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<T> list) { + int[] elements = new int[list.size]; + int i = 0; + MyIterator<Integer> iterator = (MyIterator<Integer>) list.iterator(); + while (iterator.hasNext()) { + int index = iterator.Next(); + if (index < this.size) { + Node<T> 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<T> list) { + + if (list.size == 0) { + return; + } + MyIterator<T> 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<T> list = new MyArrayList<>(); + // + Node<T> 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<T> 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<T> 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<T> intersection(MyLinkedList<T> list) { + + if (list.size == 0 || head.next == null) { + return null; + } + MyLinkedList<T> newLinked = new MyLinkedList<T>(); + MyIterator<T> iterator = list.iterator(); + //MyArrayList<T> arrayList = new MyArrayList<>();//û + //ArrayList<T> arrayList = new ArrayList<>(); + TreeSet<T> 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<T> union(MyLinkedList<T> list) { + + if (head.next == null) { + + if (list.size == 0) { + return null; + } else { + return list; + } + } else { + if (list.size == 0) { + return this; + } else { + + MyLinkedList<T> newList = new MyLinkedList<T>(); + TreeSet<T> treeSet = new TreeSet<>();// MyArrayListװвͬԪأӵlinkedlist + + Node<T> current = head; + while (current.next != null) { + current = current.next; + treeSet.add(current.item); + } + MyIterator<T> iterator = (MyIterator<T>) list.iterator(); + while (iterator.hasNext()) { + treeSet.add(iterator.Next()); + } + for (T t : treeSet) { + newList.add(t); + } + return newList; + } + } + + } + + */ + public MyIterator<T> iterator() { + + return new LinkedListIterator(); + } + + private class LinkedListIterator implements MyIterator<T> { + + 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<T> { + + private LinkedList<T> linkedList; + + public MyStack() { + if (null == linkedList) { + linkedList = new LinkedList<T>(); + } + } + + 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 <T> + */ + public static <T> void reverse(MyStack<T> 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 <T> void remove(MyStack<T> s, T o) { + if (s.isEmpty()) { + System.out.println("ջΪգ"); + return; + } + MyStack<T> 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 <T> void PopAndPush(MyStack<T> s, MyStack<T> 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> T[] getTop(MyStack<T> s, int len) { + + if (s.isEmpty() || len > s.size()) { + return null; + } + MyStack<T> 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еDzdzɶԳֵġ s = + * "([e{d}f])" , ַеdzɶԳ֣ ÷true s = "([b{x]y})", + * ַеŲdzɶԳֵģ ÷false; + * + * @param s + * @return + */ + public static <T> boolean isValidPairs(String s) { + + char[] ch = s.toCharArray(); + if (ch.length < 1) { + return false; + } + + MyStack<String> leftStack = new MyStack<>(); + MyStack<String> 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<String> leftStack, + MyStack<String> 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<Integer> 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<Integer> 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<Integer> 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<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + 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<String> list = new ArrayList<String>(); + + 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 testConstantool(){ + + 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("<init>", 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 e1cec01e63221fb899e890e0febd2154d1edab53 Mon Sep 17 00:00:00 2001 From: luoziyihao <wangyiraoxiang@163.com> Date: Sun, 9 Apr 2017 15:31:19 +0800 Subject: [PATCH 164/287] add 20170326-20170402.md 20170402-20170409.md --- group17/article/20170402-20170409.md | 56 ++++++++++++++++++++++++++++ group17/count/homework.md | 4 +- 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 group17/article/20170402-20170409.md diff --git a/group17/article/20170402-20170409.md b/group17/article/20170402-20170409.md new file mode 100644 index 0000000000..3d45ad0516 --- /dev/null +++ b/group17/article/20170402-20170409.md @@ -0,0 +1,56 @@ +# 自由写作 + +## 须知 +--- + +交作业时请在QQ 号后面填上各自的文章链接, 比如: + +51075907 http://m.blog.csdn.net/article/details?id=57083764 + +## 文章 +--- + +1204187480 + +102228177 + +876385982 + +785396327 + +1059107701 + +240094626 + +82427129 + +296910598 + +1264835468 + +516886559 + +1282579502 + +614982500 + +865797761 + +1540186032 + +176653813 + +116665530 + +51075907 + +1158154002 + +345450234 + +919764878 + +1368331120 + +517970312 + diff --git a/group17/count/homework.md b/group17/count/homework.md index a0abf5cadd..640cf4698f 100644 --- a/group17/count/homework.md +++ b/group17/count/homework.md @@ -17,5 +17,7 @@ * [20170305-20170312](https://github.com/luoziyihao/coding2017/blob/master/group17/article/20170305-20170312.md) - * [20170305-20170312](https://github.com/luoziyihao/coding2017/blob/master/group17/article/20170326-20170402.md) + * [20170326-20170402](https://github.com/luoziyihao/coding2017/blob/master/group17/article/20170326-20170402.md) + * [20170402-20170409](https://github.com/luoziyihao/coding2017/blob/master/group17/article/20170402-20170409.md) +20170326-20170402.md 20170402-20170409.md 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 165/287] =?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<ConstantInfo> 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<String> clzPaths = new ArrayList<String>(); + + 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("<init>", 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<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/group15/1507_977996067/src/task5/stack/Stack.java b/group15/1507_977996067/src/task5/stack/Stack.java new file mode 100644 index 0000000000..510b729922 --- /dev/null +++ b/group15/1507_977996067/src/task5/stack/Stack.java @@ -0,0 +1,31 @@ +package task5.stack; + +import task1.MyLinkedList; + +/** + * Stack 实现 + */ +public class Stack<T> { + private MyLinkedList<T> elementData = new MyLinkedList<T>(); + + 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" <songbao.yang@qunarservers.com> Date: Sun, 9 Apr 2017 16:51:10 +0800 Subject: [PATCH 166/287] =?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 @@ -<?xml version="1.0" encoding="UTF-8"?> -<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4"> - <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_5" inherit-compiler-output="false"> - <output url="file://$MODULE_DIR$/target/classes" /> - <output-test url="file://$MODULE_DIR$/target/test-classes" /> - <content url="file://$MODULE_DIR$"> - <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" /> - <excludeFolder url="file://$MODULE_DIR$/target" /> - </content> - <orderEntry type="inheritedJdk" /> - <orderEntry type="sourceFolder" forTests="false" /> - <orderEntry type="library" name="Maven: junit:junit:4.12" level="project" /> - <orderEntry type="library" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" /> - </component> -</module> \ 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 @@ <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> - <name>basic</name> <url>http://maven.apache.org</url> <properties> 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<String, String> 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<String, String> 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<String,String> 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<String, Object> hashMap = new HashMap<String, Object>(); - 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中的 <result> 配置,以及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<String, String> resultMap = new HashMap<String, String>(); - 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<String,String> 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<String, Object> hashMap = new HashMap<String, Object>(); + 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中的 <result> 配置,以及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<String, String> resultMap = new HashMap<String, String>(); + 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<T> implements List<T> { + + 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<T extends Comparable> implements List<T> { + + 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 extends Comparable>{ + 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<T> listC = new LinkedList<T>(); + + 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<T> newNode = new Node<T>(); + 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<T> { + 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<String> clzPaths = new ArrayList<String>(); + + 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<Byte> bytes = new ArrayList<Byte>(); + 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 @@ <?xml version="1.0" encoding="UTF-8"?> <struts> - <action name="login" class="com.coderising.litestruts.LoginAction"> + <action name="login" class="dataStruct.com.coderising.litestruts.LoginAction"> <result name="success">/jsp/homepage.jsp</result> <result name="fail">/jsp/showLogin.jsp</result> </action> 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<String,String> params = new HashMap<String,String>(); - 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<String,String> params = new HashMap<String,String>(); - 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<String,String> params = new HashMap<String,String>(); + 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<String,String> params = new HashMap<String,String>(); + 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<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 3c62f4be301a7e5043da8e917161c4d507957e5d Mon Sep 17 00:00:00 2001 From: Haochen <haochen_233333@163.com> Date: Sun, 9 Apr 2017 17:11:23 +0800 Subject: [PATCH 167/287] 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<Integer, Integer> constantIndexMap = new HashMap<>(); + int accessFlags; + int thisClass; + int superClass; + int interfacesCount; + Map<Integer, Integer> interfaceIndexMap = new HashMap<>(); + int fieldsCount; + Map<Integer, Integer> fieldIndexMap = new HashMap<>(); + int methodsCount; + Map<Integer, Integer> methodIndexMap = new HashMap<>(); + int attributesCount; + Map<Integer, Integer> 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<Integer, ConstantParser> 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<Integer, Constant> 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 <Patrick@DESKTOP-JLNF6GI> Date: Sun, 9 Apr 2017 18:47:56 +0800 Subject: [PATCH 168/287] =?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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> + <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/> + <classpathentry kind="lib" path="E:/javaImprove/git/group24/121111914/lib/dom4j-1.6.1.jar" sourcepath="E:/javaImprove/git/group24/121111914/lib/dom4j-1.6.1-sources.jar"/> + <classpathentry kind="lib" path="lib/commons-io-2.5.jar"/> + <classpathentry kind="lib" path="lib/commons-lang3-3.5.jar"/> + <classpathentry kind="output" path="bin"/> +</classpath> 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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>JavaImp2017</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> 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;i<size;i++){ + buffer.append(elementData.get(i)+","); + } + return buffer.toString(); + } +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/basic/stack/StackUtil.java b/group24/121111914/src/com/github/ipk2015/coding2017/basic/stack/StackUtil.java new file mode 100644 index 0000000000..f9401d81b2 --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/basic/stack/StackUtil.java @@ -0,0 +1,133 @@ +package com.github.ipk2015.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 tempStack=new Stack(); + int size=s.size(); + if(size<2){ + return; + } + for(int i=0;i<size;i++){ + tempStack.push(s.pop()); + } + Stack tempStack1=new Stack(); + for(int i=0;i<size;i++){ + tempStack1.push(tempStack.pop()); + } + for(int i=0;i<size;i++){ + s.push(tempStack1.pop()); + } + } + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s,Object o) { + Stack tempStack=new Stack(); + Object tempElement; + while(!s.isEmpty()){ + tempElement=s.pop(); + if(tempElement.equals(o)){ + break; + } + tempStack.push(tempElement); + } + while(!tempStack.isEmpty()){ + s.push(tempStack.pop()); + } + + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * @param len + * @return + */ + public static Object[] getTop(Stack s,int len) { + if(len>s.size()){ + throw new RuntimeException("len超出范围"); + } + Stack tempStack=new Stack(); + for(int i=0;i<len;i++){ + tempStack.push(s.pop()); + } + Object[] array=new Object[len]; + Object tempObject; + for(int i=0;i<len;i++){ + tempObject=tempStack.pop(); + array[i]=tempObject; + s.push(tempObject); + } + return array; + } + /** + * 字符串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[] charArray = s.toCharArray(); + Stack stack=new Stack(); + int flag; + for(int i=0;i<charArray.length;i++){ + flag=switchChar(charArray[i]); + if(flag>0){ + 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<array.length;i++){ + buffer.append(array[i]+","); + } + assertEquals("2,3,4,", buffer.toString()); + } + + @Test + public void testIsValidPairs() { + String s="([a{b}c])"; + boolean result=StackUtil.isValidPairs(s); + assertEquals(true, result); + s="[a]{[(b)]}{(c)}"; + result=StackUtil.isValidPairs(s); + assertEquals(true, result); + s="([a{b]c})"; + result=StackUtil.isValidPairs(s); + assertEquals(false, result); + s="{[{a}]b]"; + result=StackUtil.isValidPairs(s); + assertEquals(false, result); + s="{(a)}b(][)"; + result=StackUtil.isValidPairs(s); + assertEquals(false, result); + } +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/clz/AccessFlag.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/clz/AccessFlag.java new file mode 100644 index 0000000000..138f12d2c7 --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/clz/AccessFlag.java @@ -0,0 +1,37 @@ +package com.github.ipk2015.coding2017.minijvm.clz; + + + +public class AccessFlag { + public static int ACC_PUBLIC = 0x0001; + public static int ACC_FINAL = 0x0002; + public static int ACC_SUPER = 0x0020; + public static int ACC_INTEERFACE = 0x0200; + public static int ACC_ABSTRACT = 0x0400; + public static int ACC_SYNTHETIC = 0x1000; + public static int ACC_ANNOTATION = 0x2000; + public static int ACC_ENUM = 0x4000; + + 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 & ACC_PUBLIC) != 0; + } + + public boolean isFinalClass(){ + return (this.flagValue & ACC_FINAL) != 0; + } + +} \ No newline at end of file diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/clz/ClassFile.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/clz/ClassFile.java new file mode 100644 index 0000000000..4b64635076 --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/clz/ClassFile.java @@ -0,0 +1,75 @@ +package com.github.ipk2015.coding2017.minijvm.clz; + +import com.github.ipk2015.coding2017.minijvm.constant.ClassInfo; +import com.github.ipk2015.coding2017.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/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/clz/ClassIndex.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/clz/ClassIndex.java new file mode 100644 index 0000000000..834863c9ee --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/clz/ClassIndex.java @@ -0,0 +1,21 @@ +package com.github.ipk2015.coding2017.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/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/ClassInfo.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/ClassInfo.java new file mode 100644 index 0000000000..e2e0f50f61 --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/ClassInfo.java @@ -0,0 +1,26 @@ +package com.github.ipk2015.coding2017.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; + } + public int getType() { + return type; + } + + public String getClassName() { + int index = getUtf8Index(); + UTF8Info utf8Info = (UTF8Info)constantPool.getConstantInfo(index); + return utf8Info.getValue(); + } +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/ConstantInfo.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..663c493b57 --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/ConstantInfo.java @@ -0,0 +1,29 @@ +package com.github.ipk2015.coding2017.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/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/ConstantPool.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/ConstantPool.java new file mode 100644 index 0000000000..ea0e135a23 --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/constant/ConstantPool.java @@ -0,0 +1,29 @@ +package com.github.ipk2015.coding2017.minijvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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<String> clzPaths = new ArrayList<String>(); - 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<this.clzPaths.size();i++){ + buffer.append(this.clzPaths.get(i)); + if(i<this.clzPaths.size()-1){ + buffer.append(";"); + } } - int pointPos=name.lastIndexOf(".", name.length()-7); - if(pointPos>-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<String> clzPaths = new ArrayList<String>(); + + 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<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; + + } + + + +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ClassFileParser.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..bdbbb66271 --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ClassFileParser.java @@ -0,0 +1,149 @@ +package com.github.ipk2015.coding2017.minijvm.loader; + + + +import java.io.UnsupportedEncodingException; +import java.util.Arrays; + +import com.github.ipk2015.coding2017.minijvm.clz.AccessFlag; +import com.github.ipk2015.coding2017.minijvm.clz.ClassFile; +import com.github.ipk2015.coding2017.minijvm.clz.ClassIndex; +import com.github.ipk2015.coding2017.minijvm.constant.ClassInfo; +import com.github.ipk2015.coding2017.minijvm.constant.ConstantInfo; +import com.github.ipk2015.coding2017.minijvm.constant.ConstantPool; +import com.github.ipk2015.coding2017.minijvm.constant.FieldRefInfo; +import com.github.ipk2015.coding2017.minijvm.constant.MethodRefInfo; +import com.github.ipk2015.coding2017.minijvm.constant.NameAndTypeInfo; +import com.github.ipk2015.coding2017.minijvm.constant.NullConstantInfo; +import com.github.ipk2015.coding2017.minijvm.constant.StringInfo; +import com.github.ipk2015.coding2017.minijvm.constant.UTF8Info; +import com.github.ipk2015.coding2017.minijvm.util.Util; + + + +public class ClassFileParser { + + public ClassFile parse(byte[] codes) { + ClassFile classFile = new ClassFile(); + ByteCodeIterator iterator = new ByteCodeIterator(codes); + + String magicNum = iterator.nextUNToHexString(4); + if(!"cafebabe".equalsIgnoreCase(magicNum)){ + return null; + } + + classFile.setMinorVersion(iterator.nextUNToInt(2)); + classFile.setMajorVersion(iterator.nextUNToInt(2)); + + ConstantPool constantPool = parseConstantPool(iterator); + classFile.setConstPool(constantPool); + + AccessFlag accessFlag = parseAccessFlag(iterator); + classFile.setAccessFlag(accessFlag); + + ClassIndex classIndex = parseClassInfex(iterator); + classFile.setClassIndex(classIndex); + + return classFile; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + AccessFlag flag = new AccessFlag(iter.nextUNToInt(2)); + return flag; + } + + private ClassIndex parseClassInfex(ByteCodeIterator iter) { + ClassIndex classIndex = new ClassIndex(); + classIndex.setThisClassIndex(iter.nextUNToInt(2)); + classIndex.setSuperClassIndex(iter.nextUNToInt(2)); + return classIndex; + + } + + private ConstantPool parseConstantPool(ByteCodeIterator iter) { + + int poolSize = iter.nextUNToInt(2); + + ConstantPool pool = new ConstantPool(); + pool.addConstantInfo(new NullConstantInfo()); + + int tag; + for(int i = 1;i < poolSize; i++){ + tag = iter.nextUNToInt(1); + switch(tag){ + case ConstantInfo.CLASS_INFO: + meetClassInfo(pool,iter); + break; + case ConstantInfo.FIELD_INFO: + meetFieldInfo(pool,iter); + break; + case ConstantInfo.METHOD_INFO: + meetMethodInfo(pool,iter); + break; + case ConstantInfo.NAME_AND_TYPE_INFO: + meetNameAndTypeInfo(pool,iter); + break; + case ConstantInfo.STRING_INFO: + meetStringInfo(pool,iter); + break; + case ConstantInfo.UTF8_INFO: + meetUTF8Info(pool,iter); + break; + default: + throw new RuntimeException("还没有关于此的处理,tag:"+tag); + } + } + return pool; + } + + private void meetClassInfo(ConstantPool pool,ByteCodeIterator iter){ + ClassInfo info = new ClassInfo(pool); + info.setUtf8Index(iter.nextUNToInt(2)); + pool.addConstantInfo(info); + } + + private void meetFieldInfo(ConstantPool pool,ByteCodeIterator iter){ + FieldRefInfo info = new FieldRefInfo(pool); + info.setClassInfoIndex(iter.nextUNToInt(2)); + info.setNameAndTypeIndex(iter.nextUNToInt(2)); + pool.addConstantInfo(info); + } + + private void meetMethodInfo(ConstantPool pool,ByteCodeIterator iter){ + MethodRefInfo info = new MethodRefInfo(pool); + info.setClassInfoIndex(iter.nextUNToInt(2)); + info.setNameAndTypeIndex(iter.nextUNToInt(2)); + pool.addConstantInfo(info); + } + + private void meetNameAndTypeInfo(ConstantPool pool,ByteCodeIterator iter){ + NameAndTypeInfo info = new NameAndTypeInfo(pool); + info.setIndex1(iter.nextUNToInt(2)); + info.setIndex2(iter.nextUNToInt(2)); + pool.addConstantInfo(info); + } + + private void meetStringInfo(ConstantPool pool,ByteCodeIterator iter){ + StringInfo info = new StringInfo(pool); + info.setIndex(iter.nextUNToInt(2)); + pool.addConstantInfo(info); + } + + private void meetUTF8Info(ConstantPool pool,ByteCodeIterator iter){ + int length = iter.nextUNToInt(2); + byte[] data = iter.nextUNToArray(length); + String value = null; + try { + value=new String(data,"UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + UTF8Info info = new UTF8Info(pool); + info.setLength(length); + info.setValue(value); + pool.addConstantInfo(info); + } + + +} 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 index 61440e39c2..911b8356a7 100644 --- a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/test/ClassFileloaderTest.java +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/test/ClassFileloaderTest.java @@ -9,7 +9,15 @@ import org.junit.Before; import org.junit.Test; +import com.github.ipk2015.coding2017.minijvm.clz.ClassFile; +import com.github.ipk2015.coding2017.minijvm.clz.ClassIndex; +import com.github.ipk2015.coding2017.minijvm.constant.ClassInfo; +import com.github.ipk2015.coding2017.minijvm.constant.ConstantPool; +import com.github.ipk2015.coding2017.minijvm.constant.MethodRefInfo; +import com.github.ipk2015.coding2017.minijvm.constant.NameAndTypeInfo; +import com.github.ipk2015.coding2017.minijvm.constant.UTF8Info; import com.github.ipk2015.coding2017.minijvm.loader.ClassFileLoader; +import com.github.ipk2015.coding2017.minijvm.loader.ClassFileLoader1; @@ -23,6 +31,18 @@ public class ClassFileloaderTest { static String path2 = "C:\temp"; static String path3 = "E:\\javaImprove\\git\\group24\\121111914\\src\\com\\github\\ipk2015\\coding2017\\minijvm\\bin"; + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + + static ClassFile clzFile = null; + static { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path3); +// String className = "com.coderising.jvm.test.EmployeeV1"; + String className = "EmployeeV1";//老师的class文件单独放在这里,只有类名 + + clzFile = loader.loadClass(className); + clzFile.print(); + } @Before @@ -36,7 +56,7 @@ public void tearDown() throws Exception { @Test public void testClassPath(){ - ClassFileLoader loader = new ClassFileLoader(); + ClassFileLoader1 loader = new ClassFileLoader1(); loader.addClassPath(path1); loader.addClassPath(path2); @@ -47,25 +67,26 @@ public void testClassPath(){ } @Test - public void testClassFileLength() throws IOException { + public void testClassFileLength() { ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path3); - String className = "com.coderising.jvm.test.EmployeeV1"; + String className = "EmployeeV1"; + byte[] byteCodes = loader.readBinaryCode(className); - System.out.println( byteCodes.length+""); + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 - Assert.assertEquals(835, byteCodes.length); + Assert.assertEquals(1056, byteCodes.length); } @Test - public void testMagicNumber() throws IOException{ + public void testMagicNumber(){ ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path3); - String className = "com.coderising.jvm.test.EmployeeV1"; + String className = "EmployeeV1"; byte[] byteCodes = loader.readBinaryCode(className); byte[] codes = new byte[]{byteCodes[0],byteCodes[1],byteCodes[2],byteCodes[3]}; @@ -77,21 +98,112 @@ public void testMagicNumber() throws IOException{ + 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()); + + } - 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); + @Test + public void testConstantPool(){ + + + ConstantPool pool = clzFile.getConstantPool(); + System.out.println(""+pool.getSize()); + 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()); } - return buffer.toString(); - } + { + 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("<init>", 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<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 5dea27ebf23b3eddd55aafdf21b9bfcb1f82f31d Mon Sep 17 00:00:00 2001 From: Korben_CHY <korben.chy@gmail.com> Date: Sun, 9 Apr 2017 19:03:30 +0800 Subject: [PATCH 169/287] 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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%0A}Pb<;E9&E{9KYb97lV$-Q<0$#SI1<aN;6tnzl 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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 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%0DplU~I@98OekpK=g=$9`7uGGKHDu1_S z<*h&TiE&fNOR3*(U;y0*ouO`>>^u)Kd4hQo_Wby9D6slvov5&F{}n-KUjw_(JY}n} zMu+-wx@V*V-*_hj=S9k+XY?g|-yMHn2!0L_7(vE(K-IDcH?K}I4WJ1x5z!>&hGP7M z6r}g(>Hhs0{`b@U;|>irKcqwc36(xukTCp5)pYr6we;`ZYw`vbj{ow4vQ*X-kp&QV zGmP2M)d(PSx4}??jFH2jHVH(M1_!0UihvFK){s(+8AlZ}VDstU<5eM*Et2TFpAPLF z5iO^!Q%R&~0_d4}c{h&k(k^AXKb~Jvdu@yZQlt6%v%U(pVw0WWX<agJfizEmGE(Q& znEou*)nz|Vw@}gJ(TFABO|p00EMLOuI;}iAXeXriqVB4AeSH%W%(b@WMlx)}^_H7X zytib$^|BhK;0Q$3WsOkTC|e5#{m_i&skcFsg5y3o*>7kj-A5)@lJkh?9H%qA)9I3D zVgjpB%yV?_RURt)l^iwUxG~!@HWY5V8i<qHqKjx@H&ux>eVRlI&^2nQl&#=Db)FMH z3U;d9cyfJsG~~|6;M9=n4zQyWcotu<IGt#xbW*N~XRRn^7K2X^uU2}J9j%lQ&yl^m z`*4tRUIwC~_M(YD*Ppd_?7V*qGcGwC4<oVrUh9g(G2<61KnatKN!UNp0n%T;5*ldP zFJeH)dV9^7$gl}nZ^Y_p>u-qN<dHTbh!f@1dEPz#;bAa6FREJAuEUTl%_i+lJN<1m zm(+ZNU3w5Kvi=}H9Ph3?w2st|5fy8QG}1)@vwFr1FJBMjTQDN{%klKgC`1wsa8XlC zPJ!{D=9I%2Q~^GSF?_rk@|XG_Bk1DTnx|j8;c@P9s-R51%yY<{<zf%k_0giclwQzL zUGDljq|(euQtxRMX622oBEI5-sRRm5C^Blumb44B297tvH+>g1H;XNRh5TjlFuyrY z(6sOcSo0ak5t&D{Hj?uP>D+thsn>*r=td(rWW#!j5t`D`-oRujA|fj4XVX?km-=Y! zLG^;t5WypI&`!Dbxg=5a-&jx8M%s<z!+MfCTwT9f1llraFBAh=iU@5=FKmU^MMOHt zMkJjR2|Z1YOJd_la+WlL&y(te+G;+C0NgHBOqwNhBC1&ISY9tthzd<Y6yutw2z|~< zGVncX#7peTeLmyXrT!X&BxcEo!b8m1<)wZigCfdKY_?EmXm7p^pBY<!hS}c-(?5q9 zvr+%oQy3tiXDlEfy8krH1Z-{XKFimC_D}y?7Fm)Sv{%9+>c`gMHLHcDIU#?cI3=(J zQfXqyPon5#)d-Y0SMxBXZ)0ZI(g}1D3cqKf>ST_LGHki*=c8=$8)OmH>KVr~Yh)gL zdXCl?+De@0UHE=~dyq<>Q7wD(<~_>xoa%a5cY1$V&luKy8~geLylEYpoKGuQ<WZZF z&u*KI9&X$9q!SSF^yrW7W+*<QqwBmIG1so8`GCP;zO4%qBI%HW-t-ucuEap|49K6x zdaU=Wao-t61kt;%J@cVAH4q+AAk<5E!biAqA%uteE<OSP$78%Im41eG*w0|vG6Kg# zf2Tcp3U2JC-RB0kMSItQ|4e|!e)L2CtU<!_SoifC;!X+Pt8`#a#1%BW4`qLi@M9B1 z58_S>5zkKFFJX7Zz%9=!2*hlp9Situ#GM!-9;<D+{tudcdck+9eLKN-x_wT<4}_b} zSYN286hB{22RJ^f?Qc-szlHlHn+7JGS0$;XPq<$Cr>Z9}u%`*mHfPH1Z-R}>TQ+eR zJfAC{vyFXync}KrGQu`Z?$^MLt}j%}yQx>wBnFYXveI-MDkS>4xROInmMA#<U9?a# zX-6;6N;VOs)UhF6S~SY&oU}4|Rj}iEO}!%0!oxDpoK2q%ok{MV$E#&X;xU<#rN}nZ z!v^Q;bMJo(Fi$B|^}%vaWEHbjvWs1W2eaTV=h{{Xj!qTr>h|58+i+KAODC9Pp(ywC zLyD{>x;SK>KEqMZr>xVdE}1|ziJ)Cvw=P-@E&sk#KXE=Y;a&QnD`jvEI^Rg{%EVwe zV^Zu<C0*woCNX`8>xOLjlb~;%wKr82ZRJc^=@$~Jj44hAsOuq8o#A=z;?5pjM=)}V zo9RTh6xYNTUig@3zmL^nrM$*z>4z12j+4i-a;uUI?#V}j$%=?dc6c(TI-d#-ns*`> zhaRS|=)@$vNHdDY+n-qOelCO65Y7|{0J;Zm$dGWFa|7-E5nPa<;8FY}Q!QIVM#WTI zDLcl!x{IJBE*fuX=bK`PVG}t5E^loQK_qWEvr2XYQ*b35PN#M8y0|{w(SWYd{`~Dn zo2Za(5<nWmOO+A)kU54nh$)qj_4D(6V^te+n`P(2-chzbD`((nkznX-F(f<F%6F<s z<+1fehe)jh>1lo@15zf}STl5_Zr9Fx%)VoXItMT4Ymq^9^k};=OO5@zH0k92{!wAY z`oef9mxRdFpDERsVMkESEzF#$r**4_ia^CNl#NoxjqpdiJovf;Qc!*V0+asElSOsX zdNPI#cr}#PlKI$`N~v6~CLkZTJ0_jG05JE(kY)GiD}Omkm0cyc&V2xcLy;V3(s)SB zu18S%-lAgARYqwcl+&=xNPALUIE`gQ^KuP!$2pV9wLNL&g+~eBfhxFAzNGh9K_{Pf zfYo=_PM<QxR5pRUc+4^P#qO1x9e`Gy2>6RvxwgvV0?Ko4ak*qpxgpFVi-ipOu3FMC z38CIyail;Pe1K)J++-q*7g7!vnKZIs5=iZQ2)09)@r@uppI=vS`hn7yf$ts#lfhhm zSgdREi$reW48!u|;WKpo+Cqz=GerG7LW|+Gx`9u@ToQq7h-es=d0)?j)s0JYziNH% zb14=X7Sd8CT#-{37alPrlnPvc=F}KbB!m@AzFuTp5gV4Ek?9-7YUmW+I&NY(yLW~{ z9mXTQWKn1DGvWK?qBDyQ?J#*e7{-Rw0A&WYRqK2x`3y=}g}pUc;pV?mxS(>~S=HdN zYdW@SYZu~|id^XlkXLq`A!8o2A~V|ZwP*v1!A#h4;*?=O1DJ~q;qDpq1V$;5+nd*C zIOt_c-)E#TCP>o}6{zL;`q$kcupM8EdI!kD%W~MOUiVgaE8i%77d)w}LOwW`>7Fpb zYvE+jCk?H<C38FLc_N3+0oELR8=8A&TKonY8d|pQJ6`u-t3lI6iFy`eV#w_RHD47b zz*p^!!wKcZt9?m{NjG{_N5Qe$Db;&%e!97kUSl7?<9zR7l8)79?$oG}OkeJj<vpq_ zdd5|d^&BPdj7`F%TGJU(Y7^5O(OhcUa)+43o0i#4x=Qp+<i<u)RH@j+*X}csZ*yH} zLBEP-Gk;BSyhI9dUyw28GV5Z*V<}6vmz*}US~XjhUj;1-G!%9vp@mMIn=`j=6Wwy; zE)`ufecg<sm$Ii7G@WW*)$Tg6N3TQf+kD%f;2B!Q)cnLla8cYCsU6oL7?KB9ui#%* zsOzW?5u)o)p~biM^=Qv#AFoa1v(Af?{X7;23e*;OiW9}%*T|~^d(L1%J<%{hG4+P1 zII56aAC3;(yeS&(Bf6;w16oluctDq&s7SB@3m3>#ToT=|WXslt+l81|?}-~b3)UAS zj3VL}`*0Q>4fh8kBnCk^S(eE9p}8N3Q!Tu!B=T6fX>xL%!&PvduD`yVW=0b}xxqPj znr*AD`#E}HwOG*I=#<XX+n2x%vrQ0rLx5b#^7(B>QMTeFxx;&IMYR2lB6Y`?1>iOA zzGd!6-fdHnToG!ASCqAZ;}12pf-O5NQFH!^(mwH655sQlAGT-biw<a&2zl}f{_UL_ z5TT!+SU}ZQKiZ8qwHa`s{US>?)IWH4X1j5^xWXIAHvqJ;+J{zwVrzQ3+n6@a`n=*e zL#z+(X|3a^oKk4}qaExDE7${!8m2RAtAc_(R`JwV{R3Eg5`2ypoC&TSuq;gX(s8Uv z8B&Z>;dGMxYNO3lKX;;ja?|lT^~T{=x3xHP4A&}#JSfZ;-is)GQk`yDK(I{)Lj_-O zdVK!F6Js7&6m6bf(;H}h@X@@$0rdUyhXV$4%%uZkOv^N0{!0_6Gy7}0UT@XPs3zbJ z2%@wnt9w)6B1?J(A<qXr{aU1P4{y~sj2NEj_`z|X5d4)7{1PsBr&e|#ZG9ODG>t!@ ziUP!VhpCy4Xo+^D+RB2M(qa4(GAfmi8w7Nu0|Oi0g!?sY{iMz_eid9D`oYS1U50@Y z*JcRQ9c&y%+jcvAxfQHHeb_d((=5yHp*xW2FaY_IO!b^)qQu&Mb(1)C5w{)P55Qp% zkcCiOK+IG>R5y3xHnkFy9J;kKa}3qGPqG30@FfsHBn{nqbAmZ^?nHVu@pD$R1+G&I zVso^23m;GPo_BrF@$!SlR^X9rXfw}ftG5dnKAvyjm^ZS>JrHfHaMI2E4TI~7qpBxp z@{z6Y9bxB<7x&k}I=>j*n62dnMF;1wBd$q`H66MMzS#MWfD+edHFjfG?Z{+5_<i6f zCQ~Luts(HpZ)(SFiCxpNQX<^E#wq0n6Dtvl^~lpiX&vylqn5w((ycf79xE(`+WDW# zg?Bcg0pEct2{Ze_H^R8ydy4KrH+<rg_8&_7mA>v+0N<456M3|QgNynZJZOv1tx*Pz z>om_?qYa)C{%B9n+y0fL-P9dM=onj*k4!GpmH&&y)X495SN*DOHpZ0U&Sl;eh<YRX z!QxJhfdX3JhERU>8twaP7?%LZ!}sb3x#uVPh3#+Zfgel;^p<*7=Pv3Ee3fToRNg4= zJ$uGpfe0-I*17v83#Dbw@!x=)>Lw2}t)ay3q7V+F5GbLX+5$OoMu|vpZ+{zxyJOB~ z2Z!|25L^msqchp~d!<kX<#nd!kI9#fF-ocACPOcmNmk0whkMzM4XSCfo97hWGd4?x z8*VD2I89Bpvo}$p-^4hvvmd$@ToNBOmQVa%l+!!0Br$BDL4&{Uq@7Jg(BbU~ovi23 zaF!Btfqf-n8#hclPL4TMy^8or6Ook9ZKB)~t~X$+kxA7)q@aWR=VW!-_IXhkt49&* z<iV4C&+$@Q+CN{Lqv?Ep#Qp0duAv<EU%y)rn-!HhG&5mhYKb7<lsYZhC`j9TVo5lq zARw%Q`>cYIQvS7CQOZ7`eE4WlalH!b>W60Z@FLW!W|qI%0##=z7PN+OvR!?{h$>x# zb<}8n^O#v(<nr73x}E~rlM=g|d-eE^qk=gJk7LF5tb?YDx$!sC;BxH##R-X@J`{<y zQ@m$1nW)~)D%5T(;4xeYk5<DtO?XZ#y187UU37b8t0mLm=sQtf4Wc_lx-{%Z;VPJ! z*(rGojVbCeoi}^DA@!~|NN?d|0cAv)VzX&rC@O)sR~GcWB}AFSlh44mRQ=z3GgW}3 zML1#-VZjQO18)&dDEJFMj}8q1vwa?w&&+}lLCb(LH{bIFJLPdlr8hw}@tP77*ZFa9 zDoE5X+_4%=*Oc|`iFQDley$uor2@BAQAg1DZcmBIZ*B2M^brg<&Uchrmk3dT9Z-C# zu`cwY_mkgxboVXwiryY~N!)tVLy!1<oEsr^PYA%DuO{_%*RvBW^BYWF=Wp$IiBLz! z0!1HxB|`swuJq4Y)Ju-zPRZx&>G$W~f1E`bx>#5nn>f<{quUMlz1=b&I5;>lIG!sw zoh!JlDELz0+(agdC^#alOitxMz3^M+K&P|!M`7i{K9ZFv_|*2qUFSgjT)uLyBJ5-= zLT+lXOekuxCb#u!oByp;M7+`llhcpq@0t9nMQA5}D8Nyp^peYRG~&`z;)`-q)030a z)Zk}qOLG3D^C9JC#t8iE=}~chaeiT6Kru8hFjFzre|V`9#Dw|5h7!`ag2ORPLjJYj z{`U+0=PfvM1AnLgEYR`w^ZNhe-s*qf0wFsadjrSMCfWbE7hP%4`pS!G!yiXe(zd2d z-}#aBrTd8?W2MOg*|B29kccD@2d`oy{Q<^Eq5$bkX>I%tt&`o~2HwQt;o+geR9}^G z6&0?c7Mq(lT-U0qo0rroDs0yltH4e^);*olNSHA~6djK;ou)ar+`4aHrfzTMj$-h^ z8C0b0^$9&LMg|^KcrNw5M*PUH3Z-#X9R|LjcGXWQ!SO_yDf681gL|m(kXzl2ZGYFe z@t4L;DnrM8{G#i)ZSp$fhrcs?;y(BV+K0%==d^eF3ZLn*&Fd`)<yj83NBO$K`85Tk z;MywfzI@>}UHYvhe3@B3oSo?k`&D(&o9R{t^<n(cjS4UJT8qlV__aBFgULs1P>9J# zZBQ4pr^GNP(znJiBl2Ur_vNwI@1rl|=AIbSizeVBsSn@eiX8J*1N?(LKn~{-<%3?y zSK&G>ya$Tob>|+pTfCMT2MGZd*uu#_Pv5!vM^U9$(2pjzbtHrlT^ty&Walb9>`<E9 zDjTz@t3iXF8gDR>gN`_hsA_0eC}}O6=th+%F0XeNKPt9bKAh7^%ZH%VVwI|k&shd2 zkxG+hgP+L`7OzorZ>@N46Yq8mIDoJ~S>JGFcida;iDjo8dP#R`cO}4S%%Y{pTc@Pa zQl2n^sJ_%%yga?A+Q0|U9!kG}2@{x)f<6g+1Sb)cJ&y|8+>ml18pDFk45Ie3)}aY} z-^cF>{n<cNTLtYdz*9yHU*AnIjMG7sMTEFde(k(%!O#w>Imm044${%$w3vK>u0x5J zBx|#8SCNBVpu2ZBkCT$FqIqL^C9N_J$4H#^mpa-K)m%$}G1wfZYijpzP02?H7-_#w zKP0F1cw1AYg`=KbFTIdMEY#uF)UVpHnh=F!^v58)b-4w^2$qPCrz!TP+G0wnNt0ob zyY&Pdh2eYQSRCrBUKh}>@BC&*{S|M1a7H8%s$bN!MGBZzR#9RP1iobGnblNZ2xYG< zuGrlaHDNIy(%32LP*p2BWLDJnE-UU5dtbQ;C+^I5E-oy7_AYFw%;PCiVXRQ1Vt^j$ zH;eRF5z@j|vSfWdNP#W`pu>tOTF?Fry)&^D?zEfmS{l2`xRAze^+^ZMR32h?n#9Sq zp4z?~(YTN;Ws)#a+Z|iIL6FGGRgT3HHkzOf74}*#Y}CneCK9`Poj(UwnV_<=mad}C zSCC{c<ghYLVr4D*X`7H(T_vN?t}3~_P)MOeTy%D-m{^@KcYjYQxh!>Zc(_p5WwO~v zOe~;kx$1;$j@0THYV-c4N{N~SEi6~EvQYAy(_~ZBF5F4tn#~dltCLced~hw7()^~F zqXNY)p*VLbV|PHYvnkyl>+>Y3>m_rj)6bLW2enElOCO3k04R1{#kngPyCh1TodFyL zJFBhK*mf4qQ8EcgBlOfU-x7oJ{n%ufYV^7}1Cq%wn)J+54W=_eVMo2EXHhQ0AHNUA zy|};k>Pp88%Ch9nhTYbNmaO@ik(1K}$_+x2r+m&dm%c{wX;?_8dA<bg5MW294ojEF z2L?gdm()UK@bCO^(y6Lpwp>C@y(yaIb^u$=B9c+h{22oxn-}h^@-wTSkjZ`D8LDJN zStMD>I08pghYA^xX~+RrO0-OQBiyYN8QUk$I2PtRs0KFVGdruHZ|vJ07hB_PKtcr1 zvX>kJtmZbO<(FI+RwSX`YOJ)(J*bi28)mm78tpH9L{LJ3BBK2>(~u=uGVX%uCt*Mq z(@)X>2$L%v%=5TD08^_Lsu2arP`P1dWQ56~3{$HJc+1$fE2edPpDE@#X@IRtB8NyB z#;<{gEAbx0+!z7f#SpHqVD%6j9r!Ii=z-nu@al2jqu%<L=$P#E$NQftSl6bbf>Qzy zau;r+64XRA;$wgy>AOyB{7MbHY<t31-M+bia$^f-Dd>&RA1V7QX>g(kOIyy;Vf*am zk3X~n=@I!Qcf-R4nH-GL%XiMg(#=7r#)1@0bEaka9gk}J-P8+HL5xk>CJzfFvC&>v z!NX|BNu!WTc<06G$Y!65wtvG3fA%N5sF0njawEv~ceigk^NK6(P15<ov?!Uya`9>} z70W&u+G!4Vsi;R8v(hJf>q@16uow+B7my{RpvQ82lrOCVjEuxdHOsU<UEshj&id0L zlDzuHy3f`pL!1e!6}j}iTh7ekww!LgsBMgFIvMtjOvc;uCwdYo5BnIsUI3a)dFR;j zCTi;s^e4m{ByRVWVGd(MLeSGErTum|eVTdgLrk9_JEv574DNLZ!u90gT%7F;|3R1r zeFF@CRD++hez#AD3sy#ubo$muY_$tBEck3=b-^9|L^N{!bI@maN^0q3ZVkmofx7VM zd5|-T<EcpL%?H8FqLvNEt569Rp6c^#sx_Zka?(}3l9J+G=*-C;85(Q(_bvVN&|36! zg{o4SOKQ7~T+&r=N);d#r6PXp(L+?){h3m%FRFVPj!rDk4%xHt9fi9RGhs1%=?xi^ zE0c%k%08H+g^D?wkc<)aRO3q>)UJJ|D|<d)EC&^gas1m)3Fcy2jcV1_w41{*a5k8@ z16HPpLt;lcD!3+fcIw;apmdgWjXSIv_d9<u(rF!l*jv~wHa|k~l5g4<4Khe$*)GE5 zj4FURpjqbwl~V|^xs}El(u5CiNFxlUl1MU2MT%9W{wOjeqC+z=N4Bjhh;Rl>Mpv_Q zw{Ko0OIHQyfz<1sb)t%#dqLk?rw%TG;CNbKeIS~?sV*&BHPx$PJB1L-s4N;`<QZ-- z?w5T{#=vXO#M|rZ`+=F~198jlZiu0qbtq|6;zY~5=(U*S>JG6=jUO}@^@EyLFH18^ zmhOac|DLD^TW>ZVAU42IkL`3@wJ{RUS>UmAIz&SJU6oyuO6SB`!jC!&jxsdQ-UPnB z;v$5>WATa+g7No=sLEYt>l+Xw%X}>YcYZ+iAxdCs3`-r5tU|zSKH8oLZgE6VDf)e& zCtkV;NHu~K0#ej5!qJ}QQim?hqJB%g5$<bMi7fY!lVi|RcC@wj=(i12Y-u%X2A#Su zi2bUK%H#%Gjmn9ab(WMTDA+poxb5~yJ5VK*E0Pi?K<L)PaaFrH1B??&4)>O*%U;2e z(-h?|JDTCzA--&;V^oJDWKQd#-KcC2K5k!9h#!2MeBe?hBcwPFRRMH#LdjQyRpgvQ z=_E=Y{Zo*WU!eoDB(g6eO;5{&f0JiH{|Gf$e}BJK&_-s*pO;BG!6MBoA|Vx-|K7zI zc&Jzs^|`8Y2Q^Jc%QY4xI_t3$CsC2SPf<H8--(*mn0G@U>9JkL6Rv<Nm)E#@>Z-xJ zHS7*nxfZZ4Nn7HtflPC}mj@q1I%2YyF=_<;-I_GUc0bf+1lbKhdMV)dGn#RiFEJc9 zGliQ`<6N-mXH?rR;X)X1tNgi0!p{&?!*8#<h*f(|VR_M0>pyDhl29{GK7ymt*FeZ3 ze?SuJ_r{iCt54^{f<ekHU;iqOuEFNA?PXVAEvB_D=bhXc!A-J(39-8w-mC3%h6gJg zxehO3bfDI@ol6@TE)Zi(bU^DG?RPAw&5RL?F|=>E`i`cG5p;8XtN??D#y8S0Sx_7Q z=Sb>6KemRt35x3VpF;^67=}A21@=(*F?fRvNkLK?9Fr88Lw|ly+HA)eZHfWP?CQ^n z%o-euhf}+Iv&89+zsEp|Yp^+=3Gqs5;2pBO{rSA(yLlqPcE75Im(*(VM3uUOFNc{q zWVpk*g&kejx_^lYD{$B749y9{-{!q0#zB65KU~^L=i{|~zH2?1-*ez|!7?F#OZnod zkoQi%e6`)uq~VajIB&a?8QYM5w;zbdY&*|ZinF94y#cbg3Q|EjOX8b^>m3#F?1B=( zzH4e+W?@eW+pWP|o(R5WjiCZm(G@4<4dP2)C_AJ|jUp<@e2E75EEVF!@33yE)GE|K z+mLI2L@Di=Q|!$@&o`ict&nLkSZp!KViRYo$ta^`OcOH4VzHFZF&`Mpe6cjoc2UD} zfg$sfS)3(qxoT5v(E_{JxF)yELK={iSxc>fQDIEZdI2}z$Q^9CT0GAd6@pO|TO3tv zVHBV4T4J%9CB$meV4#`7h<GEL&Q{lnenj$VZA7IB8WkI~GVxBO^3135U^R#^lf?{K zGlF-wO>da6mEVS1H5N9aFNR_1jEJ7C922pv#x~AYnHFfl0-F|Wh!!|PrudVZ7Jvn< zHH8k#+Yq1c3|U>+2{Aq>Q;b^xpjPb}>l0N*6go$g=mhfWvGx+jcde-yZK(2Os97^4 z&F3Wn#Vj7Aw1D!o`>X-a_Z5)eUZhXiJ(KIVEtsC~8$<8T(RD{Ha1PVo&N;p4Z#I~g z#EMktYbP2HwWw3sSF3PY+Ti!KN<1F-;23NVM5$wfd!p9v&KM)n?DE68C9I$=HbgWx z3h!}S6KyEuFZ(bKbQ7u87zI}RBoBNtE6xXaOwj3!8!9kcC_0+(<jmkLNA$A64qRs} ze|IgOdsfW4rD3(=HV)Z99Mq0qyb>8Psbf~87V$nDJN0|Ogg-{QDS9`wssY+`+~P(` zDCa=8PIfc3NDR=98E)56MO3nhF4r5>Y#U?u*Btg_$)7-ra!5vrNuE$7_=Mu8<M*9N zMy=u;6G`+)MpMLZOyXY&CEhWl64h$MudxnF4qe-U3RvSEQJ$pZ`Qkg}3J!=zUm_K_ z^1jhVh*}ZhBPS7*6T!~HA;;ar5T@@_rlSBdjYBu{@79Fx=n%WagnbF}AHt47h@N9Z z`H1pk!j5Bv@5qUsnGwAOg>#T*$%XGy2npJ^gq=Ui5Rz^sewZI&im?Ec1_D;wBoH(* z<!RGuwd&(cMg^ixIBsa#>@{xW^)dYzljA6wB6lI*X_Pgg?5m3qZfOeY2AIGrFly=| zv4Qg;q=n%#p%lP!Kto-#9E9h2MdpoCGhk+&iP8mx8$yq*iOR|HSA<zYLJyH<d5F^G zgjt1^rG#CCmF0ww5EXb4Sz*2?#DtX|DTh)$k?`MbfBsXGN&_9eoyMVbg!xio=CFu5 zqQX{TBXYvD!V8kZHo}e3p>*W=)S;zWp`V2~$np^obvQwVJ7k1A<bq1W<$#5^c=yKd zQREPRDc&X!u8Iq@Bg`&`9b*gM(Gs=Cg?7sbvm?*a3OiFHZpaF|A<U8ytx5}Pg_<)X z+Ta4`hkRa87St>XA0)yB=U#z%eTlgv40Jr<s*tc}m^nV;1$q82#93nDI|{_X&|?C` zd!*StVdv1$Y=V4%uybH29P;eE5P##caN~n=Xz{hgkK-NR8Q}_v;Nv6VJ7}V3QpC6L zP#+oL8l+h(;X5wGE&<^l!hH6yV>jVDG{i0;;a^Cz+`@M+gaoT*M5}I8!px5_f{pkP zkp)($fyKjQFKpXubqDjUayM)R4ul`KQwZ6XU&m`=03Hh5+v`>`5ee*5U7XMqAIG^v zMy1#Uk*ttdzh1!KF$^`muI&CSZvWkR_@^hKYhx=j^qE6K_*wIf`admh|J#!gwlFpQ zSNceliiH!l2!gj2E_Kbax-Pk2DgY`PNrFw+o&!k=5rY#PV(@bdu6!bpkp+pJWmCl} zG1xc%4`3A%MtKsiLotOryf_y{#iYaI%kMQuGSlbZKHjf^d&yD*Nxet}28N0F;_Q)I zNURCJg#g<|P)I(a<b?gq76Hxil%e#)4SVL+ZTPHZ;6-Uj@7IA8|0pS}!9RDHJalJd zyOM5!b8+z%;Sws9J}vly0l;b6K5q2Y$Nxv^tx^iKd%<feuR-}#WV7XU@)UNoCaIim zueH>khf|IVh4cw@1xK=JBPD_E49p}YRBI}xi`nPv#hA_FT2O=ev3rekM>Q$ym@jiB zR~yqr`gR7xMV3{o_rBhuNoC0-N~xM{LN<hLn|MoJPFu##QEFpWlXka<B~(x&MEq=C z0Hu7<E6#p^&8@r}Ydr1TnAaF;jW=b#pWj+8G0+Iy2y2xmR;RbgCkRd!580ZJ+Y$-E z6NyHCh?6*xAxlcc3VXtV7D~!^B=LT-NYKT~S;3(mC3<bK&0~aR9GPfAuspSTal0eE zWUsPhE;xj8&t^TLE(YYwN!b9Z1I3=zI=Vuf!r*5wCd@7UEGicc3B;|j(w#3^$L`lA z+C%k`?AK^ng1k0%MRUKo-tb3D_wpje+$nasF}L<0%5$6|i2<%1I`fY1x4GlAhclC{ zw?+YOU4B2tNlh_|6Aaq{Rf#FiV|U1_SIsZcKNcw)3zSCPo3e9HDNZJep>(lIVYbA_ z4$1uQ?e0fro&CjwN!x6iHsIKCm~2eQk`BLWi2p)L_K0x_^D>|i?ll~-AEBW#L;7J| zk!I};JX)b8s(uTy-RLWbWbd;3+g}Kdoo#EM_V9E{*J^9g<qP|;b|hs@xSP#*=K+k~ zpzaShl82_>Wz6zUHMVA*CYrdS-C9PvHP0VM2%;i2Gfthtzbrt<TYp64LKUyT=!Wbj z(L|xvSeC^Qo-U$@RL-26rBBNDBzwXUrg#Qpk~#*LB7F~5H@<ZnFv|@!6Mv0bDT#Ho zl4E?RkW0w_twU0}K@`ffdp9V)%cg)HN*2QsJ~F$!2PL8nMM2@S=zF*Ps(f5%PNRhX zIJZE*i&Y&`W~21$$*^sU;BAgL>Sc%*pF<r7+OGyq9k>;y-e~(Uc&A*c|G>lErQV|( zRV4ZYtPbs3pSp=cf<v!tu++24F*wM8Xj80_Nw9H_SQEe%c8JKEd!Ow!mm|KEICvzl z3umzEO(ew|N7@+@CBN^a*M6il`p~UMj6d@Y!)7;l%lGlGy25`Kf&Z3=KYN615KD<$ zKV?DTGl`J?e<}}uYNh{6B9de$q5Sy~-iv7(@Q)eq=KMFP{0X?g1fGE_s+;TE3|0Xy z$6q{3&8xI@EcH{Lf`6G^#+<?ah{=oUj{4FkX`GIvddYT#K7~U6nF8sEsODr>F&=r1 z90Tt^`0Tzg_#~2AUz$vXNUDW>t($43G6^Y5(BQA;Lix2DJJ=VyHNyV)+tAI6@G(R? zol#xfSYQ+uIvypXMJnj8lAogd7{2Llkb!9FL=iK=CicU*Xzj&Y8Bv>7TylRj^Y54b z-#6t?-W^Bx4?fG!Y-RiZueJ$)*UbO2aR1%uKIt<x8S67OSyUjl8j*IUBBl9fzopK? zCMy}LjiC@L<r2guIEMZNlawpEubP#mO?vUS+;8P4X(sdP8xTK3n4L_!e|<J4uJ8GH zeFW3TwIhoYR)AKDI6xt*i|<#eEEaESq#&(L?&T6%MXuieU1!gGQY!b-0dvj^P+n2U zo=)<exabZwx?&6-plrEy9VS+%UC^$QdBi<Akb<c|9k$Wx9LB~qV9m5mfze=7yMV3O zOmS6eU8=Tjas_{pF|?H+eX|Mf>Nj5)gZy^T*QIi=Q?{DXq<Ni6sOp;TZ_rMZ#BuC) z*3Y}^k|AqKEgO(McG6cE62gef5l~l?Xg|*Oz$0L3Q7C_7br(IFjN*Fx!wp1k*|5O4 zDM$~IHiuA)LKpa)Bbv6ANH`t=-=sq*cEUFn@Em6TxGJI2jQa3G$GL(<H&pdiZOxcU z#pT&ns55~J`b4TmW6^zVE8FsCv{;=lg3qu8S*^h~W;S-}pbW^oICknRQ2;t*C(9L7 z4J?geUoQ_@DWd2&0bouZG&o5CM#=YDSFV%{U`tqUBzm!I9f-N%%Dg<slN!^_QJCu# zq^UefsV9*xOAy>4z5`y0EP)MB=BiSHnc+gNPIPOZ2c!xl$8xUXBC6)>PaHTgI9=ix znX<V?J2)Kx*U|e`X_1hBh0ok!8x@JP0>9kWWmszKWrB8nU=)KXmcsB*FHzYdovgul ziGDnyW}^qr7y?3GHExF|dfY>N%~^grX&LZExT%W8XYVoCrFuF?;(U+c!IzMQ5h&*3 zfsv1ig<m4&fs@V2<wpfx3>|X5Vt<AH!}8yW{U^&1H<z;RpDc%dviu)2g#TYzX85mR z{_i|{bPoqeu)J_|e#%w4lpz0QBqW+8eJV1v=eZIKZkrHmx6#Yw0pFsq((69_?HH!) z6<cW`skuu)8YlDCLspv8)Ok)%j}OSmo(r(Ue&TGBh8&S!6bV~h63Mc>DR*!d#tjUm z8b^GF%1-NC^Hg*U#!t`SlYE;typ~QXc2A=4_hAgfl=X>J+!R7(YOv~pb;=szjR`h@ z>Wb?sc+YlJGy|4vi<D&WXw~m(g<ld4lsJ3h&6;-4x4?`KMWkII!EP&~r3X$vqi@~? zyPR{D=$1vAlxilSC>O>0sgzPunRo3jJDE4_64Xv69Re)}&Sp0OgP~kp0j|~>{gmnJ zE?{lk$hc$;4KivHjfD&u<eg_BSX_7q6||l8=HFp%SF~+_6qsx-5eZ~}$klJ05Q78Z zpB?4rA%ulnYptJgq7*P}Vm^cr<Hjo18$M(PQ%EEQF7%o-qomJ0ELo;DOObyNbVhGP z8mIyAvMo{pHn7a%7O5(xc+*Dic{`-K7V3TV!K5_I7|3L?1~xR{fFY8x1%uaJL3Np6 z#oxi%X^m#+qF>8~w7L|IW*i=mnB~$JG##cdQxXWXijDyXc{D>Oi@=EMLP#zA7ZSQ( z=gSf$dHDCN85CK~<#^}5(;zU(G${3#CpC8afEC;65*E^nRwFF2`w-kLF1HK0hF>)X zb+G6Os591vzPvlhy^Kxd@b(HBGN}9{5X=^BLSOD7yhEO)UuJ>TQ#vyOmMLyG0{zD0 z-@`s3hl})~(8~_&qx=zFc4qAT1LsXn7fT{K>JQq#6)Hv^_pq`bE9Byep!_U_O)fr2 zKmOWD_IH5)iT2RKn~K#Z+K&G#v>E>&Xg4-4kfIdckBQJ~q8U@Vmk=t@jiy6|RgrY3 zO0S)`j<_bD+dk=}hhpLX)!ruUVu;`zWaA$~{R*ZJQbQICs7EVCqy8?f&l)qVKAvD{ zQI{>k8UY(DNZ>WPLA(Por-Xm51O7YNz;RefU_`}zV8d@j|B*5HoYHOFmYyIL*Q$GI z2#^gkb_QeRGVMm=)4#@R(A4FV1EWEwHdVZcCEh~pWu@lYVHf;DYq(SxzrzO5HDR%Q zOU=1C-n0ztR-Q_>p~q(|bnA@PPc4@sg#&*}zRKu4m>ZSeu$oum<W0SMWT*l$W3Vm? z?Af~^KqyodgDTRlniC>xS8UA!*^JTFfr_p_2(6`SClsoy_kz=}kmpdKa}0E+&%zTh z{RqHmjuzowkj0u);K6y^FLZ4pu!5{^9#!t%fqiZMnZgAd<TR}@?=HEWZP}sAU)O_d zFnwlRXR!^Ljg{Kx0-{8Lk-B7vHeK&-yA7s`r9R;A_nn48owzvG;6xH8cu|2yDdai< zIgbmbBWWNTv&kp|($slRMsMuaUJ!gY)}K!0yf9y>-;pJUAFCy9m{p!WKDpmGFW2c) zr*Uf%-P`B)I3kD$r5de}RC5w1l9)er8iukVl@E~G_KbT%A6JD<G7K4`jLdG)6UsQ* zOS>Kh-hrZFI(tcX7~1CyYXpzoc-oQqgj$9_;?=ExYh*l+VQ82k%`OP+OXK%(!qjt> z{`g?nje5&`$R4Rj!ag0x{4sJHwttQ~q8##qc=}~*wmmRp_JmluR4^B7HWTh6#P=_n z|IX|`X-=l44)pt^Ir@J^^S`%p{9CC1qB#&s7pTa*LmMsJEf!QjT4qp~j@~=HdHy2y zf@WnS{;@xT{vAg~I12t9$T#tN!qo_i67s)@=4L+1T-oyVc?XssxFsx<pBY*(C5$4Z zDXt4VU};Ncqn4;7Q!pNR>`z$dM9QYuaZz72(6_?~ZqYe_&;}D*w}=4c!Z#Anb|gPy z@eWomLTSr(g$O9VbE1YBH(73=_35{gF<4wzjYy;kq4u0CZ!S_o&u${dj!MaT;$mbk zjPD}@oO$^!+%SGS*y(P<cUN3FOHwRS<}eJk>u~8~P)wFQZ_-lP!M!RMqBb&V5&cW6 z3kF;HxB?UuCEeHH9=ruEE%ic1tI$rUgkUK%pYiO1^5}44ZcHL_X|TQsvFVjM6G~Dc zxTZ#<2y9AqNTgnS<w4(6d(c?=Mc32Y3<fldDd=inBw}|N+Qh4RY}t6S)=|3<G3lUd zF1btYP^&m;=g5Ajg37dH52X8rxEt%kEW<_;80jl#IPl2shWVAao9d%6gBLRb^zYMz zgP*7wG0<KVis|;q$psfNU2jwFWO}^0XNAPsx7Lfew6cf4;egNO{gwo?Ey;yR_#VDl z!Jjyc(xpQXogu!5RVpzWVZf0vTLxi{6D3*>adA@exi3o4)WVfty(^v-eX4Jw$Z24r z?2!|EV(?d}FJzN#EG`L;p;>C-6Ad^Eh*B#m-?Me;ME{D-IwAOcQ4|r1#eyg0Ew$md z*vHqL!(sXPV|^l-;+Fyl-&}}~c@ZDeh(|Z#Zq#e!Lw1;VIleO@^7ptB&-es20wvtb zpi<8Leh0h<z#_zmQV>6De!uH`(!Uu0JIViKe8;`L$?TJH!~YfI%>S*}SPBU5aOmjv zRay$3Ds_WsYUAa1rYvMttHOe;WlIkrINPZv%jb0OWP0h1G8P$pcMx}CtXU1Q;C`R6 zbz5edo#|9&+S~2JvK^4tPgx?rOrnbLR7#S%<bJN~BJoLTLyMm?wWIof@a9AR#QSJ( z_6rC#lk`PLG`>AK$C0bl!0Z!7fa~Bz<;GP<d`V$gF5%lbxKQ`Lhf9Rsjiit|YRgI? zLGomlM;}#7p$=-c3xQQr3-0%j*p9ilK0JVdEsyz$zuxtXZ5DX8^C|b>?kT5`^;Q*B z@JYP$fJ21_+9oFbnlqD<Bek=PYzk?YCx%iG^RZYoai@32OE-awQ>9{k23WgzJz0<r z@8KlFBEQ2zRr^=Te6(23meoCZM<FNw34G%&f!{0GzY}hPN<parWtH4K=HC+yJR70h zUT)77G8f9$Zm4#%lwlb>=;GC;7TSeM3_JK#-gH4>TgnZj#J)_stPe#-TS%WWph)Zm z1*dT7?leV{(wwUI5(TiD-eRbV3Nlp2Ag7r|=;=b0jM>LxbJ6Ziovz0+Snk_ySUZ|A zYVHP7$sUD+*hRrq>BT2g2ET|KAhGxsiZGa9ly?9*6pWW07%QEn4AFd_igOO8VA;Jr z)Wn|9wk0;48eR)cKl_I8f;5y)&L!|3s=Ws{irJ3<>_$m0C?R5+cLxLy*|%`!!fYMH z70b{=c!PXB?alZti19vJj-5=2m;n?Y*Z+enlzkI{Z+=i~Ac@x2XIS{#V><-S2fQu@ z)RHLBJU2~<Zp;<OzD8wWiQE;+gScdzTmJ3G%U{_}f9Lg|B-==bUj8B3@_$7#>;EO$ z4(W4_7|h)&a{|`+J72L#%NV*zceOZdE`32iqqXT52n@qyy_9Rpd-Z=s9%M#54c5}s zJc-^M%w~r#Q<-P)&$oNzKd4;i#0_*Hb;6=x<|s_AU=Co)f{`*Ll;ca8jCpq?ZL=Vk z6QbWvj(_-dnWdI-HXk{yecM~&ANXucBy{7i1y*r}I03_|W&znl-PKPf)OOj58}RVG zfjY8y{w$6Vu<L3zZVpqph*a%Buy)Z>@J7e@P)Pgc9SqoYUU=s0+3xEyc&={b?kH~a z8A7Pwr0rwSN@?c6yTj_|J%EjnJv@_55IjI(IN33f=A6pKU1_$rLi;mAG@(+1O0t0> z*+}lU#J$zMT1a(Dtct!m%fDczL0PT=ZjU~j_YS}OHYS?_6tN6M9_2Kv9NI|9&GrC6 z$6M#bjQ%i$w@NOAIgi;Yb1hqrVq6obsA?{`nYYo16Z85`@LD}DX($D7vbIVc_7B!D zW}Tp{3q_acT=<+IvQ`?30GL!UA}QyGYh8)Kg)Fef7j!ze&|M>TayjbsiZ7PdL7B@> zOh3kN%-O(q3#-B{qEj;Blk(d@4O>HCZ2df98^4;?Yb5FYSZcE`DxA;40*LH?O)J@; zG+30--NNuckrEQV)3y#R)qM{BdDOdP6A#%>e1q*~-V<JGxJ`En0g?qz)1dzVBsHL4 z?z01}qPeIe`Qbm}Hb7sq7Fpk0%+?>smS*V>`FafMW0?85*Yq`naO>-n!y7eH3Ni>* z+}_8?IP&Nyc5E434Df;xioXl2od0|Yh2kGghQxh?_yGRP?D!k6|0FrVo!yt@ljNn( zMtT4LCy4C-A~{QW+G&m-!yEbwR6=uOv-z6_wTd`poyQe_2}Ie{LLV0~?E@)|0k;8w zB#)e4_tn!`bO;mv{mZ*T^j0vA<&L~G*_KboOLs~OeaF+=(Gfimz5Y>LUp1VZi@Pd6 zS`tn<r#j4_JZQWpE@I%E+7bCM%sDQ=abC?}KxJWPQ{9-M3q$BK-qXYmfvK{E?vb>G zw_5u}=s}P}fjABB&Y2Bsr1mv4Z}SFZ`H=V$Ch+1BK*%_(LVt0o?!k-rbGUxXmv=IZ z*pnhDG8$uj%&<rew5fofs)do-!L@MJfFa#Sj-j%-5UFI(Kn>Ka^9-^}e2dVH<Gb*i z@yv{r5rbSJlED0)0Y#~2ZS2pRK59+NZu+2Q?gOFgnw&7Nn|V|PsXOA}C`p&>9VyU9 zij6OXH#R3!cu^okR_oFeJ2VG~acHaW9QFfRWolZT`R&y^`}5cb?mps3TM_2l4~{>X z6#(5~Dkw6k>TGrS0IXA(-~QbU=bNSedCgy$ZD{zgAQz2})!v;dXxfw5k2*_N``B;+ zG+E>zZgBvl<242PAi=uQNsv+<2~Eeu!@0XkgRIyV3U1;`z64S$J7Cibx!C&VNXR+W z3y4TN#%1t9nw_}!K$)=?qiCcJx7`Nq@HCA~o49C{g9rO>-veYm`~RtL#XWmOT{%gc z%YK0*1O&7Vo}3Np9im{nV-(=UNpA2B$?`mdnyeRB@*nTx-=Y7(@b9qw6GPj=BcVUx zZ{(+-viwht$bWlo|2g`N_>6v`Fr+`DU-&zVRoOMdHI4cX(rY~nB1^9;h(~ny>%kra zo`#K7a7n?3or%n}UoTS=oMyk5xA4Dx*}t{~g4}OpY)X?d1iF==(PxyXE}B%tiP;-r zF68+XR(z;WVdeU{Vyth62@V~7<5m4CWZNPPa}mQhAlH^vhm9vx=#0`{?fUW-e8(gO z6CpBOrS%%9hSgurF-b=G>Al^XRIJCls<bW@S1z)x-l7^-OOn2^2D7hhmJS;Ej0JdG zO}iD9*Ca+uinR#^oA;GL1?S}}8@4RcK)dCn*l1!>a-p`<mT)KF(}~{CVn*T?1!~o{ z9YH##cyLLR$+2UWN*JiQeP<4JK5<U0Zoi7iKV&X!Xj6nR1UOjtp$Z^@J`tS3_D7mJ z;l@537%5!4B=Tygt=qMs9Ngc-wXM=FVOfwqWF~7Nt|=Z7E;{6hM3unUmW5xqJ3qVi z+i@&%B*XIbDS;5TTIheJ1Oco@?rPvn!*=#cfy}2eF@#ZC25&l!FnH1e1H9<_7mQx_ zg-fXbuD`>pPnxWT+rOSHWwa@pZMZxQgXpa;XhUvUEGHQ7NX>REhRmhrra%ijU`wn6 zHBo#=geg|!x&?{??1&%a^1jK7F^Z0`O#X(fP@6kk$4qUr4-Vx-<Q2-{{D7UE_FJN@ ze+z_|Vw82o@=o`IT!+l|;*vM*JEyxu3^*AJM!aD;?FxJXi~AMo-JbizJ;Sn^DxYxj z`?&wtS^tMqT8<|9`&+DC&}-@w>Kpp#5$^s^-y35!$5$-lazFqOYk)Mv)UHA8^H+^> zgi=xEpTBc%{_@)Y4)Q+{=Z4q{vHnEd{eOe_e}@eJs(8`3p_n3n>AsVXMhji9K7bu4 z+!Cu#MdBZbj$gcH!EM|j<=XN}CsX;~c7^iK5Lf)EiL|F~r>V^G&m@;y^dC&RF+?FM zq%fpQHyDE+cyhII<crFNN&qETlfUeWEap$U!s#2HD#lOlV8(H$fY^>5OgAo~fX!iy zM(RtHELDC6>Lsrt6F@Rdcm@o%%CuejYy29m!K!YDOt5rF$0TjTQk<;Lqp1iRmYwGd zuHmJmTCgX~OVLj0BDBw7f#)sBUD4WlUF9NkaO1%u7{FbneYbSJ8uBA?8HX#a(u0jR zX+A(A27aE(9{g>_CCHAG=PPJghER~=da+w1TcQ1_SSRlHc0_E_3d;U+^FSD<qD8(R zi@SU+018abey`X`G{52x5Zq<DKwK(z^7@mT+P#E~uD<+r8RurPp&N4D;g&%^<ur=B zE^{G9ijbG;3->RBAG(3GHPr@E!_3xasRN184k*sj6pT?vSh~lbU3$5a>k5q!r50cS zCUFKP1i*l2hTyW{$AcpKGngbr!)2JY24+Z8<ue&ll6H1dTnA}`>6FU-F{LR-mLh&E zx7cA?d9hE!LOm~c?$fY9tV#52R}$ik!W5jEyG*P-HC|Fb^T&kNDU3{WMkgM6b}Q@= zZax$@g@kvF{=Q0YB+O`!?N)G|9Yxb%?gkJ288}4Ng)mi}(wTXQoI)_=)U3RstSoq@ z{v=cCitWXh*j~21fwl|v{dSna_|3>m=r`9>XH4dkn65O57074Y08g|agi_!F7Lz|e zOrh{6ZZNobL;Y9W@ONhaNi(KI8rL7e4*TEG%<+E%;D6Elm#@4=^p{<Mg4PEOMJPZ8 zuEbb3lfozSZ<<NossGEX0HW`Hl!`QK#-8VwIOd!9gY>UV&ZCL<=a<h&n6*=yAle_x znU#h#j-N5iq>^NmWuX=eu!pgPp;&EC!d}tuP-KI9k%IA4EBIPx&5_skyNc~^VU)K| z#g=VLW9Ft4DpiG&7E3eI6>D!(2~MiNXoU6Y|6DC$Ik!zogh|l4a4FbKFje9Zm1x$i zc|QBIS|a7K24i<qpfEoCn)q@gI_OlmxLKKGStOW5SZ~D+1`yWJ+|6CCf<B5}mRU`s zT7&&dv2m?Mm5*UoyG<a?miMcvN3?M%Q`f;aNM_^vt?{m^f1N0PDt7bLSpET{@lDVw zP`>d41&ZJR<h4LEH>kuBG)U;fz0vGdV#2@d<$dEb4@O&9hb9@t(eMo?EJL|+nnG~f zhWzcso@G@)qfYo+))kj4bMR-7c%=+Lv9(O)mjo1I&AFoioM5rt^9=BuuuK`nsu(oE zG0|#7^eLi=q;ZGjWCItCe~#<TG8g=|HVuun><prIam5Mo<+&-8s6u@>_u<4WzTNj0 z|4tF%;L*$v+7dSaEAJbR+V4(PgakjsgE^rL%cWGq5(Pup(8xtnxjK3(Wv2gpgDLnd zy$@s1^#~g`-Mz#TWfTa(Jxr@PO<akQ+K2nmW#(;iSaZ3H$CyfGy=@R>>Vmf1LvV*X zD~HbF`;xASk8IAgh%5BCL-_hF<*5vJcMJYev^VBdkI^;Gi;qA0oqQUObh!GD!F;6v zJ@Rx*g!kML6I=4fV0O9qAp4iW{CAN5iFnl6M8fiC-ozISARy8INlc<__gRe9!q!a5 z`Mb3ViKLUA?LWTx7xYCbo?bXAsKdSq*7e*i31Tfp7IP45C~M9MEO`sfY!>F(@u|gm z8Dxz?WC@cbE3Wwehp~4Ij&xnyKqt0s+jb_l?M&RU?PQWnY}=UFPA0Z(+jdUY-rslj z+EwSQ`hIj*SG`^R<LR5vecjh(Z`#Njl-JlPAPA-p7XVEi;8))buB8n+CxxbR1qMw0 z)H5mmIn{NS|L!(1X8QH3u~5%m4i~AOmv0k~ofB&vcGq`Y-*B#y1W=;f?R3OQ_-Ti{ zevXUtJz*vjJZ_oN+g@*>==jV8YPYnH2g=(&n<Mb|?w{kY{n<C;d%{i5e%yl5@tF=p z(TS>QnT=#{w@dD3UK^j(f7qhI{rGKlVc^J+URCqVoo-v*5<Skbyf%3N<S*qFuJ0Q& zE^NblHqZoy|3{KTuI0L<+sG{=9ocGNnfK3uq|Y_0r`eKM$hc-D&*6YFa0BPSL7SCa z?Z7PVIacaeosHLI<fSwvD=S|?a2wk?WPe_pb~>qqHS!I%kz%h(zG)M7lqFa7Cn*$+ zwpRLTx(CmRE9;}ng@uiIhgd+<yPt<d1@!Of+%mt?kUU{FWCu&(=@?B4qBbktCQx-F zD}i{0Df}=CylaWBBG=M)gGl`-Fse=|)Vqvwr_^4ez<>s<8i4xP0&GhDT0y;7e%c16 z8k}%GJ={5ycZn39VqmY9DkFL*Vw0$YsH!h7D*n`6nK^Lsc#N@{v$04xyaZ&zIHr`a zmz~0_r767qW<pu!J4AgBSA()JE&9S704|!ZX>%r~nl-)^)Sa;)2!eYK5{^lH-q~5D zCr?vI0x|H~u33_0ULmD*3^`7X;YZn@K%TkSJtuZfEH&+5MdNcz$C9};#nSm)CBl5A z?p!5du|n_=sYt9uY&>c<6BP@GlDRm=(*E3;jR+}EvNMOAyGD7*2_iYR**Zy!S(*o^ z%%z7@yl<?v%_5c#`#gE3iM%j18`V6DX-U<D#&%+*P4Z`CEW&f;`B2JddX1==TAr-y z%JZZu+*?LzLfVBvC=hsVnLja((zvUoSq!&@S>wY;7sk^BfNPrZ=d^^>UNXN{3>{s; z&X)w0)yi_<E|sr9GSshxGm6V_P<caO_Hb3NNJf{7w+53OGXoCkiiQ5bB-N?@kzcYG zr81y;qI%UVY=HJLb$2fKB=)?R(IRmYSuNTk(^0r`tkmWi?%=WL6BjdVErmP7opzcp zxKz2_&SCF~`YF5c<gGZ85iCE?rY{l+Ut%glaIgElT-4h>5d1Jb_TD`P^$g>w@Mk1l zX~ao*AKdI>)w2v=<vW4@`jP4EsF(?gu@M_=4O9)+5P1)I(U$sCLjaClen7H43EhvE z+L?)zatmBFXEuOED^3;V6P#Y=L%=&+q5NJ%@7{nV?u9d$IAhrsBMzQDSXcjVXrIC8 zF0)HGcH7!#5Wp$=_?qX!VSK~K(1AR36!S~=H3rn`=COM6L^TUkD-UK`%j#6QeAj!f zQ{wr4;Flge0B<VKbO^UYiY++43C<!XJVNq*7=-y0Xg{8Bxh|Cf_{}QwI5d#$+Ny!R zfZ}z@oTOf&ewj2uW{xS%xwe?~<`l1fxV65QR82<S-;FfyB>y3|K48gO^w=78%7$tW zotr|L`;g+dk~igKy-W)pEmb<*q7uJ@cBs`Mp}fRyYpSx)jEh6+PkNb2Qe<9JE5l7W zc{Zv<vN{S@C^VBg<E62t{Px`AQ6gCS$gCJHnRp&nXKU!-nMGb(z{`pUKxbIpOtPiU zP~)|R9L_W9L(*y*eQ9|b=V)bigEn_%Tebmw-YL^I&(alLYAOO<!maAw3GH3klzdbA zGoie+FtEK&g+Xz7mmp;C(UdRB%GU*$o}J6b)&|(7YcbyM>@f@!{i#C=*xkq02N=x9 z)&LmhUC$Oc{B5HjN@wShUNUFsQa4SYW<NQjKH!pc)lW#^!cW@9FNQ~vP(QNY;TxF) zhL;1!!Vq6c%;S&1b`0%3OGS!H@%XiHc1_XZwP+izUve{wRysP7^dHWDu-Lc~cw#|5 z<`wnq@!id;t)g9@In{Xg8C=M!9cVS3OI20%6gAJVL!z&1>DrO^koA6D!4v97<w!&s zCYJXy;HWJ{HaaoWdh#_72vH5<r!CTsu7-OT3~n?u!_%KpYzCEkRe`PW*iNY)=j4NW z{1k{rK9U9Xh!BY80X|O$QOV>0m~$VEgL=UDZ%E}dAswBAdW4WneQ*f`-h%69!g~Y= z3_{+~19zkgToO%r;`zgm0hNv8+|@cwy+Yjq0ek-vARwPo27M_Znfk*e5OM(bQt32B z0d>dfpG7w12>Jr+&wmQ(<OV-A)h@VL5Xdi{g8_Nx4(#nOpierLjO&k|0&=(Y^{6PY zQzoYh@yHVNh1<VVFvpe~7;X{>JCy^V$$g{^`l1f}j^qE4Dex(n^XUYNoe9FqZad|C zobyRM<%@FU3w1}V7E1dh+6Xd*)czf$B%FRq47oo2rMU$4;|5LMud{wXepB?1R1ch{ zTY0ljn;CVbL_b<-bHGko61nb7JQMv43d*Bu)*&YvluAaq7j~i%qDuL9LH+Za5zsPD zPF0oF`{ZoDtrIvtiWd9dqm#2v{g|ku%bd$HalBQRSs8!0Q4yu^b%+UsP=EMe<!R6g zm1;!H=Rqci7cS9;)riuHXKMJ%)gZ6$DBb;1x(l0EHf>>GTj`twyej3NOHVl9N!kB8 zIn$g7@f6I;NPZ<iZL#;Jzc0|I8*YJ|LFsB~U(4<;0%gzkOJ1i-I(1oxP=5$4wcopi z4r3cav8;)ZI?yug%HGkk5lt!|;u@k}misRD+%#haw8?^HX9>)f3Y?_e4GpdF@c=S2 z*=;QF;c?rkt?2{a;5kq;o}MUxN9U2bPikiZyy`jQx=db<m|kJW|9Y;{oLK6vFIhK! zd$FT$GYl9!4t-TG#;XtA`WTGKgw1w>`hj~N?-?`+B0_hbXg!2+UxFN|%vq+4J5LpL zviEY?#9H9xVA}%`CvaN2Cs(Nqa3f_K(y2t@DbhjFmE5NFnyMub>P~|lZY8@E8vZxY z{of0w|CCaH;mq=1U)SHhx`o#-)>pcJDy4+23>+Q5nC$_7qgcvJuvSJ^L>>H8p9->8 z7U{<y%TdvgC@GgAqM`JhVj8Qp_i*+{TS(G1)uh%p)*s%;QC23%L6~=P5fthkHVp3Y zoXiT@e9mrry<J@VqOms={RvYGp$No;KrW)wTMiLVyd&}JYPZ!7hqygP)FG?x(#G9x zRqt{s`cQPOKL8>eI1UzsN>#mr3|w7g!`SX?4Y7x@zU*W~t0F^rOr5tlw!h0_ucdKV zc7B5+(&l%88rGg_FD<!S(4n*xv2DU=u%0YHhhc(@8M{iYZjHL5QKdraUX0GDrO3SP zl&!LKwM<E4*JOm1Ky!WjvIS)xQmPS)omP21T(V`gk8lreU5Q@{wpW)5lT^7Bn~kN4 zb>zv@1QOTQy2)W~17Oyp;uQMUfn%X~s5VZT+)r<_dYEtobN)v&%Xct*#N0^S<L86I zVp5jinjNc#+Igi|)Fi3RVJu^SV(^co^n&=pls{KaY`C<GWoil><v--0P7*l!wqBJV zL~X=}wSkq8FAOBRy`d1U6nem9m?B)6i!HytDFb8<g~c0pg*ggKOTQi3k^U#auNXON zn@bY~c3U}%DtIb1E4@I-Uwf`zK(|~G0+!}Hk3;Jy_j%QZqGeTtL2B?$@-)wo4Wfq; zJ=Sx=ym?gO7wQscVSa2D3BgukSRMwZDM>LGsq7!BDI+Yn*_vy-R8Zwo0I$3=NUThe zxXI6>-`fH2rx11W(7J;F4sn{gifNE)2B+DOZ@Qvdf*{T$5%#U|*m9g9xAh*!UOJ>- z8g~$|oShDHn};9pi%FxG8=NAa=^B>bx6bmNA!~%)9)_3qQL&tUp>GQ#3l?Mu`HL~j zY{h*In30o9-KxP1zQas=^!s<5bjz@{aRo?zz#ZUxQCT2{9?RgxebVY0-c=ddbrlMN zFi5+ds(hH>=*1xx;k6s1OiF9LR}l+mhFK{O6DQKXHxaYYi9Vz;9{VcvVLXzZTrKy& zX48&Q<gJl}O<E@$CovwAlX-(?G!Oj?-Timx`ER#Ed|(ET{&K74uO?jSpWMpG*2c)$ z!NJ7Fi9yJ~$kNQg*4f5b(#G7$+`!7*<BRV7|NZ<gelryVN6UYAD-|k|%70O;>LFty zlatZ{i`o78C8;4MSi^`4K}A^#?IsbH9%4F^2n)+ns;TiNtk)n_f0x67@Il_R2qLCA zk~h_RxBB9J=~?CZGWv)>05rCxh@6QjFW9SFh^9oDHx~&dW05k$Sn-F@Y1G@iQX{JR z9Hht1MEVSx1eSJ{QFjoQPoCSqX3Vpv`@U>uwLwOc+zDKEbaIm<fu?eiQA9dLc9@EX zr*apk(GI)L7nm36z@^twxVZB~!=KFRH0Ta>ETI2^I9KlpA|pJO-Ubm_+C~?d8ErK7 zbbF%c&cblkR9?TIEvSQtS9*DH;-^KN(YY3JwN5eln{`0v3FnM<ZP2CkMxBrQ%X8fo zZ|YBOjGiq?J%|eZwX$S}W`*C07{!xSBmGuA0=aIi%3uKA)wMX&?rA5sAMI?@VVoiy zzb=vV1LkfzskEU77wxiR%C+FcL30O1c%Vfq#Z!2~-9B3An81PvruX_(=Hd91D>cf_ z*IMvoX$bMwr<@Cz@<~Dyf;I6FVrH)t260UxKkt7*F3-LrihZsi=6<?LRUEf?nzf&E zA@6`W8yqr>r$U%D&<TAIe?sPt+6D`*uRGesXT!ps3Br0?<Os0;78|pbj(9h}yGk=S z<yy5*N}cH=D!GHNnb{-Ssai%8Pg=xBD{?12X7VVB(0hP$KrUvyLnE94ZxMkNE<c6! zLd7waY!1UEDN$lrRw^u#vK6q6Evb(14X*6-bV4N8tH^Yb^$FW*#RQcQ`RTBR0|3*# zL&ehSXFTOv7}U75MoHl&=Wy!Dr_|lG1--7qTwuHj6fQ7Op<C=?;)hxLWq~Art;Sl# zRODT-F2*0{%Gk}^@5%kFdm(;C@z)UH??(S0clZmq`?#2O-SOoHq+e*}f8-Ybn>&cQ zd^v^impeEKn>!den>z_Pm>5`odBpz!#0n#s<i1GUML&O%!NVv$083CQ4FYS42qs8S z5kt%U$e6B7*2P&q#f=I8v7_uGEmbxVyA{`e@%Vhae1+&Hu|Z4dfy?zm;L_4-i-LOm z&G%}6Rr@QPy=|MV_Ia-vFus9UL}S|)lTp>g%W6=pfUGA}-tf%aXkab836bq&=JifG zv5K2dc+Yk9=5N<@owZxbLS;{^5>iPb*yUYs1<`X$hBgoT6G_gI48|U;avuXTTy9Tl zc#23t_TyiWqrV@@e;-#Up?){hSM<>N8vUvKAEU?r?{NtOOpGig|B{YyF|hj5I5hZo z{Af^;wVf3}^giXZN69FHyQ9fP%n>lmN!pSKLM)Of6%vFlo5M*zr*__5nje_(-Nvv3 zf+Ce7<M-I>4&r&k=qpDN1sj2C9vhoDOXs+C`R?oM3c5wE29wfL$SYG0a9r-02Yzm4 zhqK0oS;T~PpzK`=k7G3bAsbw~l$f^&Yg8J{3mDWn?g1CJ8Ao`3f){SwSOZuwrRdd@ zU`f$^Pe_;SBAG|ofTC2k5e<OQ)_H#6l}o#>{Qe{5KB}o}(rDrbN3Q}k!&abw0Zp`a z>`ALv_AF`Tua|d9+-4wzwx%Q0FcGS>CEe_?^JghiA1`^yjd+WFj(}CxT1+~PJKv4p zONrMnOhC-{;F65unwOwxB~sjb?+TR5$uB-_8&+>2=B~y$&Q!=%M|^v)r9bcd?sU#6 z6@~b(8VW{zPg+|CL)OHQ7OnRbtL?w|9dKaNKV8&t!Zm6Y1y$o^S;hc6_4%(Qbrk&) ztS>Z{zQPgM-iuT(^WY;M1Ysi{WH;m~rsUdrv+T?XKvEM#Daw3)+jH<S?wLYnN|=eu zo+)P_H)kY~UOzQQ79k}V%O-)$S>;)2Bhh~i<)o<L%{K2j)19{aUmMQw7RR3{uT0_V zVsaR3<v}f__^~kf0{L<wd7+OQRp*oob}D%XgJ~J9x`$icQ!TF%l^-%@s;i6_;1%D? zozY00;Uo>6PTZ2*8Ban_6nbVAF9p=NEfQ0~>PQT>{$km4UhYH75ZnG2?&9x;`5%-0 ztB$1i6V+AyqQhN9`oDX)th1Gq`Tu9u`yUfke|6OENBdCgoJrhI@2g7Tgo=a(H(u`X zPXKP*<&A)1uaQtpn@gC|k><FO-J^Lt8L>YK<j;k(2B9mI)vrgjEAB-wE@~Jo5MD9n zK2C6XNt?JM0DOj+etTS<PqgX}cC%y7U+(aHICGtNemGm6&))F7rTgZ(+W?vN;{-FD z@LL`FxrDT&SP0rc4W!UeFcW_6+JZfA1Pam|k#-0!x$*8CQS>mk7kH%=G&gTcJLPoI zURk^YCtbR7t-BKaixnP!h$LQiRj-<tAiMl<3&Y7%Toi-&RB+YMmrl_&8=gE2rf`%| z3kX-8LNzq7HA#Pl*(KX7MXgQek#R8YYTbCod%-@x1sbP#X7F8erZ%_ma`5}$I8|NS z(Q?ZLl4GrU4!emN-YiXPlAk8usyg<848>~Zjn3-u!^LFVvW?@6Otkj;@mrtB235&3 z9xm5$-l<m9Vn?2~_w~ny&kD@_GU@}&Tpu?)6aeHog6zE(k47^Cvu-W$KqD${;QhHi zmB+ZX5%*PS9H$AZ|3bCp`U7=3GHNMKBbgREqj5%*;j)O<bwp0PV?;b$$bVJ6N$5vM zs-}hPmcW?@v*yh(69uaDs2>*v7P>|_lz)=NhrDdkV~(#i7hyI1zJ1(t;WuaA{M}RF z($kUHdQx-d+9cO0+6>IC_F@Mc2|`9w76e^qInchCC|gL8vk?n_nR25@ss*2M5GnG2 z8S>i}a%)+bwJz#-ki^M9$MtN-%kCi(0df!!c$0i&)ip1uO*Bl-PE9&kPSSMy>MmsK zI1U$=EiTqyl7GxDYf_#T>${7^<P{>?zEx$F#m>B=Y2#XBJEI~cl+|&*$~mbm)nhFF z$qNF*k&|@8I;4pVt>&kK+F2{smt6;PSegFxq;6)kaqlsjm=xRKhDR}VJfJq3dj^!r zb+x88(dl$@v}CF|EW;zH;{@SlrxdMj<!eVGHCv*Y?HG7<d2&q2mhsJ-$j#0_*vd8s zum)<zz|>GCwG2NmPEK%6OL`1tM>SJR+{f}`1I$|W%JU<+er$2^+HUbYRYqaJdLb~> zQe!^xPhdU)MO``h9G$aQV}LNv)Pei_BEWj8vGNJP1NWic*6*2gdeg}<56TB@ncy;A z!7R5EuQxvmlecwG<77H9_o>72f+j6}G+^zbb&1(tBA0Z%%q3B&<pu8Ad=z}nX^{H- zGB>zkKBQA^zyUu0-SYOEmUi1`7dkn;J<H-;Na`RbQPFkQ$ciHT?zVI3CazAW)=(E( zHnk<si`a&Gk#7H1Aj>`b!8ZILaSzy_4cS|IeutUn1{sS3M$&R6o&j;5ZJ^RaX`~t3 z?fio1Btey2f=~_Y*&m^VoSq<~NO5qC4ww~9Ee?F1sOUC{mw_rg8%{Ne@}y!#t`H?J zG=y#=$-oCUE+O`{Jj1>U{s_Cbft(s@*Rm@!+Sku%#9@?wLh)PX+a-~)iK!<AnWthe zLk>Sb1k(5D?ju|aACU8mnG4glEbMM5z|aqnPcy5-A<BwBx^Gn=K~24bIJqu<-oovU z@P81#WeCOi-E)?H)0PVN5_rB>Toab?kKWdskUaXd(~WtzJ2WZhiJk)F^M_moRo;}S zMeXDdhhJ-oOh_551M-<doH2H~f)|$AqVL%_Gn!cgC8Cp>=gM?B#rG&(VnHSQ0?QT? zqU}YN_{XPN?jBhsy^?%OCKO(|*8C5T4`G&u)A)a4Bz`KQ&D!;U8mxu9qDl512{N4D zsRH8TG8688a|WI+b_AN@wZR`Pc?Y#AuN3pKjuT(jy)ctuzn*JlN0{K_fF39^F!q#S zgHG&_`>;a4!OITQg=(@AoTqC(T_!Ek05wpa=n+j=jzwS{{9y=v`yF<BK6U*KFVVp2 zu{Wk3Ar4*9zO$eqUh7>7*)4g&`K(RIfmO3uS{qG*If{{OBPu#dCxMHwBWstZHvB9k zUN;#Tqgj%UBr`mg6vc<MiEJeH4p6Z|YttIBqE=yvp1xOde>K+A^<FOZ;vFrPF^+5& zE+Ajcc0>X<!~oXNK#>4|8{ahrTJ{$CGij(zMP@oRliy@v0=Aw^Kb9@N3NXu4MR9E2 zhXb!*LSSbuk6bEvnRQEK74r@Y;eu%&p0-V0v^8MyiMDPYdTagZ{R9#{U{Y`;j@z^9 z2J9<_?n~68A9{_D_ZFFc?V2(8z2!#VLK|P4&OV?oanKbbZ64fw&a%6AX|jTIJQDj4 z32C~@YkDKr;TziORV%kBkXCv((1-<qB{2F{T3LH#GLZ}>6AgxkOTEWCp^l7|OS?xx zl@VS^o?H;S0fsbRY>?t;nw}BQg~5(qz<)yHn*PKY*EFsjgg>1B`TNh!-ti2@E^nA} zTn|ZA^Jhc6eB|RA8bEu`H~zw#6#2&&h!hj?w}7b%XiyDPQ~Oh##1~|xo_uL&)v3cG z;9g3p!80f?t$T6%ww+4wrr}*}0yVHZ_=|3}q;}(yhtIzX^}i?U|D^H13U$IbeU;x| zMLPc1W-|BxvGV*&`o~z=#M;0PVC!J=zvX$RlB_%q6QVb{KiMd{P>w*Cc|Q?oXraO% zpgu6PQYEc2aC=vm^*+F&m|nWRN@<7MNl0JrU#oV8XCirg?6p>tydCZ=_>-64Il8`` z?TCUnm-nX(1Y**-VQwq_97M`u99zmQXLrHWb8f&YcndQVjx}wiZ77=w`27dpo!W5# z(qz_AGpwCL%7<-E3|HwbR%HgC1-G68X{r53N%oNrBdt>*@}<r)#zDp-jF6UY=Jieh z&ha~w#v>RDsci!CLBW<P+0c46;q!oWS(j->UfnrNsOL(mOomjp*|Gl316kLB%ARE+ zT5FuemD*D71PQO~73?V#@fbNECvl5QYi>gF!~pQZ>YtKz&md}A3gbEjQ9M@y)Aq?A zfBBo1V<A5{cYWgw+{Db}+Epc*)lvP|+ngrGhnrl<+u5$CLBT|gTs|w@i(9qnY*!k& zRhSD1Q?8>iUi@WjbKN~&`7MgFJ_to_eBQSQsK+5atQy8>azxsy0RUYd+rkP0KjZ2% z_yb4-PvMey-Q=&O<ea1kH=_pZBw$CZ$Ky)nN>$pQlxaCJa7}-i#NYq;|Cq#Il^yaQ zKuN$?BU1Fm#4hwtCSl@cWMcOh2|I(Z?N__u=44{5^wqt6S%>KVKKY-ki=@%N_SXlx z=6l1*G#k-YQxJvxc+VQ}ka&oQ(BVS~VhDK#9L{*ZvBa_8fb)%AP!9t&3r`5db`hxv zqV<`S0NW^Ja606M@wi6$UrZa*Nz>#@HQ!A{y}UZh%TJd3cwem}d>e?3%t5&2Mkj{+ z(TU<|7i)&T+&*kd73O2SL|fO=XBsq4oj!WzKqgfC`^_U!d~vD0aMv2|@<?NLYB!~k zER3e;TqE(O@RkL;9tOL$h{j|P&BRp{^|xutj6eHFi0sF~c}B~29D{rFfwg*Xs8c^Z zX@BrgMf$K#p$f5iE#*j1Xu)AdhINdr#gT-j$!O*bA}+SxG-6uio-EwD`EM(F6=}^` zJ@jSbanhMYToX!4c@On?BG+{XR+$DA?I6}$>G@jAL>UGQsXSjwZ{ammrTDStMpb$l z2X>EPCtSstFGUMh*oD!g#q$w5Ice%%E=6aF#mm#&KUbkk$c+n?w<PEOI)IC9eisv+ zSWjC$t0Cl3e0TMb80#6j8~4IEyj-F#Pg9IKjxk(Ox3zaD4ABMJnOjpjt2{1nlf#sY zi8Bvq9<vfv_?L4h>#`HAe&ZE~l=;*eXp?O<>%0sL;W!I9Kp3NULU)D<51c!mjqF-W z!Nxh*SkiE`dJN{xuxo`m^L*=pjdMPL93#l2cxAbRswJUStH_;&GJXS3kcFJWp~QZI z0(6)7XS%Oj^Gk5>dz3oHGi|7L)+&FcX+J$wa%-O@!sX#-S=nHuX^@det>vda%&U%V ztW2TB;TTtV)$eyY&o@elh;6L1MZ4BW36=wAMY`5VAR{;IS4_v4aU^!Jh)yC5L(bs? zRJ|yoAa%o(o>a_<9UWMfl*nzi_6d5FGu~XHd(K1E-i`AcwolG$$e@A;%QX@>PcIt* zUUB_K{;3XWg3%7l?s!)Gf=jh;@<e~;bL|nv6$^*?rEL!p3y{XK)2AXXk(z5mx0)cm z=~N+x28Ka~NI+56o8_4NG-Lx0uYrBhTK2*?<Trpk9<WK$AuoZ~1TZgAdXl>R(<Ff0 zoghP?hL1>mj-qs@2oPU{g?#6L`F<J%v7^2)A8VvCiivULUiN%o;ywMubR~Tikln9A zp|-}iPw<Oi&dXaPx<urIuv8rI5mN!vVjNH@&xv6B_R)4t)&ByE<Rw?n0ARQrNfC?O z?#I0|gfIJ|q$%uxH;fo~pZXvYkQh|Nlf+{<;UwpX^w1@1EJ-5Z=oADPJHg0<)>wG$ z)A14KJ_1&|%C%kAq=}+-se?G>w#Zt};wz3beeMWCKa^LUxJT}cU$8uC`Kgb!e}Ps< zUc}VupS%#B8015HYI(@d{Hg>`bRc0}fql1DFBwpe7`bZpDt2bJf?=u%z4u(t4Wm?} zt57$Ox}fq^QfE1yOe!!>%O91avlCK7I$}Lq8@$YKL%LJPE1Bgvbi^ktRf4MPRD5&I z<U9*KPO?_q$U3;;2Pkgb>TG1ydF9e9G0p37XO_JlS%X$A?B^{CkP_Gu$=4GVU*pWs zyfge2@%|py{uA;3N`kbHk_VDs5zpvL{FmvUBA)fvID|n`R8*9Mjn(0AbCC+=O?hn- zOrOq&`r?elo+%<?02SDZ5~Woy7Z#30X#!LGH%U-i_;n=sti}R9w$(`WHceJ+2G_%A z5t$?b7q*NMQ$xd@!cRZ3-3AW5)TiC&iBc1q>N#WU&PUHKf<y1@L(k2_kgm&f5Y9+< zIG>0TOt`IjaD)j^JGK6lU<`XX;jb(1gZAKLrpoOA9l5Q%yNS_2=^2@keKK=$RT-!! zh7_>bPRgyw{$#L(;~iDu9Fq-NOqj&CG)1kMMcRw{aSX@ShVo>YmP#AyhhR-~%ru6i z1?88dtW`#(7DIl0+63h!J&o`2Bc~5y)I2OKjy7jj$Ih$uBfBz*95BG0OBUQ&=!oRv zNtPWdGgUBdYWw8kw|NzZ8=ZN!s&&_aGQ1=VQ;_h!w3#l#N4S=_T<)Xmw}Z@Bhph|; z6C3S5k?QPV_5Fs02`tP-!e>ZMz3DGJ9*FYW=KjC#@bF8^O|VW|*;KWv_96rL9O=xg zmQ7=6xs%x=t`bD>C)7t=nicAMEybD@YG|<z(EME<S&K2s%*1>~JNap+JP<z{8e~b# zey6|_N2U^TBPE+Eh?4(OXZlV2+fc4GIZ$GxmlPZf{By7kCL?T|z*whV+SI^XXQBOY ziE^~nL~q`@Gj5ZXA(7f?rzWviQSI=wl+&MpIE7wq4LfZg%-cT`MS4&jR0x8j5|Ih# z@&}0#nzQ!CSfBb-@4~(CM;ei_J3!t(afg=k71@>OV(L04bK%m;WgBZH#}f$8E$LR4 z|I~3l+E#d*AVtC}`k-pdJ%8L2W8}T>gRW$R9o05{@)hpQQvqdTT65pf)$mg}L&hl@ z{)~vxvzMmv^V$1HGElqR3?y*9eXtB+AMpJTP;bnB#6+F}_Y5^)=-ZEPSWda=__Mq2 z?cFWWh&=8iVRmQ%45%rnzC?RyzHv36_@zLPt@`ZWyhtl#oLaiu#5^9S5<0hIyFFb` z{Nz#G(#%<8vdL1ofV*Ud96>wnAe)P!+nd07Js_J0fj0W;I;pQ{9fz2+j-s!jcu>>U zTk|?JrTZ<9iXjGZat`g=G5PwTaH@j6e`^gzeeeOAN}kqJPVX*9L@3}b<|f3x$&@S^ zgThn{)zyW`O}J3_h|`&gvlWvTcF&^PIgpoenYj})Ss*=^C`M&+lV9@pi5Sh5ps0Sm zIabC>Cg=~91hSFiV~83f2qGV?A3J9bMUBn2D-Z7RF}r6Y@e{@)4DaQ0lTTyEe~#=j zw+w%HAu~hbQ3OU~-Jm@5n900wopz1eyacS*kK44qOK`y95e4oU8OL}LGXuEf!1a-z z_=?`sjxSNhK!D$px(N`UTtoa8M+u)Xu}Gtn1SLiYRTu&ZaFPUT6|w3UMz<)~CnqDW zVA2oO*(Yt`MhV^PVYMg&lRU8ArmJD&B1g82Ghu)FQDX{H0?_#Dp&A6SAYpj`%Kt`s z{yiG~cbp16wF_MS8ZgOxQ5*kroN{*hiyGvAg{ZzRga2KKB_>U}qNt({URwId_{gL; zeofqi%9iTUl(e67=?V)KU>kGLq385v;)o<AO)Z##ChQLpbWR4qDs`TW0>57Y_T8dz z*Gr{!PxU^5blu-Nhet=9Zh%c<-QzhPeJ&n1TsPaF@4GI)Se7^wjZlj*@(QNI-)yMF z%#LxpXa^aa3chyrbaTR)v~rW5#zwI_dIr^>_t_%p&5apPD$^446t&oC=JTvGr3uXX z<d{w}>MF{NG$v{l%TkFz+u7^h2k^vle|rIonTu_g=BYXrVS&Z<jz$DHy1>gL!-$UZ z>e85vjcAf6_sCoZWQsz9_+RPEfM*KTi~u$Rbcc&0*hsV)l{MRR#MV@Xt8Y+B9mcnd zO8Z|@8Z#uD$!2*M7WR6|?C0(1l<$AUdv!KBub8#(sf4L@_G`$ngk?5ou`S}F=9ei3 zE0WqSgm-iG;v*a}-O_(oN+h4oORPvSnRQTrbeqs>adHHA7FrG<%O4?-R>sU^WkMNG z^*P+l!g{VZAYgRh5=-kaRfDA&be?0D>mPDJ#b+CH8=kS23VsIg&Cr^Oh9!*^7;C%R zBdi~VF73xzbB>p~i(O~v_Rg>#PVp-aq8AE=q*N_ND9vNM$(YWMamV-4*wwK7#=#Kc z6@j7W5_=fQt0BiGS7Iy+@(355rnD66=e1<PmgZN0xQ-BRRNguvj?&e45%b1LQezKP zYV1mid^Y(mR)nleeL&Y+s+#j2xS)D9Hr5hqU!#nWuyD6mG+wL)CUe`V|5c)vbLsCj z$gxhpwlv7C9us9Y&ah{~PyZ6r%yck5aZ3FnT7^(3Qxq&FuCQ<l@=SK(76cU7bdhHU z1DfPKkL^`dRSCp~$AeAkSEI9=XiR!zwKEmvM+d}w2~`rqZEm3jNdOn8S7Rn(tJR|k zwjtXO%y7kocNvahUg?0mn(6%E`Zmk9cY~Is`aDf@#HxEvX9Wy0yLHL+IpHNOH)q!= z^tWoaW`aK41>{A%Cl3Eu1K3C}@v}zDR+L3du{>|og7>*-o(>z4Ho!L$2wvK6x7B-% zOz@b;pGn+l3G~og9*7CTsD-`s=GyC8F;95O{W=FWe`H`xi$`&Fi~WFkV9uBz({F$9 zkTs$#@d5MvGJ`(DgQl(y@6G~$kkLLP@#7DBB^(&M5)Of0-_1*jjkPV=g%9eCJFDjL zomL+GRlXlnzF&`s`7mG8iH$Y){ZtVxsjR0qShzO0E&$ECLLW~(7<4o+TuMh}fu8Dh z&m1*mG%8w0#O9AQ^cGvhA|KX(NpLSKF=KeQ-73CbZYlZi&m>!{4Ut;g+~~~*$}^;H zMBs?9pV=`-BtiyxlKX--&nlfE*WS@1KUG?)bZfapYdM&FN@QF<`Qpb*<K8i;yn)HG zHz<}>+Ke5o<2oX*Elp~TYL5?oj(F6*mnFUf?dnE1Hd`ff@=?`C4o{?Gbkk!DwaNFt zVR;^7Ak;}Sw{@2{ZMyNqmZ3ev?Or}2arq#`QXdc?J|B9E$W18+xGOQDj7ycF?=wXB zdgeeu$x7s+I0*>ILjf*>Ey|id1<tzgZL0Pjq-r1vmu|PfvB%vDO5KvHxHMygXhopV zU8X%x<dD}%NI6#Od*NmfyNCns*aBIZ0iktZ_Ae#L*7tqK@%Aqw&<e!6xN)mQWb!p| z&i0$FRtoL`cmwoRJkc$T9}7XZJlU`9;(Qwh$M3MRQnm|so!3E=uYNP0(68!9uj>rn z8{&x@vthTUnLQPUaMCoB>G`ZAZ?g7cun`|3E3zvSq7few*Z_i9^tXrre{CSW2|u&U ziTD9}h40$e^(%fl#Xz{cgMQhLqM$Bgc6d%+jx>qNm8kp(LAMc8zuSb?S=e{X%H55R zm6D>yxwe9R(6fO?X1PzQHgGEDPqTv3ly7Dwv#M>z4f(0;0Kj?3j3Sez->#i!Y;B>d zlhL)pTI4c6q9cJsnRx8TuTRarHm<Ip{|%r1dv^HmypeKFZNdC?!Nd49uldK7F6;l! z8}f!0CPx38I#fn&W(83B;zKgQlf`$F%-j>yk(*?56V#=F(5TV0Gzy#)q54QQN~H~x z`vifnvAjU6YQKes^a0lh@AxhePb>|v!bzO>IGSCoaXn^un!W8VCRcr%*cC(f=G+WH zC7(YFh@vuKDBD&7PfqN}+bxSS$72EZ)OMMTy+><XcHn*d(?bVjFP`H&;i%o|^p2)! zyJ{|!e(-Xd4Sak!Ld00zOrJffq}$ps^FGq5dtVIpG9ovg=+idrw|B$Lw-WKC5KEi< z+!H2XG2z+M!51E7xoOEk?c%7Zb^?^4P6i`MuOmK@&~;D`N{-%PT0zQT>^x4d+94J= z7tj}9D7LDeTUa<XAQIfVt!MS-pRq!;0INENY{$6yTODfV238?nW*pv<?8gDjC$${6 zKBQEfd4Fu$dpX@{#b<XFI9d#U_@U|o7`f|6M@h<KvbUypD=9}FwDE$mC7l(BXRScU zW#W6$?m{CoLPtCKA}BV?sJbWB#6xT2I8(V5<d$2ZgB@IEvPF1#ok`Vt`O2-F9apPy z<Zlvia3<p)1mLh^JFVSM6Bb5WsB$=zJ%+LCE*&;MP>sCcwZWkFn!?9k-lb(Rj<ThG zpE9c_(>?Gns@`>TMWT3hdrJ_8>*6B(5%>=3a*Ib^9YPS~m<h8$?lhr^5cPW8B1;39 z?Vm)v<dWR^Hb^Thm`D||O=u>DDRR|YFW$=ATMvChIY~JLUBR8H8Y6m2g6wPWIt#4a z*HQAp1oWVQiD&RzQ{qWtal@|NY``$e-X-Ivx1Ga?iXg@fqj(PZaNK$r(m?!(2WwO_ zau1+g@RO`{v@Sf|7*GRSAs&oAI^|(}6)cK(Je412thpI0=MuJnQ=pu=LqSUCWBWsE zGe%1ZTm0Eus5SnKkryonTQGQ6xDuaf*hmj@cvNA31Er`@QGkxnGlMFa>H~I|+Coic zwP%@r#XyBWN(mTRaQKVaHO1cx9qD$y1c*!Yg6D2ed&A!^{~_66DatH;CHB-@ypl%V zaIw8-KR*11H{vG6AZyGIpJJqaHSTD>NW@g0*io4n56VbykTWsZn#zE<`q1ZJg0X-1 zy#Mw|8x<@A8|ZJ}%yGU@693e5DjC?A{SV1og@&b*$~@Y~L_13=FD5=P6K62tu#6BR zl^_&U^e<M#05%}(Yv*{KI2;O=;W0dsRg3<z1_bT7Fh7I>XlpPq8bOnW6_<*cd4l)Z z?DLaLmwVT?m)`jYp2Lk6N0!u>C842~*NnQ!jZL2n@5k}W&-Y;lp!yvPOnhFPKF6Eq zb4H6RFT_o#oi+o|D=)~+_{q!B?I1)S!tC#`z0pP{fbMV;-diOuy@6=b`!L)nh-(W- ziXM#!Bc(k_u8g=|O9wZ;pBw>hED^JA(i4+I+k;Bys}7tbqU|K5b#Y&C9(kcBbI9*7 zJL`lKFto>V@-h}!)|92I38@p1A|6Uqe6yKzwVHf13YlL^YDsHVX0>A64ONHqKsC}i zc|4gTX<8#|Rb-B>1PkAZ5b<4xwHA0P@fNfkiejy(j*bv1PdUVt(^5x|fZ51W*%4r! zoMKrx4GJPc*M17j?MPdcPA7E;@4i$ITQe+^#=G<xLPwe}*Ie8|?uX&ajXQOvGAZS= zL~C2}9x(xS@Zc&d0+hM2J!ey=(XEwm@MpCF3!t)UGS+mD4s-4sW~F5(Y)T&bHii<D zutWJu+8!x-vqwA==lwZZa};+8$DBnP`D-cm7d69g%ev_h?AFxoBR4AQAOyEW6Fko9 zy;k~3@bkc4b}>Vy;mU56D9b@YaPY?m`K?*VN9iOopN?15@Fp`Te5KpQ^p?0q;iKdA zmW^ga@Sni^UA}VJn=zEUoUW)gGK9eC?nvYG{u7^rG4Jgx2Py5&HP6=2%a8jHz{?}I zwLOsKnuHf&KFT;g#?kDh^vJ(iEKLzHKu<8XaC+dPPY$xY;Iw9@G|Hf#aj;eKl-i$_ zRQ`mvRnt#qXX?UR9xjcnRu2t53|o|vJ(`L+{myd7!M@Db51yq`W>IoFnnAXYr3F&O zk^qf7YZNY$quduu(i={B8G0Dhh=@Fkn)@Xh5^?78uAsHBZ?U?Mj_Xax7ZR4$4vmcF z&Pfdl{2S*WycQH)F5SpufPaQ@6N!hF7o!HQR$dKzxg+FWMkzg`KB9C8$B0D*hswb$ zG_9%@B$$i5+S|wP_OMic+f3rAGA`dmB*)d?l=kl7Sec7%nDUh+iEiU=s#yy7_#+}~ zoNRpO&S}G;iET`eZWuGCj+_<xgj!ejp!GnkwNSqSYGC)llXfk8!X)^<4et2@nnrm+ zaskpMPyNUIeMM9bg6IBKmVmCHnLKl8w8gM>>U4(87@m0Wy(E^De|lKtau!P*2{Snz zPdV+xK!l1+IMro8xq~K4l2m#P5ns{>S$w+Tv(zlspVwx}5b1Vu+2?z;O4}X|vVt!< zIxhZ*AAB}uSfN|YMI=wi>>|}jH~>u`NdmIXcr~uW04)=cFf7eNo&d$EEqktrAtIQK z`Y0PZGN4*4%n33!<>(eijt9#4WblHtS(lz!<JCsCT63BxWkhvi&ai0Wr!<voMEs~N zBQNAXc+JZ2@)Eb0?DjEy)2+^=_&?Ya!zu(;?~T;;TPt*w$~sFyO(WrkXwtEf0D1~V zD}T-@cP23kPOli~$g;l)@p-?4tiH6mLRzI9iY3*{vs0_>N<&oWPQfVYt(_P$0=p&& zxY-ejjXV~5?G6p-{<w~i%0cI`<LLsi5b%4u(+CAkli;Yce*A%#$DGS$t9r{mkvcok zo_QO|av*MU62ni85;D0@*=y?LP!(Qh<2DQfx@&)p)F&FJXSI!~Fxpm=Xw+x;huunD ze2wP(BwVVjRT^r;0ES<H3t!qU@8=do!j=g-Ouv;vHksgR;{}%I`Gj7&(c-#FBZ_`j zA+6#_SSi+sM*>>hil{|VEx!0Ny^_00TVk!Awq{y(fFA#7RSyfMJgcsMlg4(Pl);!` zzQSm$1N3^%!)RhAeqn3({DoZukB;?Tt-#qfLwE(4P<deV_ind0Xs^&s;w2|I%c`F5 zZfO30XduOeXDOv+NO0*WrbP^~V`)mB>YuTxcL;KBn9C-JP;C!bK8VVYWeM_EU^cN- z22ql0C^ww2rX7u~<4`I^7!=dxmzPGaKn6KIW9Otro}nGDIPEiYM2qbh^o&IG%&tA+ zgKk)1GZa65Y5%fE=**+VqbS~ww!e$Np|tSJx~85)eR|}2JBRme>)jOlcrQ>Vz9Im= z0kbFkRaN#G*nI-6FPnPa`|9>Wc+mvX63Id}E)PLV4ZjVhe(-8Nw9caTz?J&>Z4sZA zid~D=<pm~eA13GLQkh{**9Wj6TP2)9O1`r*Z&<Nbn2BD7=#(ow|D`*{T2k=$W>%HS z83k+0rK);&>L#gjFUgf9{l?3~mp-<qjziTR$>QG`x9yQ=&xrtjm~cUrGVL3Ri4Pe8 zUwhr7dpZ6Jb>}|s+(n+2I=y+M+;8ApaOLZ1U27rD+$V(IBVt<G(8rdJ-7hp|zWGaC zZ9nF@t1Zm_lsW&HNB^V646?A)^CL3@WZ^sKD@FguDR}RfmL6IMKJB)@yc-hY2M(;I zmqGPL3Wyq-fhvmH9eA$?s3gvUJ&qcmfvQgb&Yz<=8jTn83=@xKs3*QdGG`R3O?Qk| zRWB^TzF(E_iFx>=eb}@ZO+@4id2+0+QwuzRQ?uL(*QtfJsT)zXFU`s*6djrCb5nnB ze|h)ni3fv#W%kH@3dBTXmDv6$9Wj5zbjXIls58<z`n3@=Aj3?M8u<8vHN;cgUk<j} zqq#J=A#(O?yFW7Onbgo2k(X+BhAzl+^ngzsfl3|xRK|go_P>=n02ySX+T{*$Q*Kl% zvT9S#brg8Y83svli>jf&sh_cSHvGC4H1zs~$;NH{OAbd2<rsLw6vFnFwtXCa!xUqK z(91u?HTZDs)II9x>o$0eR8ba5^+C*oKBU(LrA{ee?<GOz4UM8khn;acu~R?CbSnMm z6Ov;zO4MfIMy-!wptwfLgF}&W$UrjNXm@ZB-}8Ig(5CanDA(h@lD=}?UNw%$<GBYg z(KYFp&__9vyitW4I8T2aCfa1nOA^)K1r=}E*~V}tNtrE{C}wo5!y}z?6a(oee@NH* zwr$gEQa|KeQpK5R?+up)r_{*9;x6w1g5ay}J5S|MPbV4Dcbeazuboodhv-_)qde4) z{DEfCPNMN)W@n&DQm^SM*aN1AdU!(hAF5AakA0E{8&nHP9LJ%v02JHYaQS1P<@|-X z*VB6K0r&9TaJr{~2q`1`bI0ZzSwXP3KT_9RC(9Y72Y%VLjjER`ElZLmO*TorlJ#l~ zD>@xTrZQUWk*y&Wq0D8Bp=FZo2h27VRE@{H)~$ZO+z?cEyw}ElafC?&FbJ-8pM}-g zU00HxppGPcD4^7pXODX($&VcG*Xcf6zd$KT@8|Wg8fyBzt!|x<m1d*X{&3=p8cr%R zO|hmpK3Ko^LxqsFlFwO!x6}b>UG~meIA&ij-JFt6RU(fOF;?PqhSd2`zgA&nk<T3Y zlS=}X$ozH{(eeDJ{85768AFvj7)FDzzU8&5p67dBY4|adW+{t5#9&zM7Mh*+|IHxw z_bT;2_3K|#Vuz)nHnlIv>dRMO`HvE74ko5nUtJ`Fqz%Bt!Q9Ef#>nJvlaoZHKVNMn zqIdd|y`j!bfw?)5FqCXMXJJt!D6)CJP@z<;k^uDGlrqOeTywLF9WE(<5X{a183ujf zPB#*1XW-^HCKoCHdfY1mGna>s)TYVT`@uo^Zwq$XK>?@R%vC$!H`F$Uf}+4+VBye7 zn8>G%mJn>gZZ-9zgx2oXe`0KwD&06at)M=kY`Ij1*?Gfx+SZzS-z62HTV1kqXRh9& zhCSC#pl5I35%`*Hx!2BBWb}C*f1;&0H_>?UY*mtFfj7=pF_W&ke5Yna4T}W%h!e+k z9Nm8RxtGaRF^j3FJg>)MHj_Ih=DUF5_@PifNP$H{NwPAwxuSpXb37UOsL5e5XOV|x zclr!}Dar^Y8muyV(aeka)JL7Ih%+<sJ1A|wh~tW`#ySL~c+gt|N)tOy!kqF?jwbeq zhMJvpFSHDtxeRmpM^hJUeAhj%1s-DX$4QC^vur!&6(ZmJVW!xVg?V)O(XSk?BdASm zq@u7w$99G{<xP-DM^IOJ)<WQ_3-CM=FAtvn4yDWu;{bfKr~Yms9Du61dhQVA$N)t3 z<McI{mTH&)5HfnMVo{_(O1EfO=@gyNPq<DZIm#csPq2k=U=CJ*glI%hI4*wHD8x-F zhS>*9CE4T+p@onahiA+iA6ehP1p4!?KvWzh5Grgd5!povgP>ZTp&fdM<`6EG*g^0l zh5XN^P}Q~QpIG_ZLx{+V?4npCZ@|~Jq|DJYDFd*>?IMS_sNzq{%5P^>K1o-ODzYT8 z#-*1-RLx_|=@D8#Cv?bi@J$wd{zbI(cLV*8>HanDtAoC^NkIMfP5<jIgz=wRufH%2 z3}1`nDz=s;Hh(Q={0~f33&u;OzvXk1%k0sLodOEVijWl0!(s(2D4?Q(4?YKQBS!>6 zN;38jBE@m#fVS|a;lEO~MzgN*Xjt38K~q3R6}76^C~J6}FRN%mn0~RcoqrKKdK^#X zYg^9f-+O6$86C^u+I;Ie^tv6_)Z={X^Z6FvkH<9?bX+`O7KVHAzP9IJblt{_zyDgJ zi2Bq|s5s;(%8NagPqYTwOm$#N$<f<Pb!}9JIbkW?LbYoO$}wo?NXxOmreeo3!ypzq z&5PYTu3<A^uRN@<>yEmoh!$P;ZU_t&{*#LQg-LF1FHCZW(}!glRr#$18LTMf1ZD7* zNigB1k2Raqe=}>yi6YgI`;p?cpK3=%dF*NzR4L*Ibc$&amFaVz6@J#i;Ba1&xMOqb z==gE@BNi|BEW=5kCNFn-x`)jH(}EX1-PW{_jogkY5=XeZH3&zfOzqEek_KIiFmm>) zNrnl74nzK$G1Sp_PI1(yKIn@{lh#CD?&x&Yx8}5TL=MYl^8+!DlAv@(4oi0%JdV?r z(5p3YWh++E-&8B0!3*rPy7SFjXDzp<Nt3$m7TY^ukuccFbQv@Xx&)CGzoDFerY(k8 zrsZ2(Pd~WHT9$aPC!~qEDd!atAz4P)z&44~Ll4T4=L}d0WF6e+YUl`PE7EMqUSWG+ zx99l?9|gpS7?(@DatmD#FT&)D2n+<xBilsQkHe5j1g8jGrHd-ngPLS+V#)r@Y<P}! zKA+ZTCSw!iU0vy6G9%_#TZmoa<>BwDYe-yTz@V&O9NT{uBXhlIwF|IPTgA3UfRQQ3 z{m#gO)i8~&rLI6=jxc#?rHvBB7Q9eDBhwkFy@)UWb0yu}P|ZXi1TIEX(Yu~&u9X!v zoDrda2*v#JNaji!<Mq_o*IzP`#sXp}Y<%V@g>2JDifWgSYzAL)j1W9=H#rUs`IN+X z)Gs~kj=PEo$zp?(VU9?&C_{utEoUjHHEEcSS!&1xRex9K*IMeBQ~sH&7gLV{hrd;* z@fnmzCt9?><gP)n;$>my0=lheMcWD6o2kGSd7#vs35XUCBfVHgp5y@J`Fn;-UJMaA z<Il!a>G}ibz8(ybyi9x1q(Oth-sKt%0L$Q_+aj$I+3^X9{RWie-GoR%L-66R0obPC z)t>Xa6+og&;L8l^<A#1ZPn@Tf6ZkomcVUWsEtSMx2KWe5u83KLTI4xN$SJpjGc7Jc zyu`taf)~H0WLm^c;xs)$!T!mLc27D$A9+~FgiNXmZ(^z@llX3+$9fuO=>=IUx^h{- zx}-43g@voc-N>P7_9w;0G`1vZUBjIwQ;?``W;mYrwT5Gb_cynE%S9<WdB^&Ay5CjD zI;&OXK3Zl44Wb9B86qRL9^$NWgB(Q7%#((^1jhwCCNd^P?H8~61v1>~N3<=p=<p3= z@<BINRF<Er6A217aI5O~5r?^`I7UYGH}RJ}0IOXqLrLLOG_pwfA`&j0oAaeM>Ivfg zx-{9?z8BH4ungT-x_eSz<Z}JY6(yH0Z^PdZrOJU7?ZXJ9u!9iOCCf#h5W3biV-jAm zncI$}2x*1q6vQeE3Kpro!O^5MQsE~b2~edoCU$FZdl@4@#<TvJ8-X)eH#Yk$hB;&c zirl}f8L6Fy@WVaO48g9)uxPl99O(<loU!_~4B9U<N(}=881C7@rc)F*m_!aTN-YGC z`H|%l-G{Mb-ltp}iyWT6(XntMSDk80!rK>Iu$><YF|K6Am_-*a)0cP<_`xh#L2@`c z%yT+M%X*TWRy|LP2%CwEvnD|{jjhk&UPy@Koja|uA~pAETM-cGJqtYC@~GIS&c#oh zs%BFaWz2dNvo@7^ROT{>4zQQy10c!rYHUYRm7MtbB^i8$>sc0X`T2T6%ne%EC~kmZ z&VOk=0qZMWTy{~=>I9F{oej*d>DcB5D%xzdR5TBxDoQ(T<pjah3?m=j0$3vLkT@_L z9icjnwv}uq#K(}CkPZ`@G@e*C8n57YJ42h?E?i(PZ`ah;%(wa4O~OEjX}H}F@NIm$ z$6a7v?c;+ukIwVm#)K&7tEU17k1V7O;+YF*0ZVE1GCBf@fkDN6LFEJc!249K&(pyZ z2ltNWGyT{94`uHdUP-%kjmEZZ+jcs(ZQFLowr$(CZ9D0p<BoaKd%xecpZEOO-#LG( zR@GH&tsgb!yyrbJ237JfB{#iAEP0@jAb4j8!~#X=hMCmy^PPBC7qf`fXyqnLcBxMZ zElwXZ+STAkk~Y(aZMckKBPCtK(C~A(fQcV+Q*i1nHC0W+!sd<C7y`;@-3^g$!w~7u z_XkSsCnH-vg5C(JVH32^kie3*EhM!tYTB;;E8o;iwVMjk8l<C1{=M%`WKr$OX*4Nq z@|xBm*aJ~1Yt*Br-nvqFCy1D<+0R0$?!Nl7{k8($3<^0_dD`R5!SH0`PiZ5{ZAz&} zC=;YJQ|Pa#+?!K0DF_|`!v6ZU*v#(twoohw>fc`2?7JqHe8%NpF>*BCqS0-*;9i_# zI|Iry?brLp(vLfJN&a4mPot$4>$#EROSE0t@=9{y6lTsUv)IbBi@0{ms`e74@3T(? z61K`K4hxPlrjsu)VN}l(6R30~bWR{CifwEg8<L5xcT@4Z2-etX=i-PIGG^1SEJ3r^ zFpI-$Xaq>9uZp_Ok&qg4#b|R<o~5n9Y`3JdzA`65980?cL@K;q!nnBmk7#cpv#5Un zR%B1r1mjf8N4ZyrmIW2H&yr5M?F`%BZN_e0ztoG)i+HeiHTVy|9>+;QIr>ovCckU6 za$r*mr?hAUM`Kz`NS8$)i=9{##~DK&cjQ7=OTbilM#L;l1+eWHGob_mKA{(^d`ZS~ zqv0244Dr0#W(~VluaU}r_2*~mi66xcxzPN%i3n{!b3_$qzh2ygorSppe8_nrwI!<6 zdO86)+a~hqmF`D$G18OVBqu6SkJE<~3U`PmUMuw3d1O?$i*dS$a-Bi(`~$!xa_|qa zJgHjF9B5k@z@P1LE$B$jAJ*l&eH8GEn`05rb6}R#>6Q7_z<jFpJG2b=B^(MfQN7cX z=p`l5sh=A(_Ss36sYzxlclCp@x2yIhO@jlQ9%Y1lewV2tXk$?>MTUj2rlDL2%G%Sv zd&Nm*H-me)rrNoI3i`l<fkyLEz(nv;Y#iI;Nh$t>(+xCaPCaM{Gi(StsLL|6gVCTD zKT(3^OF+_Kqu-(_%sg%r8LyYJU~l|#ROS^+RN2OmKDh9oMU+Z4lp!(juZ<yEAuM>o zBHxEFom0qUT9YQli(MlGYF%(gXd?bmmEJZz<hGtg^LZ)xKHQXms}EY~$v~pM5-qS; zvonL}>;8kzF__dNdGj8QUh4K>9``xNc~aGT7q_<qd)Vg&I7m<WS@<oWS7d)T9o5eq z|J`w*mf$`9qi?t9=34QYI(#FKk6vA6CD5QBahu|7P#>tvkcdWs7!%|Y6fTe_R4|7L zA+}{+JhkfTYO<mOd@vBXLt!Iy+1b#Ash+DCzlx2sij7kBi9%INc}^Cy?^pRoWJAxJ z*wi#$*@3e(npqL(DT>$}rK8;@_ba$<4bDDZ1oU`v<XCcKV+Yd;If~zD%r#a7HN=<p zfZjU%yD^3BY{V`*$|}+)*MQ#c-y1u>u_8v>LJhMHhy`!w(^>fp#UO|A+d~fOukzhF z>pOm`>#W18rss>hF%F;qzyx*9P@qTw#}^*{qzjGBRSU0X7?QEjSi3gf_bXst7u5iY z^=8kCNsZs6KtzzYUpK;N-cs)dFC@E0@jf`USl9(svL0k`ki)vO5B9DsLLD@}>t{g= z88md}f-W>^=Z*vq8x9;Y9G%yA$KXbZR7$3WN@zJ9Ndv~{WF92o9w+ErV1UL6oI{PG zz&M8#dQ$X5622U4Gg)ZjEvq`|?>hfrzPAwV!*JjaQ2~z{U*uIG%^79X6<%BpS#vnT z^$@~NII{;sl0#VZp+J!<P~-_dEaMmCx%}Zkdi>KbA9vp%MKVh$<3r6kULBrN;W9mR zxt}EozT{gQxBosYyxuu&-^tMIcW307E4RoLjLVi*R=ntKyawVF1<??6Q@d`EURRPS z_GJCEZRu2a*@c>94h&m+_DFvcb)*LQEtOzz2+pk*3}S8Jk9R)W%49A^y$sh2tho@3 z1e*ppF0FdnIP1ihrdYIV#LB05az1e*g}piod!&;>Wwwnz=p>s6m9?mZo*w*?df<?q z<1$0B*^{F&`UM*0EVOt$Bu})!Yli{f;0=xAb=MU>W!m3@4~yM_dd&Kkcrb+x#KRR` zb~kR^;d!E<y`ik)#{e3omcbSjc%#L<F_1Hgk<f``YgaYhs!+nzQoz&~)jk1BzIGXp zA%)$)OJ)l`)E9hlEcic9H~6p2{j%=zF_ZSvU*#kQ8F4>y?JM@nnJN<!-WUut=7;c> zc(McRE3Ck_PnPPLAq1Te$l3{ta*uq;2|nBvN4oal`D)Zh+x2O=s8UAsh)`E*J;)ti zO&0lMgO^ZwW9J3)e{ZL0<5yL9;wYuPER8yJfk~z&VY%ipjRkSBzcnsiIwow1cNhz3 z$=YfKc-xRhH2;yWt`>@J!D4Pgz-mS#Uq@a1lA9c28^pYQ(XYIXQ=BUCT+5d%;Z-a( zWoZV#iJDjz8>1k5_(O@BPJ9*8j=o4yC!5#D<<QYT-U&`F^OPj>2dwKUk7=*CikC@U z#3x+g;H=--m+_#7*bYpJN2K(AZwXgSm-@B{$vqAR`qJ>ZNlM=$l_*aq#HeXfAzw#? zOE>Ur!zHa)C$_P<T5*)w#sa5xYE*7nfe)X*(5j0}Y<59h%zxoy_7=y1E2KtjHj$R6 ztPkWJyZeDFeAoAhp}SM%7sFsF{s;ncZ{BxutTN~e=%YI<HA%r%ZCP35L3e5|do?<J zQ~#pCcZE$d{!c~4<sYi!K_hkB%eSLJ?(tB!e1Xo)cXxQ3!ApwOD;er`Dx7VqCB)&v z-^LQDN$b9;znXz^k?vFPpO}12pe4z>VvWFcOpa0-#k<y3OiYwBvqc9rS+^oNFA8lS z7LK%8Uxbt97thWuxVyOHw9sy9$etdOqT6C4=#OQqscldXtxGesyAMHiEEpE2{M&H> zsStsGSz_X|oc3etun^<BWar{!(w43TJwoto$htS{P%OC?CXF0#6k=5JhLmsMO|5h= zifu-6T{<jT$r;8!qNG^7)eF5*u2}I4XFk$!HRm1@U81iQbo*CtM6T6*C~mxIQ^8Cy z;(gH_22>rX_e_RY(7lI7d>=}qsPH~gzYpsQ&3H~XyGSO`I`qCW#LUxbIu^IAY36YG zs@{;yUkEXXp$w7~s~;hsy8V?czr{)EkF7eClQFhA8q2LSVx!IQaTXo#Ek6D2hCT`i z;u>MCEP7u=LAtD`I&9L0W33I$N(zSJl(so4!@Xu-mlwUGydGJ;Vu)jrbF>+zTMxxk zNxC=4OI!<k#`9lt?j8Hg-Wb{AI&p=^r%6NbZrqIUI5QC()!gc%Mjz44;^M*h<wo?8 zMxoR<<HhJ{UmO#nCXOb%1a@3u8cAoB5>6zzax0@k`7dbWQlN@1F~rb(0)L(oI5x3U zj(3S*U)xBsTpJ}lB9d9*D<Sy&1l=g*5PO5EY?`eX<qoQQWYugQ3_Hi7n|IN!JlTWW zj<x9s#`VO*TY$ce(hV|u=yzAZ|C#z=;I2d8pL@UWE=E86<_X#}Cw5TBCwX*QI85LZ zg;5oYe(Wh9wOIK>z7~=EJkgk8M|!6xkO?|efljwH;(`_H*3J$2RtxKR9J&Qc9;+On zIQ~DUb-;<j-E{+5Vr~JaAqOVZR|Ev3utPU<ZWv_ZTYi=kx!~F%@sMlrBRrw_G}4|D zNg3~8uF7Ww)Y0QmdC`2H7^pTw)al;R-tR#4yy%ENJgcqJWd;#&_5)*hJ)mJ>j|xw^ z8VX};8#;E!r8%|YeKlIygXFii583-GP1KT^5zDt|EY69*+<32_VrJXM`q1(WSxt(k zrDM|8(DDLa2u?k(^@pPY&Viqs)LWv|B)k1wG0>Du@^FLU9D19ozuf_CvwLzy4Y0~A zIltkNBd6YQE}P=9H)3R=l16E6r1u98%!*oRG7+Fyy?<8|S37_1WFP;b%}IeN^CV=- z)v$NRshMOaAuP)%;B<Vdt?C`_2~)z)0_c7q^s*nS6rC5ItINI~=?rS^8`r#}zR<}y z?aD#omB*mWSB<aL#?6~?g}XUq3N^$EHC<bg#vYl%gHMfERV+$f_$Kp?-;oY@jpi@2 z0iJ`3<L|D!^j)z@a*4@O@yXIg^Osd=+AsFX6lmsQFUrUiKNZc-X_d*J(rLTxmM;db zw9v2SFK`wwbQUkZXtewjOLs;mHOX`vc~OxOpXHV2exu};x6-5;m^8=qk(jw`Fo3c7 z#o@+WMCo^_gumX)D@lSe6EHk#61;!WNf_Wugv67OYLK)mOWd_P$!V8e=>fiZ9v~|B z${pL$iSVj_3mF)pBx4lD8%4<^GR(a>j-h=4=~3M~9c4otP1@4zXwbV(kb;#j&q2FW zjeGNSjj)K>(tr4f3?nSQEvUzZ|H^pI5Dg8F)N#<ugJH_Jnu`X{TUCpHp3Sd|c(bM9 z^e^_3S0?REH}=M7wA^R@mDiURi8z9ZVUd+?+CCpq3vc4Q99~g(7Xa6YNM>s^e?;2} z`19-7f8j;jg|MdX+GnSLjOmQi8Cg@csSBHW4C%zx$b@}nvdI=$qZQHD$Rfjq+EZ(l z-<&N6DdT{JG&um?e<E9@96tLo)>y_u+;SDEucr#2@(sLh_12CmrW0|)BWW1V>=tiz z*y^<&gD<~yyM`5WarGilw#CL5#gKhSx9MioiWBNjsUBwoMgDqW^S1gZaYsO{norTV zAcNZ<Sl7U4eJ+TSz`q9}2GRjK62Gi0LAM`pfc&b45Hp3D+f>SitYpMNXX=5Ab3Z+U z>QSsLTyfdvE(ro4io;-?>+WV377zvy@YcQl-2nE_yyky0o_~||;n1ZB;NJrd=HCrq zeE-*sr?aDht&_EZvkAS5t%Z@Dv5AVUiIb6m{r|~-W~<2ABdcJ1b(=P3mH-M7&RG^| z$tSSTB5F#?<ZYy=5(ii=qE(*OZSy2lpV@Bl%U|!bc^t098?@QqE@-C51EY({<?wLj zbaUZhh`sOFTCXZDF{Xd)Je@p!c<jFIT)Fvqf57@PKU2h@gmg0eZ2TDo<tQ6h&!H>K z7=tuJ-Ik}X-T&KRh!JNH+b|o!SP?<U)sQMAl2IDkRkS}7YR52c7Q19WhWSTBy9k)Y zM1?~LFzVouTGz6P?X1<L%!0ETjgA$aWeed^i=rcT$e?_cx@&h{GfQ_rbVqZCWx8yB zdHTct&&k!TpH@~Si%Z(N>I|^iNHl3%^UY|jQZU(@sv-T>CL*2XFFnEKA*O0C<aq2Z zx>Vp`gH+nhu&FpsCLyOX)o1b8#C(Q31U39e_(}Xm>y;VY-QUy9R_bJ=%3XO7Avq@| zg>hiP>{BTxuU65u3Q$tw<J-v$7nL0upSLE}$F0NH)*Ahr&Ll9mmrF4}rAX9hXIEaL z2wzh-wquouT!F;wlY~g*`;S3t^w|R3Zft>^%Ba%h^Z_GL_yQ{3WAm@|zIzb8!4+)T zJanvN*Iew9GY#hEapjkrVH^3*FsHFvDf@p?wiI`yY%ExZR$hLV`#wcl0!g{+#lipB zU&R2U+Hz2C%}+lM+t{<RoG!zzDa86^y9y)BRk*^#&%th0;UWx+9|ZACIJowOOCNIk zb&e&=y}P1`vNyIvJW%&_ZPaIfN-yHUwxp&(UJIFlO{p~_6Tfw2x^46P6g|>1d7I*9 zSkidxc=aNT=~TUEjR9vi*d`zq7MNeirlX7QGW@PY9M6{Mvr>MsTcl-(EEs=}7T2sA z853w=4j*cU+$vVw1kK;sHQ@4ue+%q21aI*RyTwHcMo&UHd80B-<o=MM8*jK4SXvvm zfR_Z-+@whqoUOm-e!BaIiQWs6E<pwafIFgvCZ<I!Vno(@Y><-plNMiha10ztZS`Sl zlQVB`FvKAGGo_r6{_V=Gu(PscscRLl2cb<SH-F;VM=5_OVmSg)FI+l;P<|7j8{-Ku z&^B5TM8y2gDO$ljkfblDhccezc&?p5dn~fZ3n5o39#KzIc+J%i*yDpJdz~LJxaYA9 z34Srj@oON%5rN>{89^d`=G^vn5lN~HjwgzTKzCcT3l(ul*lx1~NqA3G;{7aPpoOsm zq{k9t7^>w%DTfRmaa&;H5xZzkVOyw^yEJ~8-Pzkc^~guetillY(mG$+(!STywJ#3& z6&u|i$Z)LU{q-%B2I>6A<2b|>iAMUY$=JrelZKEOgMc^K#PwMHr;!|Gdlf;gejFu6 zff>RN*$3W$`yePf1oZ-e+6AW#{0L^he-&B&=~({ba{d-sj`<_Gmc9pzb-vxse|0&^ z=HE0w#{Vh_k_cM68F)A;JGz+2JDM0<7=8Pof0taczXz-q<uQ2mR-3D&*<J{tY{#+~ zSR5!u!kEcIK!h6d!UMr~uR5?*7n+Y+{)~PdLCcZxJ%c}sVfJpa)^UUdr{-My?sA?y za?ALAy}Us8IaP6w<sbC@7#@j;24_>X;UQ7C>*|Z#MRJUeCjQxu{790&^a$j^fa6?z z9#%7(z3zGn^(9Urm%CVk`P3c8@HF#9)FXn+nuMQp;ZYOjp}qwVRPO4HD3TyiyP3~r z8=<uSXtD?k9>@@u(E}0Fnvva;P~e8)<*VE~R8dTypdhVo*(5h)7C)xAoC6hFS{*GH zboN{zsNVHcLOqQ|;(kTERxLYi)BT70!dS~dV~Xs;bBDxO6#)nSV7}vVO=%!)tW55C zE9JmQQZ(y8W#-6O4Z2tNb&hx{vQPZDjdCn!G8xzADuZOtP@3!K-J@p91;hi*59>R8 z{Q&_yv@fKN193r$8;i(zj6bn{eH@1a{)2L%h{^#HD$;-2IfxijFgWG6WMOrgur$ql z`PH;CWSW0?n6bztcVrA}J6d4=`Fc?A9WV;;QU;@UWPezb<-I3zevF;IOOyHBB8&A> zmo%P){Ngjku*#B$Q`tILFDOYaP16vWrmE9Ib*a4hmkh-}QS!g>6M(w^u>4(LR{x%N z`LBcNf9H+qziE#CT~#Le`$^)P`^doA?tjX4*~&KG*g^5_Xyul~<QN6m6#!YEkU~Vz zODhu;PmzB1k2`Jcyc&qm;ogk7QG18??fXFx|Kt7QTQyS)N_sDlQR<raB<CdSg!823 z?cwbW9)Q`sxB%M|oCza!5@fI_0;J@~aLgoQKR$xR`D}_|s^T<B7R(9e4~!f}4wX1` zX^SD}mTFw(#f^?_6VN1EN}CMe6)lDMvkbd@9F;~4Dh(9|y>@8lRaKkBx|FR9#pyTq znz{{Z#emmnC0n*Jb<Oyt%$3GMEF7}n_8qFZojbuqz>WK!=TQo-n7b6)x4zo^OT=#* z?5^?Y4hHGgd3)U5y7oq1D-cy-3?`4jpl9MslQQIG_%`$(+YMY#YQuOgX!I!j2+hb` zFGAmxNY2&ZTkp>)?8N1iax7aqh$Tw7?TtK?L+X`R5X^a1F)mh{`+}3i`e#&m(dW`; zXI!r$<-XfC9wqAaBwoL|#wj6J;|9Y*u*WRh!f9llED>R6Z?p%2B(Ze!iu6x`8qaH5 zr(PRqu?8Sho}}ktXjbRz!W2M_&>PrsdY7#`bO|i2WXe<JZEgs+%-qZMul(r51!s?6 z-j_!~>1M20LC1yKX~=UcB52iST3hX1`tD4X4wND{?+-|1HeDb%9%Jvya$$UoNnjX_ zkDbpZCno?GbBf4Abt8U_ZwO`i3iSGdh~#nzNaOPhXn%#cbGe2csYMLWiCO8IHt3S5 z<Kb4pW3I&VvHAN(z-F)X0bBv(yQH=y%_UqgHe4Gp9Av@!2qe<nBgmaka>_}Ltl6up zaSw~QpnAwDz(!)2NcWcY^A-NVIC~O1<$!!37w=_(%m4ggm^*hHM=140t&hCaPjWZa zN04c2v`E~tk5GGbb^|C%w2?0E`HGSKqbOTDp?gl1!bh|0gmoM*`VMx(gr*$7!0Jn} zVIw6gN_ps(;YV~n!j;HYi4LhWSgZr|8UNpb)_<DF|27^}HL>LKZ|6(=-JJ1X8~*=g zJfa3p&VS8D-oVl6n{Ms@Xt*f$%WnSV3rj0vC1lJmPD*0~R|c%MPm;vRfFe|gBO-;M zR3V9p?B;-OVZY-_e&z1A-yeV+3V=TqQ^Dm%v~2e%UcT^R{^M%u>i6a04l*Y=`7^u~ zZKY0Eun{OU|6OH-Y1@pU)pL`WDRcrI=AkEQc$|d`eca6#4{7m~IyRIzXAEXmf*Dt8 zTK;mlUK~!irkP;vs*=S1CCJNY-;*jrxoSIZwBL+9Io>|DUAFgDIqU96q;cb-iF#Wc z(LJVmtYkzIJ-siJa|;xti`S;cBMCT6=Wqh0Qj9xCaZO4H<x>rqH`Db3R)xhuxKVmQ z^4A|%`WJZFKU@*r@)nrj!0|E3di|YLX!11&yw(-PYXTS@!APd?tkTE@Kv>$BoVVp+ zIIL5=a^~IbtG0#FNIn_Xm`&xR49chX!S*9bZW(U+t?geTA>*-%(DY|rT#^34mNoJt zNS5jNE^AKN%n_9F&A6Li!NajLyirzZGq4WDeklA$5!D(Oi3QOnERG`B)I~OXD!RoA z-1;c5T=Z6`c4Ha$mjNOh(J#paFHzh65C8I`|9s*98wy=(E*7}oF!&b01rYhKq5oe$ z`u~E0u${e!f{WcZvBP&4#5Y3BJpR2L7b|PoA&a4Wns%+bWK9>7(7CiFEdb28WEMdt zZ9&K?X+TksLKN{S<6V?DR(JotlC3!E{>nRsEk7>tN5PBJRGSd?1K_6=nqzJxE7r!V zn%Ky8>R~>~{1)2YF{6L{0%HiC#B@H;CSMpcV~C1}5oIjVJKV^gOF7YB=tmJ=bu&;# zw_Hwbh8m1-z8;nvs0`0Lw<#NguW*8S?81Mxj3><W<L2=W?57Gs9iQv`1%7v~`jHY< z6RE{oem2lhwv7;9`+;U&F2i4<PH27M-Hl46K}eNv>=N2f3l<Os#fmtZ@JLe|tgws> ztFV)#%UQKLNWfMq=QU9)Wv4P^8LYS}f--4-Y9p$c`*`>RS(u9d9adOO_}cWDaTo1P zTk$RB&PrEs$ygq-wr=$;o<P!;diJO~w7&M8A&vUHvARut-Be!$>CkGD%}{*vhnHbl zjiVIEU|(kuq8pB_h)D&@GDLZL`;#PbL&sXrnc5PW@KXrVF@8;$sFij)>|n#WRq0nR z6B$b(G&(aK)2SoF?*kq>j^}}45p8?MP!Duyb?5pZ5Aalsl+TkNn5G+s&+POc6V7#0 z4BI>Rp=8rC*IrILOD5-TD(o?~=+O_SUK!FSYQ<Dws1i!oF~zS;5d&q%S}z5rt&^EV znyTS?c~Q>{Mpd}=&Y2sPu%)M3^AfvouUhAV-x_SABJ6~`#y+63{CQSEAE0bZujJ24 zj+~xn+lB0Z^yd2gL_&5&@eT0FHg5sJ0E{d&MO9M_A<r<XvG&Wmh3T}2-(&Xe6Hf_8 z6}*#-nS2a0;uI}cW;TfZ{Mq9>LZvjg%~%bRO|z?*W#_K#om5vW3W%Fa-ApdYE*xOj zdb`nH*G)U=pPW=9DfZ0=>K~<vn`$7pQGC(6-|-yZ`DFiqWBh_=oN%k}!#4=#AE6pv zea7oKmW%qdDq;+E@C4gOkV70DYiPb2%#h@WK`xm=l07h5Y(|PMoP@~>lC#H3spl)+ zf`f_Q2LH{ec)>YS4-A8cFyS!bd`|Offy=V}G8NU3xMD#aI6G}|<_GZCHUHD<{<l5; zF?zRW`IfR+`<~$y{{L%_%HKAsX=iKlzpb%a-9lMw6!kMC{=SJPV9HR7tc0Va1|Yzi z)1{2S)!N#6*cuE5?BXEQ9n2s<G&iS9KP)kgOeT?STg%PqprqKQV<?)Ipvm_9N@CIH znv=J**YmZt*VA)jfjd@(z;QxiMzAow-R;WzY3F(-%Kf32eism7C^w5jOnM*=StE>F zKa?!P0P-ZOj*yPfAe68}0`eq#&Y>R?osP=^lDMGVdbA8V7{lqnKs){>4B5k7d5Y)P zfJ#*74IU4jr(D~OE)QkKlZ3mZy0>PUS1&HU{X)!a7%4u=BEF*`I3G<2KH{`kaB!@| zb6X&cpU@Z|rRVC9Z*Ibk1(=+cv-su0fn{Yrb;yQaxFFo<VTCTX5)ve9zrGbV<mjw9 z47TRErB}tz{+t&3!Tg+>k`ZB;_J_a;4^jlBgAc$4gy<(V<~FNl_W}6>(M}|(3Rmxx zevh{N>eBLd+N~w?(UUQA=|~DjmwADOuo0k#UpSa?QSqWC;?_Bh(p%s1uv7C`m$B5M zilxKz&KA>_3=bJQ`0^piWByoS=EA}tQ%Tow7)Ne-vJx2J<Cmr)a%G<56Y5D*?YiBm zkJC{2#`*@b>EQdd;Uk43x*<Tjmf(_`m^96rxl}h|hn7Z;WopZtNjsdO!HS&)V#Dsf z3ArkiH#CyJqvGxHFHNHuj_8@Y0ixs9M6BOXvX{<xu)fCdjrhi65EEv>`D?kATrZ)q zfGz}*?jO53QHa{Yb-}JHw&6$$>-kjBpOG?b%Y4p)%vE5KG(f-ew7c1eS0nfCdRV$) zFOSYrm}A5XSGKH4V;V%M?GaR(11=SIkh78;bon_G3Ik5c9Z0qeZAcXgQYZ*#2B$aG z)C|j$0JIq8y3vw#lWf*C`eoX?a6>FmqFjw=tp)Nq=%7-|8x^DvVVdZu4ii$X3Y4l7 zYmp~sKhzr>e@MW{Ck5?6GhK-#N4Xio50<bxQtd~=z;{vZFeE*DzZHxxT-`+|k-yRH zva?B+PQB}=@^hdST<@htL3&fdT4mN$BspN}ji`a_p_6#4jI7?cVD9!sq7X9?ACmP* zq$l4Z*)rmIQ=dy;xM+z&CH}z2R7y*^X^6t~mKtew2*n^d<aQSsadSwO{goV#9OErF z@^lN#MI~wSj=-OAYxMqOq|#kxMDDgDDtG^c$(Jyscc}KXP9xhCvsW}aYIm=d$v1S6 z$v2jtVX11e*L0XcnYSk?EK7wsX1EApld0IGzuyF$Tt!P$qGVq$%woehjZFn6dhK2; zWcxRDYl4m`r9-ay$8QaZhf)}LB^FF7Z%n9r*crxBr0}xvALAd~ZcNsX$#k{CHenT- z?!unBdZyuhn&y%)4+V$_Y3D3H;*6T~un(4uTwppM6^LxLyAZ>cY9+tRKVf0!cGisz za=L@ErETw%P5HEV&)bWTq=McKGip|-AYIP*q@l%EajJ?@URU5YCpK*x=@-3IA%Z67 z&YPj{l^NZ3>RT$$%GwuJTY=1#uJf=MrSm2!#7{6S;K{?oR4|*EtMqt9o=lu`icAT9 zt0k)OxPvAAAU+-}A`Yk<nilM#FC6yrZvKKFtpFK4R~7RVbn=;U5p!Oy0%)8A4P#B7 z#-?J*JAE4mkEGYulu}@5;w(<qr7aQJ%9eszPhz|rXwXu7E7a@~WGquhE>P|msJsjw zB>N3>$)R%2BkbPGq2y{T>0QFW{fZ>In9dAYAC_6YEM_`<Xgf4Sk=TuPJWvo*%OcHw z_c}v>viR1WwUeZ3EeODUX44)is&W6v5ZaX<dpA_up-_=uO}m!mi_VGfhv#yc#*&vm zUtXjs{xpv`a&7-l9M1+@YNJGb6Xvn=ERbGUDUBB!bu<0K{H48Fm!iFkw17${s5_Fa z=wqcZSweE-+i&HS+J_lD>|J71anKg*wyS0|@&34NtCRk?!QW#KMRogF*2rxKF4BbT zM_GcprK{uQ@%WA&I)v*DqdI$!8`oQX<v>r+2awT{$g~7_OTi^y0_$5`k?Q1f0!UKb zk3ep9Ji$NZU4z-Zu&^8LVX-G{`wylcCl=R+<{7U{ksD{DrIvDP(nd_d06nmDMLR?a zT7&mdQ9`VJXU(CW+-;QBHW(S-(EV)V?K`J(2R3by0H7b0xPKB2xL~N_1%=`Z0{TH{ zy(lEzfPuIpSGY54x<kv}sNUbPm384V?u18nK^Jym%iScp=REC+_+ruD>PkDJy1fAC zo+!MhANdtO_#I+3-Wjw6<Qlzbn+5aqN3;h3H+^wzwL#NcQhuzr{nW)N0_k)Bk~=_{ z=0p%ia^Zj>rz46WhFF}PP$+W`^JLPzfr%-=b2Tki0Isfs1j<8{`Bj^0Ll%$G!UUb+ z5Ve5N$8WAeO<D-$Cx#uPM6w~FLRQVG0X{A}H$|b{2r^2SuOyTjWD7}7npMC*;{TPW zKF~>eKZW#uA<gAv2w6%>aW7^i+3@nHA^C+x_67O7mr&yL16|Vm3*z-x*mT4gwP40A zRE|)6={wh!Q+I@!0@JKjzqA>skK!6xn8mFZE#($>fDtNM&hPyelomZ<K#QcJ@W7vX zs7vbM?u+hTX!Yc=LwK>Pj?mZQ{U=XHVYU`fCM+EmNFKcsR_HGD#JRBpv!e({@P`1s zKMUUxaSme(qWMDveNiR&Vk+Mqn0Lhp`sH@QqBJR-pt}X33dYKYkA}P-%SsPmh6V0l z8THZTIqLOKyhE((j?mFn7T)tT49ye-cb^haxt%vgV|ZSbh2H-NjhfNOdhaw@ef>)y z@t>i{e}a_1^@2Cf6Meq#<craF@=oyodyw+2xb>ZRA^ErTmbAs+ER6O4Y#0)?zGZ2@ zg(IZ=1;ptU%iKh&CqyzN@fFN)P)tHBxEBO{v=?Zt$w@F0V(=%>&AOuao&n$GW5}^X zS|Z?a$rCR)&A#3y+e!HSe7*ql0&IXSk{ZPKQvx>I5(mMq&f97Ws|p9=@SfU{p+dZ$ z!tlRa@UQ01L3^A-Wj1_BbTD}gC{n(5YVI);Xs`X@YMqOzT?cLjp5MIpD6-6)N@smA zUmEq9Fvckd6=6;%1fI7H7`SVw-%|!ll>|3qJ9GG(o`W`t4c2$uFWQwJ4s597j0~Dz zSlmZ|>%|a=th4eJ7RnFX3QQPDc_BLoaKVVds<qD;jGv8(wgP=(^L;xiN~v&2H=+s+ z2yiQhvnkFiEf)iCZsea~en-wCZsnX|LPb)*jQn|ONdrlUSWqDDJqhli-C(km-;dp3 zBMyQDhL<*uTUKDN4=;e5974l8H)mk^D%66hBoDrTiwVMIV3`5;My;41namiFm_5Ik z`K=s%o$H~J1;V<N9$ivbmfM6s8)5MKzDSe!>S?G`zOBVv^^-N?wS7V$+&7*D!@1*+ zLgU%f{3%;pVVHy}He?5d;s=y!wU6ilu?Hm0yc6ewC4JnIE>We+82E}2t7;gyNi|~f zyo!Lsh&2WNm@+@%E$BulC*uU@Mh;PWy{TxyEIhgdYW8kE>%>Bph`*gU+082nHSvUi zS76qos)J;`YfgN)R9n>=S<N0*d2M`l(U?nv9mR}{b{?yoD%4Y*q;&R*<;FAY--!C3 zko*r=|7My+{BXjJzQGFi4OX82J6P=;zgfJ54UEi9NdCn~ZExV{EM@XP8{6!J>2D!$ zjFDUexAg|aK2`Z4&8q4<lU4nnBMBuTK}D3O`6Z#A4(jYC1_llq(w;20wKu23QuJgi zwZezvfnUMw4;TFyv^|Z(AsBEYgELdyf3BE&pVFTW_d9_BL};w!9SA`np{dYVY4#H! z=prwpB4`4)*xcS=8lNm_Kf`{rU0<ELVbLz$sA804bnRAgz)OR*%plNc=}c;wh#Qj? znYD^vQgCWEcKo^&EH&tG^B642PR}s1_loRH2@}g~SZzAJviH&VQjP8032B$w_iVN5 zK+Sx5Bg@_?<GhNQ@!B%a=-7AWl5M@-^^$q2iYZsaZ5`~6;LycECwk9&vG2242s0zw zvt<^SEhJqdOQJJrP_AD>`vJJBpSE+~Hed562VTy$0)o*zbEc1Vs)F=9Ji49+dYWNi zESNDkE`mq+?2Af40fIP&+Q6KHFoZ<sfxSUanm+F1g!?lLhG%lcuAL6uCocQGAra3D z+rpA0xr4?ZQz5^XNFalhr(~eCA0fX?@(nPfdCRI!+ZR6o-Pbm01mYMdm+%mp(pw~| zU`T;Y_5fwCHi*lGz#|UBLRB<leoG4E?wWA^9_((X-aZZ~z|QFByiq@e>|qqWxM~c@ zuA*$*FIFVwoP!Q!w26m-{tD%U!@Di!Df9!!+mZxjK7xdZ^68>GsQ$NOawadn_av!H zVZ`36mt*LkpaWpO2_n4^UvU>$hT(ZN3mrowRSd(W$ZRDRE-7g!6Es93WKgfoh_{@t z32~t)6jZ;`BK}0pDDCFI6Py60Jx$6Qt++*U0ivJDH0}Nc^FJZ`A29#*y!r?w8b7}? zcjDhEoBt{T{;$lPlCzz?nt`*C`M1ygPS23A{M+099jd}&M8Rp4auud%Dk`?gAXXIK zFij+5uLz^CAtl*>Moso)?nG<TyjZRoS36EnD#CdMd?}-vMH52Y2as!cnqE6Rx$SxT za{B`C9`Oam(*<)!-D4eGK`$@jG&9G$|GJ~bE7p!K3>YuQa`U_-4D>5U?w7xoBK4gq zA&&n#C`?Kd)f?r(z0=m@A@^a92Nm|vZzEK{q$ItYOhOMPcrB{^<1oaGC-(#8_nC6# zfC^7^R2Ec4W#jJFP-4nr>kJpnW&=SSc07YS_$9xSs9Cy+D@879x_r1uazM^;{WIOA zie=<tOcis(jm&U4-Pk(30U1~Mz^GP;`5-swn$dGpJVhUONTdpV*JEIo^Tn)t?=RPo z#|?0|ScQU=y8TWCu!rE^sJplO`=LIr(5}KBkbu)#O~88)7Bw9_Lu@8&Ir(g>enqu9 z)Gw=26Z6C-7Wq~DDxQ-Q?!|X6SgeVtlJN96minult+sCF7Ye`f!zWgusui7uyBvZC z{>7dD&sX`Mm;BdbsfMwWVSm>(hQ1kAssF3Ta<Ttr@ltlQ_&)v5LaMs$^v&S)wM{bp zt5O~sg`b;1@8u^13Sm)7tYT9f09!tmyg{OM;`itg8#eBPg!k<*zdvTqa46rNl!3AH z{WzxHhaHaC$M&{OLJ6hl^wf^m%(~MoXYU_}#@^4Dk63`1ekcQ|Rg^C5pWsqZcZARO zv_T9|2_1ChChcA1>rbdC!fgSWcT3<<d@u&sHJ~@~TXy5et^k$*q!KBp%0hE>M6qh9 zODLy6$TrhU%dZWlEiQ!~KDR&p+ejGr>{vEaHkwkFJ;ksC{~!Z>YIK)tIRWjMTWj>O z+bOdITz=osIb)H`(2$pMktAyrO*d7+BEN?6QI)ZS#+kq}Wi4)5a+Hxujus8<QFLk6 z;LT~^s_sakO5<vc>RS?}&TUzt#l@Z;vL?)=JYotip2Dg2h(Zm}n!mt(Fj`iX)uG*< zpHMYLk+43>^Kr2mPQY9<4m`6uO^yIzFg;(!YVL}Xui^C4Il!9wy<B4HB5mozm&x0` zE^QlTZ4qWow-L;5c#r+3SecdD%4i)k8djJYEqZ+)ygW?{Tr?d7InR2$pF)I<iOaUU zM3n*LU>@-grdAQ)V1-3VUpONC!(iOW$3}OIrrF6Qmg4&wtmzKLHllcpIWJ!9<bBi$ zZL>FfY0E{<5e1U7jLm9R{GRumQy<e^N;!LFAg6OtlOsci2AA@DuVEUjOJ044T_}+e zK<t+uIIkPiuS-YCo5rsmI;R@aZSmtvYVj{=O`;_Eozpav%L2Mh%8M)>A{XMdz-}P1 z&;C`z!uk4(w*fvXx%xJ-Rvwk}(}xJt4*Rw26I?+MW)8%Doh4!p%JL>{tTqaJeUdh) z48*Je#QvW=O<r}@HTXMi3TGvxsa{73-iC->(QfYi@Mr>nz@0&^Aed7Pl_AMSIy`Y& z0r!60@9xWQ%c@dVsvr@>m>x6HjVc2gZ($}JirqFWppSMIgSU>`3&-mCShPfNulw;O z)#$VP21XA!AL0FKz?^P6J2=CZBdw`lOG@tu?vV7tHy)t1j(*W!LwM4Evg3gJA6z77 z9MHE$59A1Xi1&y2YJ9aYhJ9-g#Q?$W<KFUN6DXbt48s<iSj^<lkMVrL<QQ|r`2wD9 z{pU3{Pw~WHAxSRnf*9Zuk=R^<l15#Z7A0MpcTO#Fi&q%2zctq5lt$U%zQ|q@ecmbW z&iFoAC}#q&@73-P_H(?!^ll-Q>cRYe&SIe?044y2!X&^XXbYP+M_PXKYWLY(_)lD< zV0@S6_LGbjWipF)h)AuqyWQrmI?dTTI2Fz8SE}dilE!FgNDg-Or&=?fG55halAj^> zv!YnWPbi7t>*T<s==7aBjk}J1vXwsL^`GcGOw{?fu7PW?=Z$+}%G<~4d6E$}oh=wf zaC69c;^jI=HU}y~3V`*@fj0MnNj?TRHqE#-lXQ9TZSE<33TXBRHy*gXNKjm}q3^XW zrI5-<vGfYu@(EGcmilQEolB?(-@YNK%Aq6`;8B#K=`lpT!Q4n?5p7%T-<P1tJ_Wa- zf8L1r4t<ioB?Sx+4;{ne#NIf%6xy~c%<>Gfu}wdYhqHF=1@UsW59R~=ILj|^OVk>y z?umPEqaRI`5SVQd6hDcqdIh^Aa^}cB`}HZ$Q{$dQ@|`j3CBfoM@ef}K^25JjIdy0a zT71%LyIP&PXSwpoW*x>E>%>Cykj{c0HvCz+IiPCkq4}990HTBN8#!|j)vNcF{qMs1 zPtW=vpZj-VMUlOs1^kW@&%PJd|LSuE9UTok{@sr7Kf*)N|D&9PP3~~OMM7)gFO)x* z!hx@^35TPoQb80)6znK|3Mh*`D%s-L6@N+a!2d7+3IaZqjvt)nf&)b=lH8TE&dzMN zGjkQ2tJe#-CblSmrbRvXEh0q>jA{LQZN9$pkWu(i;F*Zac&=&#Qn-UQluo#w+WX0! z4YN%!7oJCGrDI`#2NFJLgIu2rD>APC;<*RAi5D+~&ZbfaGs>FpcxJ5`mor_QzlrxM zHfK{zuy1xpbO74zQ4@wsq?Ct%Z1X(l4xUH0ag(t^vni#p8BSR8icvXbRK;0O<ZHp3 zP3Lsw)n{V-X=v<ZUix8H3uL}Dt<ulZgPFr6yX=9!fGJlynWK=H4n%~BgW#9&x%vGO zjs2FIP&kDy%wahd(NXcWI}^(1X)|{8vAo!FP;f>#&K=qJE+r`yckKscB~0gP2Dk88 z!#U_B={n5js=o19cpZ7*7%r2w`gLtvgB#1yQO8??fzNoH6)sQVNjhjZjAsWHEf>cn z%$;>Zly%7`<^?e)W!0P>sgV;Z*~>2;Kv0x%CRUUQ#bMwEMxDYJ&~lU+qu0n+NA2F^ zrmR(JJ6Lw38Jvlu;yPL1;0qqr7hI*aYW2m-1;mH$#4umMsE9^+JMYkyq6f&cKVM<= zB-4wK+hA8Ck9cfG_k4JJU>@I8?Z1frJqiC${QL)5e^>K?q2;FrXaE4~?@BA%e_PEB zT`a7PO&sa}j}*1gzpwwjuvcq9dn+wte$8|TG!gpD0Y&UlgkdR4Lc_Hhm?ZEOHUCUd zEJD=S*l7u18Bf3tnx@RO<(jkU2#w`+mYtKi4M2$C*p^DST`b>pzCJ6tDqcLx>3Q^d z$|19u>1Jnl+kZNooaQ}w`}*4b%E@xNIxDo>eF6ZWG1`$-hkEMR7XZb%_Xoj*$NA|1 z6-v2v(*KJXPaW)OahZMl#vi<-KQQTm7HYTT1{dBNy+>@H5DH$2LvsHO1uy@GA{bx( znJ^e%!98l=5XDz|9}-GV(LG{7j^aIOV3y~Gg-7_E|EZ6DFV*>44aHaH$ya#4_5Q() z<Wi%<Gp5E@4p#G7m~_W$2bR8VUxfWVKEO>J6Rxz-Qhpmz1*7SHD3N%2|A)K1vISmL zZ1k{E`7d)0Hb==n0$fPAiV4%*w|N;+L!wPlix|?l;_&d)5@4f`){u74R^6Eobb!^t zuS4K16oFKM9bJ4@&0cF<q{WG=Q52SMB%G7pk&@^~mXYv?nsOv1RT8nV6yrNL{vo+k zL;S;PRPP0RR789jF^|EChy%xaDuS#$Z4VdrKmBUIxz`n{=#gS&2pBlV$ya*C>tL-; znNQUll!^CXO#rUgf7C>mF8|QHlnF5^4?|K?f>GxWoOeX{CD<e~Sf1oy)4X-}5Wds4 z65a1inAl%69&0CNcz`(3-M!{5Z6IldyrUORo7_JpPE%EqxW>M{(J4e@T@2s(xx4Hj zG>BE&B5H`}LK>JZDhvr;Duo-Zzdw0V330lM*j0#A2*+wo1st<(+)!p``1pz}+ixz; z5if5j43qNqDwRg#C?dCx7E^K?o^uY(2?9Z$xQ`1{B+p+C!2x6dC=<|VOo>A9i_L7x z2CMP=^OES)<xJWptEt(zVp(<?cQ&J&<<v|<u{=4W8>i9LLRvPdR6d>ImFvh>H6yoF zics3NMVlw5K%xV8-=4HynY8-@n1HeJT)KkbG{yICP>3goE44PZ7dvtk{0LnM8ciDa zD!uTm+wh;*=UFj<IEI;I&WaJ;L}kSZ$J*StE?}-&!Avq}1~gm7LOr$SW2Kq<z6`KA zrk-1GvQf`trWgd;oK(weT<)(EFq01fbxo-iFpG>c2$;!(fxe*93z%8q8U)G~#6(-W ztm^v%Q#aA%Yuf~RDcyqT+P?DP>$P@_EkE-J5&}GdnY8Z@#YJtO^7*TYs(3SrySPl6 z6nym#IMc$jRG&*wj3*oHKBlcw5hSg!YQ@5looXp73sEFHj(M<E+`H#>T;WrTDDcqx z;J4EwM}^Sunrwh+hEuU?=M3kIbuNr!`mKgoU7J~lJJZSEwy5c+>ix)3rHO%(W<M5{ z_Lh+(ZwERJI0Hf3?`zDJF(Jj&NW~V6B&9Fc_{vC5%OIhzaaFLIfSW_=oh5C;hL=MC ziwQ&C80oX1{agq2y6Vt3D4pe>skg5R?NiZZ166S_Mn)7;Q@iY`x<;X?_1n>Rpsxp8 z?diK<{Qd|*=;q&01@|hsM-Ti)`4rsGMfv=me?$2c-tR@($-5y7Zl&mw`343I1p|9x zm$WGzy*F;pzNu1|HP!s~)Ryj=@V;u>G<2(QWvWUaZj$1e3Ep`_YR}bRUrD?dZ84k@ zSaa}fM!@XVplMxE6LRcN;_Pre^q6*3k$@FQvuF*}c*m^Xbsm4GeJKY$+Zp*m3Fj(_ zs)#RyX!yF6wX<BG@_`@$NXYzmNuXPIWyn!UQ`n>_EDB&Nt??=w6MY-{^yY4us%+9m z*OY+fO5>FpraITusSTTfjv5ezK#6_~7WD|G&9Y()6q@zCJjmb9`)t6iuJ4_$7^%Fw zMf}#%Buwh&Tsr3>HEP83C^cyDgxV3r=P_G!BP&~}?2B@P(c@U!<zC5`98Pp>TQ=!e zmQ)WGt$}cZl^fh#YSq_g+c+27Ym0z?3@B-U!Akw1J1m$10bH6Ata968ta7QF-YWAF zS^(GHoZs2d`Ok8#`0F}v6Z<8jl$txK9=-Xq`n_s^H9EDf`Jq(A1UA&k@qtzYKfMCB z16xgK>)}8Fv}10e%0hIWeb|wJ=pHnwQW54}8!d<I0$pQvqjHxlBK&Yl;!r5%CYn7c zl-vcAw)zv*^zFhu->^pwEDauMH6LlZ!DmaT6$e?eWMiDj3MPXt?XsvF9qiGCE?4ug z?qxN~B;iEV%myr{2<GVCN#+<qTx9&&9OOCS@5{i>SGhI(7gX4@g4=o5J<Gn<yZqRz z`dgYaj+_|&XnUJ`>X;F*J=EN=Gr2-gU5%$4&tLIF+q%=u7DGV@)rM&1pBZ3nc*d+m zn>WO?tU+9o{_x_Qr9h0XDdUnDygY0Rt!MYBTk?aTLdOSv;&7j_<$_uk)8805L&5>N z#`0SfEW4xUgIN9?36yVaD`y05ZU;OSg9NZ6n93BtMT1Ls%R_tl#Q=$w21Cw-{_GIB zKCtCcLO%_qoq^hx1YJb^N;<w#C*rjuD4&YW*0#^XZtX10zb9|jR>{lH9p>C<^$sq7 z3|MC9#Kf@e_hg)^&dWA6_NR-Cx&VxA|BorwDJYIJD;&|eN+zg{F=iRE{E0BDR$QoN zrbu=0^bKGPR!f2=y+50gaAf%sARL!DrAvsvCzqs-1(i!!A(g748C0H`fpBd3k^vl- zA*D--e+OdmW2PkTaasIN4HEK)BN!ZF{}}zjvhpQb9Oug7B_q%!7RhZ>D%J^wQE44s zLf}TwIjQ=6CZ%#lIIPwr&n$mWR>|%WWy_z1zH^oUQ-}g~Lm`>c#bli36N=~BfG+rw z-HXZ<6AFtZ!1}siG3WxZ`hy=OimeWF(6q%pQUX38#e9}jF5F_<2H{+C0zOy@xr~Az z2zrD<HwIEmV1N%EKYaR?e~aKe5UUdF_W-<Nv31#6{{EJaK$0qlhEgB}TTU>hav>M{ zpb+CtrH|Jrk9LAx0Vv0+D9Y$cX3{$!-BYw7Tu=j+2<)Zl#9RbdS7o6a0;>#Q0T-E_ z9-Kwz4XCY!=K37v{50(`DWBcP=Z7Q5P+%E!E+@64t)5j}GNU}_1l92Yii~G%n5^zX zLL)3k?dIAJQ3LKup{D6ZN+Gsj^;|X?tR#&28aLDpM>#1}%d~c9C2?<_oS-&9O(Hs7 zM#I*H{iErs<w;r<y1;gSE`+Tc?f6a|=|QS^Ayn(Sd1I-3b6!!U#-%Yso!ieuqZ6sC zV>Vbx+m#}x;Yms}wm^HjjEAi&!ueVH_d8LAYN0mnsHk19QD<$M=5_FKctW*!E&D1_ ztB%dZY6CF>o=DxE6CrAlF@7?PwLc=z=PJ={+>;TyUaOYv<k!N)+hD%?fp4hBtzNRe zpHBhlRGyp)QKK6D^8WicCWB6n#UQoH%{g>QZ$DUIb{r3W#Sti5*T#rd`^o~ffgB0F zU~Pttdvo@op4t?3JdwX{^ZJct=ic(eHw%^)qX#XTlkB{qxl#$blW@J^j|k|xv}uvZ zc}g<$KO&QcLAZHcsFC3t?o8;nhCRwv81V;4G^VA|<WBMOQ>oRyw*w<eJxF4=Dr};+ z!(A!0>Yk+5g2%t-E3vKJn-dRr)xZDJ5Z}|K6t>nC&D}-mF_;M8RUvCMHy}9r(7vG0 z0fg%4{hN^_We`~JxE6_haFt^RY^YS%B^v(ZB{v}Pz1^tEvO(AvM*Hqio|->CR3~+~ zCQysz<Nc-{js6LRlv9Ji15`p+Bw<xr{1Gi-3#wIcAMymSjFLk=X*a`pp!|^WHM306 zQAM!9s>0yza$RZX{pft)h->hu+a6p__9k!_%{#BBux)+lB;pI*1i<JpMC&%&A7=6T z0M3e0$25=fB+HfRA_Lxb6)5de6M}D5!Xt||E0JgLsdL>qt%ZIvCow00G<YF3a=}W? zpyAXVECV{$ahAEP6X+_a)BTR88nmw)U-OyJ?epxJ3}i7@^BU{}!1?RnI_v+8{r|Ho z_`Bb<cO#Yj`Q3Ae`+v*v37Z=@Dw#O{gA*%Sb<#=cd%h-nN6iu2l2Ti;PGqOZLMk|g z0JO51hlUoE5*}2+ZgG<>j*PHfM8Mg(3R=u;>#PsLP{(-?h`so*kc)24;T_u9{;=&P zc&5!kTi)-4L<Tsi-sdRG%X8-G18>*OwzvCZ9K~OT!^nt{%ZA6Fmklj{Qk4Bs^R&Jm z{>=u%U2+C)OrthBkb{IBC#8|t@zUaD)r<xQb}x<Rt18NQYrqLD2c4mnToJNYMj&zt z7j2Gv;UlLHcso34m6>Vl#00*>N1{gArS#DDt}at%>|~(e3ZB#v=y&JhdOsQa;Yes# ziMyveNA?6O>GqPolhSBh=H<h?urE>iCYk=RY_$6hC*C&J8Q*@6>vBtpE`O#ttSz_e zwc>WS6cADWuB_0^i$=J046WwOA5gSuM1{UEWE6wiSG~0@>&Ivq7<Xyp9`Yq*;&9{M z)MGMUJ`&&*+~0d*S6KoCXTQ8Lg9MH>y~DPU%VWF^OG%Qn9S?h;j7k@LPo_#hyL+(t z+gGP4s%g9Q4Vpnyd$h_L=g8&p<VwBS<0qO+XP|!kqC8a)ijYEFAg1*D9HnUWUHHSK zT(m3Y$w$i)y7&<eSYn&47ggw#Vc}`Uq?;uU5)b;8Zg^rpVzxvY|JFY{E~Ge{wcdRe zZ@smd90%H7*R;bnwn)gKjwFQhLFlXxjtbL1=r8c#b5XQF2xBOYCmm!DL@q3Dm=+Nl zC&U#5BO4qiLI;9R%yefF!1`2O<ZT@+20+LYGAitj_yJ^fvdjXM+$iw$kp2HK_D<26 zgx$JmY}>ZkF*-Iow(T#rZQHh!j&0lM*fvi7z4q8=t($$$O^vteqDEajHRoG3A1ElP zY)9+p4}FUoaZD;YH_$nO_Yp>Is-$)ibg-j8C!HMz5=62dcW5K6vXpY&Tb322;yi>d z29rk8%u`=yI||UZHkmbEX|$_TYK;L{u^C0nElKd7m#3}Y!A*n-T@p!iBE}Q_)0gAw zxyiiFn?Bz8ae5x6^^4)LZWdTQ7-A+hs^MnzT}W0EpOUTB$7r3I57dB!FmMGbUl%9i zV+O)>LtoMoS?CT+r;x)0#qs;&(DQ#8U=tj?P*^HtA`*26hB(&fM9URikX*b;nqy*J z;ZVM9%Ny{bX8XD0t0ImFRuU|i8j7i}Xd0RxMx>Ezf)=o^o}{5d5zHC281W2a#e_PK z*oJGw9HyzwVjye^78?bFqSn>+;*F%(-#}p4laD4NDs1ekqf+${rBWbU!bc5^&0wu1 z#N*SN#;hB9c~m)oz}6twmbf8Mxx^NNT$ULhbFKa^cQNF1$p`Lu)$~MR1{l&l>GS+; z3uI*XArwK3xeay(d1sCS<&4$s>|1JefV$p=+8%0b3;OpG_daslIi8R&*RgBJMNrWF z2aYxk*0KerGMWC`0Df8NJ=qQRJWS}{HSR-xj2zppiirC%QH4|4aigSl>D*|#Xb_jR zAnN7Tv<#vX#-P}+tzeyyj1lWNy>-K^b^cJlDJ(N_P%!;Re&ab!h0MF2m=9_!lTtTZ zH!(t_(R=o^rCM_1{8Y|xd0Nd7+=%@HGo2Lx?(aHLR}p52kMm;QzJQflq+=}!?=IXS zzjV7E$=*HKCrisNdI{f*)iFD{N)muWp+;3S0VzVM8MD}uN`hQ+xj&AK)*vO0OgQh2 zaL5u@Wvub<7%9r&6_<vE4Y^9ikjzNZq58m2Y-9|piD`_b;UZaUuBBOfb>VI=xMPO| z(KYHGIYs9r!n@yCZQO<l#<F;X9_(-S#&XSMXE5c1){ap-Wq&>PsZFsB_91|K&Z(ig zXi0$}dsgY&iHubP6Z_KeM4{dQ(#mL6fy8Q6MJGn}3T3^03wFv4?+teIcUFaOADJG@ zv>ME9f>#mA^dWc_?oxAJI_!Ab-|DnCH)7|<tyZBX-40SSaPeKw7y*UmO!D@M$o2|p z$5X1x-6;w^g<x0-v4jv8Nl;HIhAdSbcZ;Ct^0e|p#>5|kb~xOaB_Tqqnmm#!%$xvm zF?yUgBlVttKBJj$wA5cAG#}H=0;9JW9e45>FPH|K1?9f9tB_De;Pi=~^s<*UC?_;X zag8p#zda!AKrCv9%d}KV&!e`gxVQ8};42nnMbnq%S^p5(wNY8<uM=f1r+l-Z1^McL zLoSQk>B}~C_?#(LSGSnLNuOJBj5XwlBv-ho-n=|8zFEIAC`Y?wa+d5dInoaZ48Cd_ zpvgL<SyFPHvH)XO9knsr?c2Ebu))?#VC3s#PjHMS{+F8czc;Y|x3&G}hZnY~<+m3h z5YT`G5D@kM?T44JwSkk<e`{>b9?)KYmL9*kp1aaH(mSma!G%D;pyDRUtZA@P1fjG> zK~TVeTZyqpM~x|_Wy)?EHPJDvtVFebzQ!L@8I}zfft2Q2XkIn6e4CeA4ApF!Tb9-} z&q0oSr@igAJ7p-4KEJ;SN4<Y?Xs+9jeXiH8-0wFjV+q0iH1?G^E(VY=vu&}04d6)` zE*yp7b;mEuaQ{SEV7UrIglMl`hLCJd4;{C)O$PJ4Ov%}PU}C14%~s8r?W4PqW9rS` z(7@Loaje+aM@Cw?k2`B?&%kc=!d@Qji!pSM4$0zdU-WBjG9lZUVA%e1Z*{tq#@XHr zfjMf2csAb8c1sP>a}h>=j_R+y>FD~nvgOzgbiMVfb=>LF?qEc{9`V-piVnS4xjD!2 zAq6Gu{dO@z^hu=lnuy*RzBX34CF1Cr043aCe|EEiY<ptD?1Eb-#kPm#&j4<9bl|~k zb#NfX<Zy6c#nc-VPaiju$&0muY<CGO$2&UuheKe%**(K2Z||@eEx)g<{ox1s5f@3= zerw?sVm0&k7VGK0?R!s$Z={*f>ZKFbcfUWE<(sk1pwWNx+wz4Kv->0j!4`9G#{E>U z?S>q)d-C3AY^b*Fg}u?<3c?FsZ|}$fUe8&W<156|r*iLl(;oXPNAkm8@*_TSh0SXV zKG$sQ1(onQSLY=Jb_cMhr~Q%w`+e5m(|&W!;Kc*F(<jdU5gKxB`63VhUA*Us^QATL z%>IEm^Ff3vF!;{)L52FXJEEOs-v`Su>9{9}>9gMtoC=gGh{?N)Aw-p-z`iGF&k^*` z{{+KVizp<IBWS?i+<TNT(xK7ZS;yOG>#i8HnL$UVwZ!(af*o_IwoEI~?-5GlG2Wi; z3UOrRRd@?HILQD<XgdxYDyKyHW8-r{`0Hl*wEEVZsneODKP@CBrC6k<yr!8wm^YC| zoJxiVgqY*v8m=k^f+z5H_erp^2bOq5J)egFPPP<*BzF#H6X$89qYyZVD{yC;a6G13 z{K~t#)kT+HaqL=(u95%j`V2<o(2{*%q0tmk`ql{|AMNWilS3SIBk;?O2_=Qk%o`_X zil9VK#292wJ&z$d&&h`gFKUH^3O)H8Y4J_M)6X9^1eAU&I}>!S`D-d4h)}g?ics@7 z7NXt8rQ$Y*D16|cL;`RQ@J;QhCS~fPpI?&%A>!g3SUqSTw24X^-M|TJbrC6WSlbX9 z3AT3$j^0zrWQ1-STCmP%$u8q0b$rqP%_2!;Y-@IFwK_kK4->D@GW=<?VLn1}oJgxA zPx6T)r4{xojl-CUm>Vk&Uk6$NW<Hx)XebW7UEs1nnMN#3P)rMDRK}O>Y^R<ZXBDLr zF5hkRW@xKV!IMa;ag&X@n+(OyywrcyZx^P)WugS-G$v7*<X9-})&ZQSLkQR?*xIs| z0_{_43IPt~Y0&~&C2z}(*@WsZ{OKM%ct2FKMZTnfktL4xd@LXlIbs;M{}OmTbzRgM zOgwDSZ;&`M1X9>bx0<YZ&_Ok|zMjH|&}i)}#?^Tt>O=O_yaQy<MN%VBAOkB%sCuiY z*9IDw%R(JGaeM<Usy@kb`DHVoaf>;U#3192zuLV#yA+y|OE>7X6s2_mnb<ape$87@ zZq|}65)isUPs~~#+zP&~_F{xz4SeMNW`7-`<9MdfYt4p|v?kFW_^X9CbDqk~CnNoU zD+G@HPov|>iNV|wn;W8mq9#CGCWM2zgdT+=F{>%Kz8QI<Pp(QLIfSi&RJ{(?=I67w zihgz|CEH|#1zx1)18u~X3tF~~%2L=|N{8q21X+4M&s#H-4V&js)1_CeA0?Q&PhE#@ zm_S!^zZ_lI#K>I!a2QO}+4^_5)aLG-wJKt9zfAF^u_ijHrgNe8@(zBi^^fcHM<RQ1 zj76>?y<|QSR-;geiXtmc{uSG>8R@%~qcT+C{00QhZhd@XSn+MLMY$D)EmXI1*~qNu zf?MQ+y-IXi72Z{SK~pob73*QC%Lg=Qf{m0--qvQqbJNv^sRB$@veELqb^n5dm<jiN zGLM_{a#F=Z0yE%mpZ`b{<%(F<Jz2}-bXqkBMKcBVcA_2Wf}JWR+!{c6aOU@*!sA97 zf+%G9(sXu{5XnAM*6rY8K7D)}fZ7E#Wi3TJR>TEMtcW!)`bD@e8(7wO);snu9d|vT z<W2da56G#E5kEzQ8x7-2Plf|4%`3x?sa|PFVi=ojVJOXFhAGgPnV^kMcSl4~ag;Y^ z9C_-O>iAw=y{8k^>M~xKs|b}X=W!B@U4nEWO$z~xlQ7z`Jcq;`jm?+6XI-}8>>!Pi z9J^P*rHOP=b4T@nn@MV~b!1UF!j&A?a8w9&K@ki%3Eum{#>Ep*xHa2sjy{p=&4-{2 zsx5r(iU>vj+d_K7o`OU(x3E7E?FFKE|L?!qSXoEv`MvvB^ja@3fcGwzCHV}FvZj!+ zJq|BJpA2Z6Uk&Ma$kf6tFxBt7`XP<$5Ut|mj0DuATr#q!O6!5yP=)j;kL8&&Cr}Ut zU*=jPF-^>+_?r;iItb)P@R+y7xV+Y6Y!8#i(Fgn5IdJ`<M$?IKVVIEI9~*(l>&H>@ z(q1=9OJdtRcRH3r;wMs!o8O2}+;lB9uQtT2@$oiXddfD=3zzA#;zW3{^J_dQI5R?8 z)@v8nG^tx6D6b*X1wlcF{Qx6=l>oEtQ>rWy@4|387XIq^D|0P<jX2VcEHdK-w*Uml zy||b|60Oj}8@6DsfdCtYWMyPQOfHhtW8Tt8-aTR+TnaluPV0HmZmL<)e5&~&D&`DZ zqD+Qa(R!@HNEF3!ZzJcEz|b%~oha0Q&WaQiaS0^}MH9DB#=kL9hsbo2BFFxwk(AsC zq5my2cJU>Kb<+$@joRnJ_kkXvZm0{Fp+Z|dLtGMVb#a{!*9yt*g$3_7$=<4WTRRfe zuvvoxk#}?6LsjV{t5&5i`C%#Mq;^8xGz()ci2mBDb7mHflGkT{h^QRcxREd6R>o`` z#0FR_4yA)3J!Tb0t{EceGy@!3%I1c&ndLF>9aIgw`kp!W*+sM1>IE^I4f825P7CDd zmgmCLGs;$mQ0o6+PVDksVHZapis0YJ+k1c!%-3U$oN)TX)CbHI1LrIaN%_1pb)iSo zaqJvAOsFFr!QMTZlt#|I2xdqg*|T7pSr&+5Rt{R~WRWhP6eLGB?`z+=|5X=%81hi8 z2)_r^|F$;v`>KkR-S@)(0`nEa^2M=}AswBRk509L4%wLaFwtSjp<?}TSWA&;iaKbF zDh>p@6LLc^$ci>}rE20Pku8eW4?jeQ*MJf);tjI6VbjqT2|$SL7ZypW>viXDL1J-3 zz^ueBjC2T$v2x%8HzTdLVtu{&{JR>3E5>PrF=M_U+5vTPBm0tqfY{%PbO&*aWsIP< zffpVG;=>(JACM%y)k!)%w$_3mP+m<sOpx+H0xX!F4|Sf~$Tv@4I~qfeHt+ELBvGe> ziXRS6W*-UPV60^0ozNnyer|#8tCd9`B&)6!Eow8k+F*C6_{&f>0Xx%M-LS!=uqg_A zQB*;@AlxQ!ah|2{FH}8_Gfd0+#EBjGXY>4y;hR<gGzbOBUkLi9aT$F1cYqvqUsrM% zmLpNo*FkKe_q@~48X;y$7nnjBi#C%uizO)A>@q(5u<I(>D(j+v(ghn7VSgowjzX>C zrg4xoIJ!k*sU}lPQzNb1RlRW>Yw3V3y!JXiR4aJYV7N@f@G|5-GVb8h8bY?wu>|!I zCDl0v4S8hsDo>}$2e4rD)5cagm$fY8Dgs3o-t;Y(1m~Uc&7a;64<(8Ye~LMJ;2AA| z6~hkUQdE}%r4{aMLYsS>1h5NrL00TO8P~e1pdWU@#hMTa4NTw5G0&qVyPp<Ce|)r9 ztK^?bDBo}yBCW<KvOv-jcTm7xyLM|7kn5LA(B{7ATV{<tBR6JIZq%S4J=I9rfwjiA z8rqqbH1v$9<wr3DK7L1c8f3i~7wu2GTFxInakT4gkLgiWr&0N1AP-0JCwi!LfY2&m zx-tnw&MVl&sIE?{v?Lysxyj(A&VpQ43o~rE=%`(Fxw^8${7BTyLDPp!`6!!(WCJ-8 zl6xww>ZkckRYr1ve^{HG^z#)syEP6#s<Ff|W6lTGtFAjGmeVJnPIGPP#9)kSt#^7{ zLfpezZ)LDMA1tugqzfwvp^yvI7SwFjc~EQUdK$WDu+3X|!D-{z!ipM_@txkuhBx&y zjU@t1tD8uojVYW5O}|%ML_oh>x-DJA3(*KD)&t20PuT4$9!&`bZ95`EHPvXDle0$) z$sx=X#QPf<r5YFH({J^GQb&`7Q3SJ7!<ryl!A$xcWHL^Vw3Z9g;!~K}A}`sft?_;7 z@m0-~8=D7kD8xGWkYENu&v_*DjE2>IeOa5n!PuO-Kgu36Xk_rK$y(O1H>H6>6jxST zmE)22+%}ld%edZs_$&Gh@=S>zDQf_<ni^t+$l4)cxQa4oaE*PU>|`_oxuKM~kxvac zt7&|Z<HNv|dJh?`xAx@Rc{_ifc1>JB_VwtO$yf}4VS&E`5rIbR;obldeQ-2`Jt$-r zh*e+?wAy^`<Ua*A_`->QEPnH?`TDIRZmf4L`j8cWmQ{aZHNQhNSC+}OD$pP*&tN|k zy_0ixLIM+}2osdf%gX!J`op~MK`jA{kh}<U;xaj5<TJoDPsfZJyGDBVcy=#A9iWmx z7Yik%)_Qv&-NUH75wixlm1$W_dzEiMfi&KUZP53`9Wl5MLF5;Rba%ZH2k<m|PaSSx zriJrvVJd8bDa#+x%tffj>=1ZCXXfu$^KyJVGH5L*Xue6+yrx%Cwk3-27Qfq`k=mZd zMPmhrLjreg?>t!E1$SUGJEaJX4{g^WUv--i8*sgIviL`Jc35vP|H&@!V;z&L-Y>e? zPH%{RRED>d)~6ofhkyWk60ekD!Wj0H&1LdbBZ@KJ9Hpd2c;`{`?b4|*UIp%J)_R%F zsEkCs6L+Xj(I4j<9aT`+4GoId)FMi~<*`A3vy2wriGmy*1Iic!A${P<Z(w9X{_O^; z?a{s9H}zf{kaj|7?K+3`W!9m7fp84y?J>OIZi4z!hI@$zc$E0Ve5j8XhaNn+zd#$b zpknmN?}7K<nwEup7iS3lXc^4d<dPL~;TfKxN0)Yo_V4CE*;I&q%0vr<(ed)iRT0&Y z<b|kNX0Wpan8*zRsi8fTP=-q)`bHMHe|LNiQb4>RG0%o#2I^&LHjETY{4x!Q;O1oZ zEK2yCFUQ2n{VNDfuOI~*h5HIps+!$^Hdz;-S_TI1ovY%kD^-T@NuAKgF1b|CCd$E9 zY_?075)nmEMS?vHB@B6#8V7;}CQ-yEsoqI8>Su;Jz`i>SuHe_qgmJF_iy`E-4eiVU zyQ=qaHVppP=yIB&mOQR|y2zp*9q6A{vrXtxidMv)AieZnn_|kJSthWWBNRmuNvnU{ zhD21Bofg%KNQ_la3M@JEq-^XSt>f*#lGpaYMY_PZ9!*C^V|@Q`T;4<kq1QwTT5@CD z68wO%W}~IZT)%?$62<gOES?RGlTOHwhrhFPkjkc3+d{HkZL@u*1FS15nimD}m#{F| z&;CxSSX6+REl7<a%lyXGrFBpv>FdU3$EXaU<2?&<77^c6r#v%#!ZmzNZ_7KjU-K=% zu1H8c&_fe_fw`eVA0ScvmHK$P@X9whX(1gafSO=YH~gmE$2tT%KUrf_#=*=yd^>-p zZ3x9qe1;J|dr%*2+x%P48(ZkJ*PtO17R6eWBpg1>KD!e<9VXQEA5Pw}anWSsVFvIk zRa*)iZf22#J$O3DFG*#6o)6$J2}n-(e&Z`$qO4aU3V+%SE<shr#FS9EL+7FaZfF&2 zf5!$E0Y4eTefb+RW$x~oqlld3s#b~a{D2EP6IA@5*7h@v(PtHWh+Mx%mCZTUn;1sw zU#Q_uy#zw%nMLzE6ocKMuP;R3lNiJQgqhG0M|D!MVbcndWGB0RhhP)u&VIo@LR0@4 zQ~X>mYpqiJWQ%xC1&_EVJHh!-3G6w{BzbmSpW9fDsbODgVXH5sSyyyUTycdexqb42 zH1Kdl6}^DGfouvVoTtdimz^!C-zfnt#`w2(!1HBrCU~dQ^LVAxaVb@IbTn8swl4m# zc+%ecPB%#!X2z!0{D&~Rnx+vyI7Y}>AgYo9Fqv`wfX?%-f22D~<-)Skfw#(f1IdrV z!Z||F;+ETA5zL5keV}zi4)SSI)~lBg)(vL1?@-pKHWv0Fb~PmJG%W3OOIK%*4g4MO zd_aJq&fV?zbYth_J9hiI{PJA=pW}C$CxJXCLY%M5e7pILKLp{tFGg1aV(%?7S=E5J z$eEF&B?{ssQQ0ay2SspfL8u1aLiU_UGb?h2<k!h~2PRD!3ociU`K=0J09T0mli;%U zQmCoXE;))kS#p{G>p`hXX1I5zf=8&_iw;ZuH(Ag&Dd0=^<OA38)>}P<P!QC|oLEJ= zz&qiCp>oB%JdQ3ax@mypR0GIK23bxDq|2z#yxVg^q!<K`tOlH}Mk4+<cA1i6`w%d& zB^4Ah1}rop4Isu6gg{7*7y&3l94M9pSYB58k$JR*DBqGD`vXi+p!KvCjqtawa9bZW zAY!*cKVvjRg9H*Ij8~obE?*H%otrnh-wp#kq(B3tccVH!FRyrDxXj0DQ7c>#EEag& zoQH~1A4GCed{-`D*Kg~D%nQY5N5O3C{5-flRDYW|?K{t;KKmj<q*_+T84#}@SY@Ix z<s<QN<$b>O9v%sHXLp#5_K8LNH6GLzB0C(=(U;FF0h#wGWK%ff_KUjNs7w4gae|O% zg2P4ilvtfA^ioMeapw<V6H$)XGRB~(efTf?NFd`#`dwsv1+oApG3&r^60ikP%E_WP zyg8FGJ?iwH)Z%=~Usdo+X}J3tF&ZU%Y%QurHr2zM83qj5wz53HVc>-ECD<KPC0j@O zHSHTVrrPWw!BH;jkdapq9KpQKp1+mH{?d+Jjtc(P{*B^9E;*^vf@B4ER2-zfnFxi* zrjV^MUI4a9U`VuMsE^I(9?*e_f%_b`_^)fJCC+nH$kr*J%!U#Jj*%Bux%_!Oc%&hi z8$-z^?nd1ucIQ#6Uztn|&!mcqpY4Ns`<%xV24TktN(pshzRMoNs1p+=`pY`tZ}%L~ zj#=l8CSyt(W9NhEsjhw5o!8U8mk~qPX|RdztF0v?-LazUK$)((!D53)eqWkJjhs=` zoRK`cX)&{yl3m@B8rGwX6T~AM4j*ecY~XrOyu;iB_Axu|{Sh*_QPlN<B2ielkhD^P zp8p!aT!8dP6-M?(t~8%&kd$Xt>;_IV<j@dWo51%0pGED17&%0!-~K|nHn@_f(FuGU z!C}zl2Frlv8|?RjYmII<P`r=drt|^o66tDyxO9#79q>Nnd82b{$0;&1urF{!dJD`e z?D7qM%lsje74&Z()h*ii=o+Sf1ZGV@v=2{oh#AH(e1C8(BE*b}K|9ZQ*KsJ?s%)#` z#LYh;cq7UBLe=p`iX79G*1awC?dlKA&4iR9%TvE6s$ukVhT&8*8Y+qSqgLS?J*Mi> zB*hXves(--va=f<W_r3i>nnAnyEfUP0bBWxp&&E*4fp+>;+aiBnpqO@YkOB6O+0y- zMT0vT;)ae143r6tF*Q1q*lh{)AlO<;0@|SrnBi~-*fj&uH%rJz<d_z<drCdvM+)ef zrD_DKWzwd0t*AuB$d^M@k_29Cz023FWOquZG`p-5AoIRazO9^3BwP+$%0kGJ3_f^I zGOBi#C!zs&`0zj@U8PJ_<jXigm7_}5GfKfn7~$X*5xehtt#yqO!kbA)#U&dZSP?s# zi}OxRT1Ba@&XE?vHo;T`(K$8|-Q+Uv{!1%^{XjR%q(3dlYTwM?YRukVN66lWw5=aZ zEoe6aMVmQ*R?dD1s^;>0XD`F}HTzy>Bvm{hT{fWoZH@SA+V27f*VtW{XrfUk5TD2q z!oA%wOU9Fn&Ta+4y$klCpNpSWE5&XxI?ys-A!R?Bz1a9kOREC0>Baa+zeTew;@#ly z%4F1Ql2G@^({Ec_cfzc5+CL@~(d*s{QvRcVL7niI<fY6@60T~B?H>$p78X|L==O1v zYW-?1f|U*l(h4?V(Z{_N$}dQDwh^6@>;x<CfV2hWd*(rHf*`Jaz+Z0+73?FTz9odG z)@5LXO6Qr&0Zy5Sl=VUp5<s+bv^pk&5HnQoUV#_UzpHl&hS`VhAvmSv1tF*}f$Txx zD_<xk@*N+6h8_?a12e=Z_u1TaB|O>uavA({4S*2uCy@m2-~NO^qF5OGv(K%=#+owJ zVqGN=@+cwWn;_#G_`_M6N>wXg{Lv|Eoi$wS1J%V!*2OC8p_b-PiT}^tyDq=|49nO< z?6FTQLFzA+hqTO>4L18Br}=oLLK&HzyEPmtb&wJ?_q-3xE!}!1QT4q2uO+xTXCz9Z zTp}G2U*Wb);Wyu3%V{VdP97uWS)jUlDumXS`Bp=(-u8XOZE^j9XCglpO0y~fOb>v? zPy!oT^^WT7Zj^pb<&x%_GNjGQK<||8b!cMf8rW#I>k7C%6g{%!+s!yX!+x=-H`SWf zsKP(NcKd*`-qx=OE}fFVI`&vEFXILS7A8gL$Cy@V5vBz6nJPo8CKLi68VOy2p;1xh zhY8}=lDzx@cKU<9T#j&4DQB*>HCt}_J2eAZQ6<!t9k)i&X_uQF(WUbB#<{sy>Ku^3 zIWy!Q1W3B!4!<9J1qkP?wIZ1Ag1FyPd{klmL@i{DI{;yhZ?r+|^ox#?@DSLJaQ{^= zU$)uIo3ooc;jo}fdUiDW&@zqjpi!9BE85#nR7h_#lO;*ET&(*7(-CsG4ULoLU~oT> z^I#yhj}q3C0)AvUzXwhe6OcP@OAef?BAu=8L*<1^<vl%|0o!=$4>^DYFDzWGv?rM% z?m>8Yp#}AoaqGeqT5biNra$!>{Lu}1=g3vKzrOTuib86vpU6hMX`{F(j3|FdQ)p)c zy`G6ssZjoI*F;!4GcHps73|Uku3VB*uk_dhX^ud!#lc^Po5)WRhGj^l{#s%}Rztd} zx^wtpaWsM0AK`|7I#A}NEtn9_U%46)|4L){$Br7^n8*-U8yJ|aUk(TWC=L>g=4lc_ z4d8d@oFOb}Dl7%>{=xiRq6x`m$%j@UtzY#Q&2-kO<?rUc4;sFGKYmU$ZGC)BFq0(r zu(8tei6m!VWA7;-T`o?U)mS>SZF+~gZ6y9eu`TJ@p4B0E$~axK>f(!=wIerm@@nG2 zlWYjD{CGZQc`jzUF@1@bwl9~1tWVx5i@T3dQc}6nrb&p${fs`Bxo<|Gg4LCMLVHfM zf6K%tq*243-BhbTxU%S{CZ8=7I9kxqs3Fg&q0)4SMU0;<<o)MD>pV;=GL7C_Raq4Q zLUO~OKTpNKho*Xz*kmEJG@gVweoV|PB3J}&>zU0k4fi+3HptI>u!S4m7CORpmnI<m zWWsE{pihWfWzkzm`2eALXWj~<J6I+xJ8!e25Tl+*1yfR&s|laR-_eL^Eco}fOL=x- zEJL;YQY8n>EacurZlOexyvp%!oM@He`UP)bGAgk`#cybnO1^?$yW$F!{O}V?X8PpK zGm5c&?v?`D1z%W(XZLl=pU~Q(Gv`Z~bcma>U*z#!?PF|A8usKh@uweHq7~J~VNpR( z>ATZOuh_>xuQspX%(wW8%$dXDBF86*yGOARgz>$`yPCW!Npa++X#00hLKjGb$|OFI zFM0P;Q#oxACi2UY<L9#Dttj~0!ehuMre3Wa3(oIOh<=3;ou4MS6$t$?NgbJQ5XPKn zqt0c!4xBb?-zZK7HQAvbx2%Dto&LCx<n>ZArcth$GGPbw(*uMha1@M0C5$p&4{BFT z0Tj&fJ%<-wU|+PY+Wd?HAi0#afFV+Qgy6LtT2F&RgO>o1^LA$yMm9<<wPzut24`7D zHgc^F4+D(`XB$R3`IegV;1J{UH(m93>#bSXj_8!3kqX_fo_QxDL$u}$KE0-996pXU zP1&4Gn`)CBE$iyT94(t_h#8xfWtf@EmgTGbD7q5N&^_s>9ek*0T~@rzf9!?ze6j%A zcI9D{sXrYP60~Y66IoKfwiqfae_}#FXEH=^yK;1L7;(FFXOeSj$tqSnpC~F;Jg(&a z)ZT6;mgye8S{8U@A8(61TF!U}rX2xX0}N=7`KaUXw-@#+Q@m8AyHO{*gfLFN#EA|P zV?Pc;6Zy+Z9El}WK@Wsrqw>@8K&JiI>OvOFlgFC@RzES*#`}z+kM^WG7(F1E{XS=W zg01C+X!LxDHa9TfDR%St$KI;}G}gtmdXRE{OmBIxnY&6#r9V0s<_ka0VSOIk(DPfE zHegrfKlPBdgYSEhFE(w^gn^m2)NSCtaIO0j_PAdu0qu!5<ngesVP31G!@b#tAe-cm z<rrBau5`MCdedPZ{GW5OQOlVTKGvXL?Z5e3lx6dqyJLXe!lLf%@(Ef;bEoleMGAKc zehT8M<=jb~Ij`xQ+vLL^@?B1Ub~KG;1-w`2K{mMYZ{u8=uoH46mDau$e*v_L8+I6j zCq|l(i6Z3P)m68vK3e-m)_?!SR{QUR`~Nx8pEN3C8TpYN+y1Dd`2KGreIq+tBWFiP z6I%eI@c&tgx*3_+11#)p|4Yj9Bchi>Rs1n~C|yuWM=K{%M+W<lsQW`%56ebQQ6dqL z-nLtatD3r3(#72+d^K5Cy9?U(gsp9${Q|@v&bYhmc4ZR?p8{@u^*Z|fF+DOlBe3HO z<Q5UiPhmeYLXuMDy23wUQk7IMRaP=jh3r}+sZxOG(gO96!L%d?$bimv7Rj2J->aR; z_3>TXB$u(Kscygov%6FbRj{TUNnpaKq2D?9B(-=NQk+arX9~xn#hSil(wOw1A?HOz zU4S19|FIkiOYq6{1h1dnq7dgEkB;YtT{pX`jE(0VbL+&&Z^7tBzYb1>eCJE_syj)^ zE=CLIJ!Eh)LJxW~Kh-r&x@utva{p|yYJI5<*u5ri4?k#Wpj{e{dL6`2QRw@F{Y=vq z3;8Rpd4|{EU&I8e={G!Uf{kvBYg~C+&+p{JIUaXj5KC?Q^?Hq}g28WOL3Kgwl~p;% zKYoaaq8&VDHBKdCDXS@GrFpe-EK{{J80K{k%oP_Z5G0$uQGs_|A%3Y<P3vQCZyacH zd)cAZ_RnSrECNUf#LFGwTr0VZ0)xT4xn@@9=kO!6ImgZIwiCCi5aX;lv07#AzrDp7 z>U=j;7(c-Oqo@1txcHxlk>o8Vk^a%sq5N2iEByaNjHt^GZiMZee-0LoM$Q%hp&#pC ztN-N~@}pk=pQdJ0DpUUn2K}ON*iR^Vh;31zYC<BCl-Ah|Qc?*PEEdZrDn9ey7}hat zE!U~$0M`X|I2sRzO(k*I1$KiayXpisT&_n#ws%BOzni@H@ZxD~H1d7DJ!SRdQKuye zJqJI4PalMD?6fE}ER-6pefO{BfLe1jiPc{k@Rr1~d-LBs#cwWNN55pSD#^&F{p%_8 zYMM<&fBA}RP*oh9LSLQcqKh1{@ta7ci?%?bp?wWbWdwPo|FP&_h`6``5|<7#;OdUX z-cxE!kSA6yZFztIRj-{-Pe4HlPf7&`s22I?qwGrZ*`8-sDLd>60~5*Jac7vtz_Is1 z!Th(Ij$E=Jz0R92*&nMvImj0-J94WMsrUwLx2J0FfYsBxC8&N(Fv|y?O9Fn3kumVJ zhr%|#4k@r7Q$r>qug{qn&sDb)Pvx0nmo8x3J)iM@T6kRAAP?@e`O6IKgUJc@ep5{{ zp?vhGB-&Q5g{xrS_8NjPRK=j^coJKK<}h&WACpp?0bK9?pfz#?*PJHAqDp9<0UHK+ zqra%6lYk<E-b0e4n4Vf*!E=k<YSAypV}l$#mZPTMoCCC>T-Y{`q%4H$qj|k-c1aKL zg>;zj2$Lh}_Zo)W&`<jH1Zf(YT%xL~sqzM0?ywskkhJeP@M}B0-6Q%c2z!2DlM=@- z#p)SDcy@M0_ierP_n+3K9AhNfgXFyplaD~9z2tNh8k<Hrl2Um+sZ1NLFU?j6(rq}Q zI+35!oD*I-&y)F4%o86M<7tLjw8P$p2bBK-^8bLVG$<Gh5EK*?(0_=!b@iFv+&^Vc z=!dNPfAzZgZ>8@)p4Cp~cGkxK6UYBsqW{0mF^7LBfGfml3G+!pRIP)yYbi}h2}qXO z4B=7tNT?!uv&MXmzv^8JAFV}c9}yqYOZjhLPlSsNi&QJ#ChdgEcA{Ei!UZEDiuuf@ zKY5NPUxq3Lz9H<PX+>rBlz?Huy);B1^tjS`O@zA{6116*?4tH6kTE0E1{08Lu^rm| z&O>~)1ZDG@=Cv)V7jY2Jt)4UJf$ODo_+Z{OLp+3CP?Lq<Q0*U7tKPH}Tj}Fu-y*DQ z>gj#sbPED&j>YqH2kT*)DV-N#y=qN0NMU#)L0*fA;2v0nk5!L3M$Z(rpz&<M@+~R4 zWYJp>Oj9!)N$*Ttg@^s)l}%Lbz`gygqN%Rj9M#^mBEUWQgdYF0T+l_O+I@yL5)AsF zoZ!|c@X$~|wH5-bY9qtj-G6Btv-q0nNLN>#c~;o+-!0W3q;>n@f^hZVK8C6a<st|P zsPd&$1Yf?X-^>9BAmYv5e~o3ucl0j$Ku%}&eNF4MXSR4)^Ny__wcI^2O?k{h7t0yG zu_3aBuAAzO%&*kO8dwMfnFLVPh)Z5nYWe@R-=_!dGzZb~3WEhXMr?8OA97tyD`)?= z4~pl?9NiGfJ>A9`3(L^W8j^VgfGyS89LC4Y-Hqx!INxed8|ds^`W9gH{~40TLV_EZ z0sP(W1Haa5_6-VZ-M|~-(X$xl)+mP?ty|rbZM9f)M`+~k!{u(5Wc4A$6^_n%q^JX* z-H*uJ7&7bQjxGKrNeC1)`QsV+osK(&jq8o_+UJnI!?ll>n~i?kI%U<(Y0N{M>MUFA zV=dp*hZk<mCUTnSeKu7O3qVYwEYyXF6aLPr{P6#<D@<~)?6g~G6AopIX3ET8VNx&Z z14YZZg7tX`*=_u2Sj_r2GF6II(<uE<#V|KCjPw|8_oA7@A{2?qKJ(ONcs@le&5cn> zre}60s?ZY0k>EQ5qz_$o`3&e9es|e4`tUY!kxB5hd@GuoUHHN;Brs@<&;e7RVJkQ6 z(M-!_S*SdQLQ^z2cP)KQKOKp`xW!NAlsv}lc|E%VdC$zE0~Wv<=|HpO%f!{Y_nFwi zyIhdCJic2{Ou*mz5&2&_+yDML{?CrXDeG+MhYJMc{{Klkw6k?Fadi4W`;p5`cl|$0 zYr{LPS6!^GA^vd0s8GZ|JS#G!Wh7N(5HJ)Fs&J}4^2EtFxFE1Z;6Cs_BIO;1m@71z z&D_oA8xlJ9)g3z3I{X&Z%j-iGTT2yQGwsil>FjZ{Pv-)9>rON6X1>1HPARzik-2<c zabYD6lfoTtVWIb{*ZW?Wh>vm8!ZHLD`yjViwvPE>;%*ZENH}yxN%?pqKpEEQbz|;t z%n`!=)Q66&me&&yn3WEDwhhW9d$di;$==+E@TgqvNxE1zgqE(BmlNcemX>(7^~+7& z*cWGKobGA3Shj>7ua>tH<d~JlJl}XBxV?bgsuK~w4i!rAVuX(v-l~%jEbZ6-;Y|q_ zk9J#(7;(HULybk>uSY?A=o~*l74=FOs|1hoNW_)l*D$WWy`lE12wib3>}{JqSdii0 z0@C4*BK%kP!TbtGt8AR<Rbo0K%Mu%hkg;j)D9uYbGVsGHCSK0mv~<iILr&yK>zq4q zN#sc1G;k~(%arAxIABQZkd28LLk}Opn6s~x$hNurmDrl;6*G36;gvIX46Dwg-MJvF z72L?k^eTjSxf>~xsYBviKh~k+74Fvar}Nt3_L$cTTkmS0Hthl8gNbXIokYi`_%Xzi zwxXpFqEpjk$tC^MRJ=^jrnRzVLuKQ#;?l)MqgltaM`JFIx$o-AUX5*jZLW)R9^cv) zF*FTJ*?u|_AX0Fj-jp!UUe;5_ie@@q9tj9ivt9d1Beg_IPIo-#)(W_^3eZ8mWng_Y z*DA`iu+}kCJ3rVx(wEk9bCf<Vk;O7`^sFm%emfA&#@8Cq*}`&VSm<rJX&H)NmT1av zEFq0JB9D}^N}F{1W!e-r1~tYO0kJF|NRO)q#xVg5IZ|13Vw*$ac}wn59RUFAXeopR z(7hZLtHxr!XH<&_AG5I6DK^y9qXk-R>CpQHwBp>J4W5T*GdZ|<pw9hEN1uwPg1Nu! zuc+gbDNt+V(q`mA;#&&lN!!c}%va$2!}ybra~ejmvLbz<$U`!f(jLVfsC*WNoCZN` zXP~BrbYFgcVJ=!qer{=LX=N#8Wgz9MW!!Z#nS-ZFahe&hg&Q9QwFO*ByNF+XibTpC z-*99G0HQFgc8b(r-&$TvW)|`Gf*Sej0hm{0q{)|+bF`VDR5kg4dOl*aiw#-msE`7v zki*po;XklZmD_d}R=A0G7YSLJYedCMF%yc}5A5A4!bqL{0&9h!Czh*;brI#(JRTOG znxX?KMo?%uq!OQ556+4nsh~KHZ!XA6<)bvvXMEJxrzX;`B)8Kxh52LTHLkz7wuT@E zy6?R2hx1Pv2a8d1)*@;~=+Rn!kR|~X(Q-sz)fGcKO;t&&QSO1dso*!UzTHZ>T1-l_ z$h8n0SBjK!q*X%1<&la5<oL27NdI?W)iQN4d$^KTl*Qp=xMS;9`(Y;wAalyBcn!}M zDm1XHumihhtW2@_CrlZ}HNSwh&E2VuGzgX8F059ZSzUGq@?L`0c;c<Q6#%<c8KUBC zcapq#*kVR(hc;Wsj!+k0S&$(z*UM?AqMl3ju%0NHq(VOK*kT<Xr1ZfibLK70HqZZh zkZ6T5BkRWA1twk+sVld|C?^&w<5NE_y>LE&ey_QHczRfVy*a;xQWFzq!%FFJCW8{) z`5^k15Lx>$&)*$k0RT~v_4I6GU+u1|be<@&7YB^Bq}-S~NU*?Pio&n*V1V;*a~A>w z!MWO8!H9$Y>v}-eqbFGDJ-GGPcO}B=tw0Rvr;nHId-8KGaDUb8Mo`}C(*2v`@(<?Z z@ci{&cipOI)|sVSb$Dg;#S&YO{2#4}S8x<#>a7XOS60;X=!+7z9?8GR>b9Qm=Xo{i zVKybr9Yf+6hyZ;5o06%yOaHu^RWimcMoaYFrp!fxEA!}<sa$r-I5!?$g*OmoCDnHC z;ps|=a>zA#xK(oVd*_Jumq^_&l%3su+%7NFor^=Q7u6EO_bNDR_!c{8$ic~sfw{(k zy_jCKNqV$2ZX-EA3y*N;&SZId`b>VC0PiDkk}dz`8hfU7j4K#`3wXbojeli9w!b-U zR7I73h9XHU=bWwOp>NaHgT*pkwUYu{=F;)p+s@hQaE9g>TlL^Ni)dj4zufGQ-qW4U zgDm5glpcQw!JzT`mc*p9r7!N3VTLtf!=duKOph;p5c8)MF<ts%Ek@(~p>1u!*Tj>+ z8iR6xH-7bZb&O3FT>G<4fNpp8v->G767No*D}gW}cEI(yb?H;9V#MzI_|H9*z;`&L zJ0INpk(ucnKp3NZI~h*T&Mu^Mk-XWQ+AcqnJZ|S+XuVQXw+o-Uyf}7-*ep#r@nFCT z{h#dXcp`B8O)D=w0CWrlZ8as^BApK;U1SJPp7wZ;d(x{zdXINqUW8YI(5Pzcc2KRm zKiN3(&1Lkf=+@y8Jdph6)wn+HDc7Nsm3sU8+#rPg;#9v1vt2OwlcgJUi9gpMv;(1= zcWtrd>`ZYDqB9T0GO%0~3e3T?{9~hJ;}HysKW3#Z+q-yhwu2`8oV(0VH#>DU{aHh+ z#u8LWDJ=VK&TxB%-#VX)<>4?tFzR%vx<fC|Lm$tPCI`3hV;B-d&ATNY(spoSYECX< zmc=!BNX|*=`(n(KAB&?YUgU5i_PO)3q8tm0T2ujXi3j^n`mHbELR6dhr!b*O)8~bK zCm0<QV%#wdMLHsEX(5pvxJm;<I@1x1$+ra9zH-B<V=s=_dc^-hZE{p?$}Ri<g7TPK zZB#90y<M7mx?8RUUCpA~wqNU57<Rql6VffH1m}quZ?>u_`c_csN{t}L0)5!lJ`EAB z9VPx__;~2M7vv~&?TsmoPf$~HY+UyfF^gk1-vQ3HuxSl$IKdsS2q*z#RKC9{d_v@r z$kagr296+chTwTM@cpIS>94=|^^wDK{C`1(w=Lu^P&0sz=hgNXc1PwAOGc9iuF-q= zjRgplk(Nn6fcIjd2#G$h_w1m)1z)iClpE-bLbpm*^oiP#c%gKI@PalAn_gW*s{UCq z=VChzd2Od5-@6;~n@w_1m5g{@rD5O0N9{QaPKMrPt<Lcld?>=kBH0wXTHv-UI-SS^ z2tI>dW_M0O-r^Vve1-aQ=g23ULfQXDWdq1F0q}@<UA#yg-Lba2!~oV~VG=1$ZR$^| z&g0U)?;_Wq5z?{!pb_Ui!`}^;5~C1+sm#x0jm-=Ol0d8**8oZgx!*0Q9LfnfW!1(5 zz7lDfq>0E{h!c0O|9?NRfW$Td&I=g)`Zv+xL)?rU{8hd-4|`GQ-9=JQ=-uVwECG&b zDU64CTQ<!_KC(+iS*X~0xgsB0o$|=ztT~U$rm)e);wk~o&lc)gAv~MrGM|NqJwKEp z;*S7%6CsKRQo}0+-Wuo{!7i^yn)rO7wh*K{4qxB>33W}0*^7ur4DP8Y!W`}9@10|t z2h#2^-G8(vrIIKSCK99BPoU6S_unW5j)xzTQVfa7g{4#)vMK>-C1h+mTs=b24j~B& z#VA`c<f$4`S&hk6M^wbqDkvGQa42tlWDg8v4+MCxz+?|*5+}8BvpdB3h{XA^#QE|> z`7<vfrnbh}!Wa7pPdC2^MltJSYkLW{<e|NjuaYS@(C~imTid5tK%Ts)pS6z~B~FV{ zZkgdX7C6fgNTd#+IRtg-x!j21P|?j~Gg{N}sGnH>P5e87B-`WvYk#ZveUe4QEjP*) z{~FvR?1sOs3Q2yU^~;vUYcI_UHoP@OozXc{)PhOZwZ$zH{rn#%tLWvp+XnW2bwR5` zN#wl6?O)}gjikXb-RO6OTRIlEUx)g#(E+U#_qPC$nNsvlzhwt>n*-4%e5*?(-H7vN zmcN-+Ct96ZIY;QLV5;-AbzEe&px4rqB#-RQxLC3Sjz@IHcSLZh4jStnnO8Gc%c%2P z>j_KM&$O-EB(*$*DfkcRuJdKal8k-{69`YULeysZu<cKZl8)IGZrPin66h2vEsqL} zpRD|u-)6%Je7t-qsv}B6QD{B#(U0?boI^8xZIsGqO%m4|c8&8N9SMWo?a|tu*%7bW z+N0BjsP2&2<2>czjCsE<Lbcp6btXGbVY-8C5BLCxdSdVOYzX>JzA3c@YOgpR*|o(x z_uD^~vt=J21_`;5<#}%V=BKlpY>>w^;=X(xg_xy0Z#7jhUmlxtF;bf@L&fJ0QID0O zFv24pVkfeY=3`zfg>QIWaEzk)AX_SEG~9wq;BSsLIifbT+FTRlYod<m7}B+9<6FIy zUAgMVr?27Yz6VdY&AB<btKe@Oxi3C(KP&8*P5y52qT|wQ46|8<ULUNEA<|WPf<iBT z2~vkj#v@8|905tz7wU{L`GwmLIG5P#+0zd?o4sR)cdvNcz0^9Z&VciQ=MyB~+^<mq z{XpMA(GMer;}tjP4a{(ujeG}ZVv|Z*!j2iAB0Q{HFb^PV_<z%Vk0u<d9kaUBPiZq{ z=?>t8V9AHXQSlC<>m6DjXA(3_G#rsA=Nsmyo&C5L#&@Q5ll-8VPj?!F*9Hz<@}MuE zI3vDtnndIe^fF3b82I9Robw6%k;CEGylA<=vGujT0g2x51=+^myZ8R~!Ffwil%!b^ zb<>WZib%vkvk`T`z$>upQL{GQSYeF(1^2r=qtGyZRC{_72sHlo_5WT>N9tf-g_tiC zx{t72=y%>$ktgN&9`Px%Pi_>t2BfX<0?n%j#7nsxPi4dj*m>@#FR;XHV)mNmm;<=+ zNKfg+{R(2{04+vv+5fP_k9nj{K*TlX_q!$gl}f+DW10w&cm#J+25EX7;_7~QxoUgx z2g@JBHpXDxM;s4vjI&28nO?BAsaitOOhilz<tiCI3w9TUYd#A#%BRzX>nuGQt85m} zay_2!GKkxv7gMfBp7&+8E7M*x!K~SsnO@I(X7|~8%2*`^`v>Y0Tro5_7wR&=BPcXZ zbj6M%EE%U|`N1)o+++24=4WN-?wNSB^iC^@p&0wZuLf!7C5d^-;wOp+)xmtR#D_yM zZoK#+<reM_{2rV0{if}3B4^NxPU_{9@ugbjrEx4b)ZJk@V&w}UTwz(ZfuY_~A=88l zyiw0^-lcY6-sNCwrlcp4sM;pTS@}>kXOMkJP$9qT(7`qY?Lnbz!TMZ~Ho*e$iB_Ql zaDU%a8IiqM=l;m(DFbE}U=#GY*7t;SNhHCXk?@f3&oTN6DD;RBZpeV`MT+xPxIg83 zx?@Y;vsII&)UM80dQe|nUUW8SrZ$&I9N*!4HXP;<dfa~(JJh3|=sw}rvjI{;wg~b% zqQtluN|i>E+2$P3Rk&+PQ1Mn~VMdx4ciUnz;##*Ix`bRoT1fq;MQQCh+y?s>{k{kq z?d3|+F}O>aWbz}a0LXbA145YfvlgmnT(J8h`o8M{X@VSRCs-#mbI*|vN;`vQB|ntr z%$Lcw7aY1<S+#wulhBtd@V<A!8!M!pPoy26uxsG3>)&D5xJWx3#NBqky$}Vx5b+CN zbgvR$bWamsx}|p#!6>C~Z6+D`Sw+39=7%^y_gU$0;Y$Wm-byyk2CQ6OyV9t8)PSx# z{GPo>uOZ`hVu^axh<gZyeQM{VM&#|;e)K$jm7Fj>Ib=PC)IG^bl!vVpl0J>eAHQha zaM3%XrF?LI)|xj#A95!uK8>@_&!><m+i1|WpHMem4sNAI1C<v%om~mru;~x{KwSd< z+j@f6wRz93v+s~6-cTNd{@WvY&+?YPbq8-PP`a2Sa`fhK%TA^gAJ);kTtsW}AAHQ` ztknK<2A=mkQ1xJ1cuhE0nXoO=?#4k@tD$z5z{l=AMsUrcbBo@wtXa?3bOn@Ml5)Ae zopPy+J)w##BS)VqLmzv`E&$$?|ECJR(6QQ&rg^VPo3_Zq1`IrYr6T&z1&u|3cFV+4 zL$%t33toz|*P1O*2cg!*FDe(@#fGiCluHPYsd+7CdRfgD-TA3}$2o>xbAkL^DMzE? zE6s$%BPorF($Y$slAY6r!J~=#CR3wE@Z*WGZuQ)mxXfSZqb0x^;IGZtY*Lw$h0Pjl zikY(L>v)<KQ^m>ayp|%miNExSE8}>wVIhWRB9blZV~X3QZ0TV%B88R<FsvdIv?7CL zO6PjB)vG`>y3sc99zIy#+C_fJk-(Y|DZ@TQ0gM~p0_nO%awm*ia3;_CE{vJ9Kut>n z)-;){z#5(PU2xK}<<8?U7pG+mf9Wz$C{IGrnBJo`#u;KLO$u3thx})$n%pFkm_8*s z^DSIUn4FGn=5o|Cc(J~n?i{FrHrW!ewx-{LKRFHD=+t+?%fv%C>EgG>rSH<$6Tg;E z%EGe<+o(6oNZyF;sJxN(D3;LB%3geJ!-^c9J=GnyDabIhRn$@KJ+-h=^W=3@^8`LV z*DVp)j9Vtr5kG9jp`7jlTel_U)XWIFVY8UGB{wx{wQ!|yawG+?b<c^=ss4RwdFU9P zamTxreaP$0cFMa{y@<QqPuG}Y?xi+Cib@%<v%bQgzt<`F9VTYDs5h61viC=w)OaQ1 z@sI5GLBQ!*<qc2p)5QQ9kTcLC-R0?;Yg;Ny^0UpZC)Nu=G4i?*o1ABsR5PXd-zT!E z<(vZUOAF0vK4CK=#v;DTo2ih$)`v@b9m}fQmdyjQgG0nMovOjLDtlHcJld5?x|PB5 zrAisOO#^E$cXXHDLg1Z#0tLued-QM3gB-H^R_E}!>o*yV+Q)BUc6PNZT$j!_JYYUO zU_BhY*RnUBupd6~K6ZgScD>j5+^Fsbm#&f@!_+>)Xg&TBdi&ffB`?j?J~o!ER>~ji zXg#P2E*;h%5lsCX51HL}%9(l-_4geuu0EmEkd<b2S9!>P#r^>TrJN~cS9I94ILhT* z7c94g%}5xlJintq5b)!7@(XV~Lw#s{;h!juh+4uApN7@C^}Z-fMCO+<Q4XxFSD(fH zk<g9P>KyuPU0e5KaLiwGyB_DLU=#`;zM~g7U`0I49V|wUEsiL4^T&XAKqsFT3;q#{ zjH{WW)KpI~AXylrtVb)f!RvD*a$6Lt+Z5WZQ|c)kp&v-C#J6t$unA-G@@tFs7DBjq zF=7ti`F|*TryyI}rE9dYdbMrawr$(CZQELH+r8ShZQHiZ)9>EjAAA4j;yZC7GOC`M zQ8BMFB1dJ89Ah50u+vuD^IYNLv1kQTrnY(I%}BP%HOcyVi#fTs+7wL-BoMWChnTJf z<2P+!FEd?BG76#g-(_NSE;V#69dxY{s4B(Z%e_0M)Pd)Tz0P+jsOG;T#XBT@6MuL6 zL(mK`KeeT{=zgW=)0vy<*kW4o-KwDicIzjpa*(3DMi*}^_J2+}y7XuOFMT-}v^7rF zG=VII=wEuMt^c+ptZ@OR7V;?D$~L;h8`mJMz&2E;{EDo@Q1c8mwvJYCi#D$8ml#CW zA@tq;V`5EDa*NaHEA*UBeq}vrSDm)E^?SW@ndM<`D^l-<2CW10w=PiNbI;Cn@6Pzn z7Ps9s^6<%43ggDRgzeR*-xm?|SCW&hb%f_6(sNT$%QIWcvQ!IdPIa=ce$~x2EyG7U z?2&=*TsM&8bwKNL&qj6MhG!YXsj&yu=myr|cI{Yq<G&-h6^0V|*|ze7NSe_VisaVx zZG3i88Pxbdm*JT_^_^+r6K292<%kE?QP;1Pwr}HD|7zTu?m6^3z16p<dvyMi$%!2R z*@bv~H7WlHx=-VF{rxV~Y#+<izdm%0Qu{1fgSx9nbOm>Z@YCj`Z4NjqL)vHAI?=T@ z5;D_g8gOkv@QB=1k!Gtxfb(yETZ510!>PDkI_+1mz&A2mC%8;EN%t2^^xSrD@3Url z{&&pLNjK<U-WiBbZ4TjYLguq;`HU~XtmwM?$L><Wnh28-&I^bQjzRnrz<CX4$IYUp zQJO{>m)(>1+CkeC4bt|LYm|2di$dR-(3@c-uU%iGN=|-PGWN-jX|u3M9+R&`3bfFj z+}PP3>F+{WqEp2~ZUfW08ZGkiQbrk%d^~F;v;d|qP%WPnIE|!j;<HHDl3kzsOzfm9 zg6_Yg*GQ>ZT7Kg}eOxU)HDep`b&!d;h@VA@EK&{_HVn~#2do`TV`xG}A~4eQUQEMi zQpzGU)T|+LfpMZGXg&~_f@PS->(RU7i6t6|(wVWuD8{U0s+x&|5^H72$1+9BSt!P# zNfGDHCBo`jbW3W9&~iG)@-8L?T*`7dW{O{lJe(B9jUKGusARIg56N@6pc6|1@1W$W zejTReazQ4V2Hs)GWkZhL^SSeoP5(L!{>=aA|E4<Z-_xCn6;Rg>nSP^{(*YhU@w?NI zv-x#6&-dyi#{-=B^D2oPOn?I;S+k!5TH-XoVUv$M&jW7J!~~4^YQ|-GTnD3T(FWtt zYgV{q$Z(rMOLeTT^NMP8PLVEi6gFQI;s{M4{*bVek(Shc^rn)HmOx}&74uVRe<@Z% zQ#A&lRk3Kh#l=*MMMqv01~MIwES5;<DVvn+M?FV{i9^_czLMD3e8qq$+V~{Kd3+S- zdJ>~M>7@*NUgT#8N4E31os1s5>BIS{X@fmwjTgF_4QR4=j{|9q7l_(bey|uV^ObmC zJn8g_Uxz>T=~yf0{@7~>M?peO6cMUvZ=ZTC+C`$;kR;Wlx!S@KDzX|*AvLQ)m$x`A z)TRtDPF|%YZhn1iv})Q4SXAK7BbysHxQ?v<GNY2YS11bFv_j)87Bj)7QAcj7GNnm< zLMroL><V>yOO=Uq<oY8b6UGtaBWTXwW;86Z`NWM0*6*l|50W+Rz*bwoGMamitj$hY zXXZF(=GJHCuHSNt1iwW!9O_9=>$Ryij5Xj(rB-wg?l;N(t(w0O%0s7SNutOQd_hg$ zqyWe`_>Qv`h+1Cd-EbhhO%S&P348?t#>{HV&~xJTy+mj(@PV_W1hX)t9nO??nM&7A z>%tOO_vgL2dg^@AoQI7m9}71ulGR<cChOcG(5o{0U-0I%FPv}rQi}}<`32B2N0=_8 zXo5Ne*+kdcK{!yjW#E0AkMA!NnzC(i4LO&Rk=vMa-2GgVk^899e8OnNR+z=ydfB5k zrhqW^sHEN^v&hf3CyI$a#WP60o>q)>Ke`8YRH*~Qr^h;LLTTFM$IdVt1|LhiROT_4 z&cJ>LDB8aKmacJVY}imxR+SvXu0A6<j*&i9O=uk?{~U6Rl{{t5=A<avcC(Qm@?t(f zF_}<3Kr#Bcz)YrAk35?Ga~l0QVQ13o#$_b@T+XFGRB4xTD)&%!3I^3WCCzXgROS^d z0_R-xg0*9-Lp|+T-GD&XEMLmqQdIU@bO!rRgtCQ5Zw)jiqhDCyzL-aLwR;Ar+MMjJ zzW-$u{olj8|BUtinZGY9&(NoV0{~ni0RT|^Z$uI)TSI-Tf4ltt56?)|Tuo^i-Dmm& z3KirRRR#e83@})!8Y&ZzvS7d(QcBC977c0($HWd5Mbm1OwMxPYku{w)Q<Jnt21zQD zA3n2Y^dgJ(+K-sblc?{rtk0orWwG~kXFou{9~UzF^TxH;`8)No!{xXu4WL>?w|gxX zJuS?B7^djv$^A|$s*Bfrpso0sx6Q`&5U`FL{QVC9tCtwfaHm**fBb%sR@ddA>rL1O zH$}>DVZ<=En?M)WX)rJ;@u7aJ=UAk%+gh|~2U%a4)61>4`%{HhcEb35{1Z2AS1f8r zsc5&BjAR}v@g=DF#wQ&%?QRsNX;Dn-fv-BvabYX&Xg#iERZh!o1gdjb>uotEuk*es zkh!%tf90*+$O)XBMgTwe29_KlJU0QIsHJkCHhrUHEYl-%s6nq;i)?Piqo0RbWw>xO zUo;AYMXjA0tcYbg;`*e;HAdO;2}Jp<ni}c~Cve>FNK(E?X6xA+_zMk2nexRjA<Uuf zP$uTwYV~1Uf2>J|sXsn3ZB#oJbO9nxS$><UwSqmfSZ8?7E`Q+{ng=}A9&cD0x%niT z%B(^$SPnchPr_U<gK|5Vk*><+J(VjpOU}8u^YjKD?A14dFCRz*aJgpx2<JxGI*=hJ zc$esExMum8vA9aMisb8`P7#^ofIQ%-Yf3F?0GbxE>ItRgbC<Qu3#Nlqkj$sfq9`{8 z2CYC%Mppu*0nUdm$(`s`s2Yqnypgo4#U%okyMXM;o0LSD9YQ4*N)_}(AmuaOkrfDD zD;fHqkbT7Xq01f_O?8BaU!7x1yR1rS899P)-1@q+3y(O8F#*kiM4Ay3tfvr++=&m6 zJDHH4TFsX+SOzeO8)+p<WeDge!<%Q8D&Vmyr@PL(;VpKwD08a8LkRX*BcocfXx9%^ zW;;u)j;Ogymsn6#G%67apgXVBB_!(^2(p^_zkJ*@1smu~Z<~#*Fb+R{BA83`YE(Gx zcLe0@GiQ@#kOC=A!BPHJOaUk?)`bfXhR_+t1S&G@ZTbb|k%D0c<vQrWM$3w|_^?$9 zzbBQN5hbQL0p@gqMdYX%5W46$D{qjeF^3NETspf*4Ds8Jzc<58662#Npqai@53Jut zOX&ti1gRrZcl0pc$SoG<Qnd!;n(_s}mh452#=0dVH)e1R4d$;mf-m`9T!8L=T|jJ6 zIHkjDw3g1WF>4h?OUO3G3wGEB>4}_O^~R?T4Q1_EG%wi;k}py!GkrD07t!ViQV#h` zz0w!zhcZ8~N-evMefvh0NE`cCvE)EYVNCH%kdx&*ptd0>by~R5YRg|HMt1578^XH0 z64o_S9kGk#LGp5TVek91JGzQei(jXjyKZ?$Hq0BvxDliLwk)}lmzRryOuF38B~moV z=WiI!jKi#H_LFMUr0++2lMBd~EP;EE2XiNigz%0p8WicGl0>_e<-*41#h7uI4@?^s zA_oIc%#z3R1hr3M8{u5KlH*7=g~iqB@Tp~jH${J}%f#I4r}mhjerX7big-7JAqJSo zaa>x6iXxb)P^Y=yxtz-1<3J#kIdw%v6S*g*X0;k7ZDQ?#%@|FOLqvmk3Sf(rxW}n4 zi<Hs27Z;<|=_v1$@)uS#HMv|A$#fN-)-mmu+k7?-0kj`XDr8gij1u)B(8ru6%%!lo z)J7<;dY*RHnn{`(dJ3h?R7mCdi2Sbg%V{5f<+l~|$D)K&v+k<g_3RIFrG3ua(Xu5p zM$f?-w0jH1qe-PYZ}oWnh0IR22F6}4O~RCyHqGP(jY$Raq-Ylhv##?47zh1);hKCV zaQwYhn;6&Ge=Ym*u5*LQ@*YLwSucZiw1@o3u7n~8>_87pWe!@sw$E6VJK<vGPVk0P zw~S<X&KX=3Sf+NvKF~gPb<o}=!x3@eopZ$Y%Fb4)m~lpNq&ohDS;jjW0f69ct`Q!p znD{g;HpZx4kmYj-`6Fp|XBC**Ui21UU>HoeY>#u)ow3wE!4L0yy?5>YP1iLS+aYj_ z?pBx)u`p6`2rFgSxYo6Rq&W(WUu+f9SP)QW5i0&ePr3?`pNXX^OMvo9@t@|qJwl35 zRgXBe>JxY^4c@aTA?gguq*o*orz@@<dbu>w?h1gYYFAJ3RC9g*<L~)r8nY3JB2vT9 z+eHu2si6RJ^8>t(?-%F|5|A4Vw_9A|J=iV-%&i8@{&m=1PS`F-3>auk#48&~@;=Y3 z-@7m(4&3t|zCGCRAblp>^gjG80}it7KD|A9Y~=J!;R}{*<hk1r3uKAa2j`MXq^WhZ zTkl2M`fl-L{fb!ZMZ<>d7>UP}4nO1-o@hcPfNOqI*1`||H_2WT3MAWY9#&ZqP9W=9 zc0Z%L*Y(#@ed@y`Lu8dBx5<|a3&?ym{uY^%R%*M2jyokMqxgvlQ_m)S%t+BESL&QP zXKkM)*<HT;UTu=ckCr1BeNLAf^U3g^HctD#29Igv`YRV*K)&`BK9cQ|ZxpxkS7fTF z3W-Hm+WZGaJqf6M-!@1^?!YV1y_e12Mkdsfx$>cK;+h@Cse`FPNUfa586EedBO2iK zd=6~t6>MB&EM3mF=HtgkTePmGb<3DQ%TS@Ofrz4kJ4UR?m5cpw_%y=mWL>SkEtg4T zU2J0eM4V~2zX$6T`Ba2qO%B$FTBM<zQNB=hh&)Lr;=bL7s8)U!0*0hr{6M}@xbGmb zlY~>9TBUghS2p!E-Pk7yRW-5kMWj9Y{g9!QVIF3(bZy+MBi26KaIGg=B<NO9Y&wON z(9E`m`=G=w9EGO2LA|%O{i3iEc&4DY@~yCvB+I)+DDSrZk(D^_(b%PzV>xBgD-5L| z>BZjSw@#T+wnmZ9QRPrf7NT^taSeFd!^H2<ntsB}5oDSJNLCauSd?(41#sG>2&WBl zBr8Pp714AOhE*i>urMnwGKY!M6vn#7iR!2||G|!Bm>TX2wSfv8CdToW)swnLht&)2 zLU6`)cdq&tqo&GwZ>|LQY5)0q;v@Ro58AWpe)p`j`Z`3Sro3NGock-;Sp7{dKuxve zHQK!3>j;SJb8Hi7^SvK7SVwF0sg{a;9q{T-b%}JeL=%x<j_mq6QmNiStpRlJ;Eu%l zRedn>(Vqt3_*Hyz3-CupnQr4ZL8Z8$&c;Az(%_|>h;lhXwpeEcnZ<~CS5kb`(;|6O z832#IH9X)}u%ve<q2gKQfor02qEabcAi4&sp7^uUOQ8}VIg1;@Qo{0Hi(K%T@Z&W= z+5eW0`)^qHAHesIeBAc^YL?&+*^(Uo|HGW#+Sy6p;K%<+`rmgUTj!sre?z|{6>Ym8 z8zdgq?+mMi1{5Ve%`w?|B{6Hj-sHJCIWcj_HHAWoI`O8{WTR#)mJ!H~7a-cRD7FHw z-2}!jd`1N{TrA%$uNhPCMN{u(^kGL=Tbrf~Odpa2PuFSgW6tf@*5|9~Z|`?(0I2>X zvVmP@a3VI*oaFo)jt>4%)>FG|7+Ya`XL2ailSqM30i+1Id;?~vaVMI2ePSpLG!<|n z%knbvB;myh^AI1B6k<LTFefQ=k4Xh5OZl>eMZCAr`(_a%px$vMKZ#N_jCrR?4ALE0 zXetCSDRg2j@dIY<tiP&|<*m6$6lAAkn8HqZxrAP(eSVGki(pWP(Dj+}ONo0C>EsxT z6mOGCNS$2qWlPlM>1obK74pOONYskzXEury-Q`*;R)<mhwuxiy8iP28?&Av&4v`Fq zh+#PG3QEgV6Qa~msNh0l<q4obn`MA0ASFm;_R+a28Hz_2nN;|RD&wc)Owuhx<{q<3 zf6Hz3li?f{Xb;m7n0hjQQ%FS9I4Ub~ROJg%l<DkONcO2>zWEd>5x}u5DJjlMCK`0= zrAfpI>?#OGlQ6E6q>-gy$tECC=ATC6#aY6jQikZ*NYq&8k0T4(lS?CpC0!8Fs}C?_ z7V1BjrkqI>9o>4D*Oa4F%BOR7%d2gw;Wvd{vfGjmM%IsESQd{&C}`TR(aOzG{Yt7y zSwd3OrUQ#A%x)MpbK>vUkeAM=n@8U|yZ3?r{l}6}_o445x6r+^f>LF3fQ-k2I#iOu zcv$2$hTGg|zaZ9{erZfU^D4%@zy@W}d~$0IbLLqA7`>@S1wGr})HpRDk50*`G=L@$ z(2@bFj~M-_hZx8+C#n^SWWlH=7bj#K>B1WQjxLfkHKhp3{3HP%1US_~eh#b<XPMO> zhxVgEUj;c57akLg$%8W_+rnaB+U;fM2x8szw9L3X4mq3B$#qXgjKkBccVs_=)8d&` zyB8YO#5(3Oeayssp18A0V+I{~CFYqA%WDQ)o6W|*Bo|W-J=O!)YKT__F30u9<{)C9 z#S61HZ3jzg8`NQ0#T#arY|5_@x(D)x>&FQi;en5K3Q3O>IQ2L0*GvFV;rq3JbvQz^ z>J$E$PvMVj*qRlgC^~|7enVLF>M)(7nP?-2)kLrJ4WwQy-o-D345wZfyA_zA&0am% zy>x&lz+b;=Na0yxYwE4_UGYzBykK@VVtp?phdj|5&9ezkZF`;p0(2cO{!sItj~NFY zGfX<NPdT999n6*uflPGo86fXf2ylg(XZMSvR4k<Pf?g3Ql(y^;!I0i=KpVUU=LL7& z1gW5gG?ip|uUPs@n{}r=pW;JhR}Ib`!{Nyz{c^%S#-vF_3mxr&3rrJ6OW&1|*cU?l z`yEpP&BHgC@y8EV8~x14kKgHrK=OqylxG5sB)xQD6dQJYoy~X8AZ>?AbPYrk<<~p< zR1Rd|=JSl+c)s3s-W~@->vx#mb2DVq2FVJp{g*h}1>n|$VpI{LRd;D!_s+-PNX@8b z3n(3f4Vas$91*^9<Yqwg=SVu={?3nfNX9Ap{jk%9?_L)oVdPifV_sbTyB$HX2)b{9 zcwgRt1AMnMeH>FF#7U`$h&$M+?>0U}ET-OYoB;XX9Q|P~)+5CLDMGn{Vl*2xG3$e) zG4^$)@T@ClQ)wjofU=J9(r`o>`25*Td7fD@M>APJ^cU&Rri9<G#EGDGSH&_8m;_?( zpBF;B?YWT`F0ZFYK5gn?{89*yg0l7fZhD+PAuFdS`952Znbt-tjlcq4pjf@@l6s$8 zDLCi!d5=U`$m-qSNy8o*X553U4k7BGtSSriJk%ZU^#SiT*aVf&*y;#4XTvqG*q+dl zf}BORH=uubLaYO~1C4ZH<&TrYwmLv|drIJL<`dtv2iqX*9iW@`H!hlabSii@AV_CK zr;aYqvvMn0`~NxzTqY3RGtAB>Ty(xoJ(_H0hIGNeJM<sojbaJixXyhw5j;dD<;m3O z8AWiI5e|1`?Q}^S$*6{~d*z#z>@>V|C3co|Zl<pt5Y@Q{`!2s?Ec22$V{>$%Ua6q^ z4FJyFl!M{LH1}@~1Bvx=T~`dH9C8qK>I!IrWE}>Acya+pK6yR){<9VE-=*k3Me3if zM01ZF$m@?qpA;Mb0K@;*mH2-ZDJfeU)BjVV{^iui+x)uXWtGs>5C--sS78nbjl^G5 z)PNKbPOS_9a&}Cjo}NggnE*|<|B}yBO8d6M20ZOE!IrycW}F!}%lasv^Qip|=<V>a zxtWnMY0^LJROjk>)!Kc}+3k4M`F`%Zy^Ws_P9Z`jF&!+Pcl^433PwGT{>6srf7u{F z3C|&VOz7mV(s~FItaGq0`Egq(P)+tgQBYN`LvA*R+^Il~c35AwAElNqf1D{_m9DX> zH5<Xq?dMlJJ>Rd2214TqT(F~*r$twS{)#|I8TH{P0<-iYkXMmYp2XmB7?n)kH&?G` z1Xzs^_Ju0aokpvK9!-mu)L7V*XMFF$V3{ZpmPTc9*!VfBFnLflD(tC6H)ffjmLhhq z=N%sGd|7AGN^)tIu(367;lfUvkp%Q-W2$e0%wf+$Wt%QfNEts`-b}g~+0WNtpjH45 zLiy0EMQ%#vAzp_CA2@k3*|97Hgo0n$SN`vv`6)z60teM@=9P}uhJIYVvu{rFIK4s? zbZ35&W2Pvzp-KZ)XrIz%^m&p^0qTW5=N#2A1oGIUR1b6TD1ib}^2lI*9((aIy0D`N zbg=o#3>*LaPTP*KZ)Gv^->MPGG-qy0nV5>c?U4%B6h5i^`($ZqPjmToxK4yI%f*gO zZT*Ll5S7_!w5TUyoC<e03Bdk|b7a2s5N&&rPHE*N@10T3#i6dfkhs>M6i7?s$qHq@ zuYx5EHY!IIlg!J7z(Zzk_w6smN~mJ@X<E!i36&gLyT%_)ll=|tqRNLq65b1ybNCqY zWCaSz4iu+OakE#TyX7<K67Cda4O1z)3a4yYd}6GWNg-vrMcNN+L67la@_Rn}3>bF( z)0j!|CS%c4WJ?{D@+<>oXHV_NxBi_4YR5YWOe+D>OCAhS4W^}O?)--p>O1X1@ZQld z(uMOK(`_5{>~RgEf9K#}?#Z0xqW0WuN@&hVE~v0pup2;lkzlR`Yw}{;Z2EoQ=^3K@ zXRpIH>$Gr(7z5(WU|-F#_=L(Yg<@x5qOkNz08&YDziI-2qhP!wv7r-FnH}NCWaZJQ z`{SB4M&SJiw%@4IvFdg8ifdv#oi$PoGY;<kvOq5A;W8Y1TqIUxdSJj-_$S<Zwn(}` zF9`Hx0bR<dsZej^JKpJeLU7X+Z?gSZm&uvlpq)30dsGoP%~omI8lc3fLyMB<1;%qF zMcXmZPjZ}VAS6`y%XVuP>{N&_Z5F3PDE$Ri0a26f^vgC8>ttaF*-EgnJN-5Y(m{8S zqg1icMT|qhG2rPU{dUn^9D_|T)PPyFjolDqZ1ZBbUFa@Q`~ZKUA%n+?pAZJ<cleJ5 zZaCF?;qHUNB-@WVxV9TP#~M}ZcU+}iWVe(2^(20$$KnM{kiCw(aBDYuWEtJ+ducSS z6JK?53@FOF@KZJR?Qt9KrKZp%mhc2=F1+Y)2XLrP1sQ3dhP*euDAL7Br4L63F5dKc zUyFMvAF)OA?FJq7cEvvpegzf#a)*saTtXkCmxYMG4T;wgeudoMhM8&k6)l;M_)rKS z4Vlj^ZQ-%|1zh*dVdqI?6HDaD7tam4!Pm(i%Zvuwnx61V-UEbW$`9!=b7cm;NlmuA zzF-PcmY^HF8C#nInr1zwH-l{ox%Z#|d+s=Jnq==G454Q*xC?s8uSMyS*}1m^eaCja zky~t-0?qEiCwJv1=)g!kc*a*>{<KFw{eDfyeTn?GNvri2)-5Evki2^F+WS<)d%^J$ zKK9)tA)xXZTGD-sb>2y-qC0HwM&=avJv`B}Avyu=Jq{_?+bs*}+w|ah^TwXtJ4PUj zFgU9O+iG#v^0Q9vlPR!0bl2jD%4^+}4gO-=qYNfIfpRGDR(E*^)3z~@>R1maVd6HL zOwQz&<6^$mW)nW^k7ig7#cSEh8)rqQU3~U!S98A&wyy1BttE<;!X06GfzPtWnXs0U zT@*7wAA%lQ#yT)woA_DfJJ5>o^cYH&?~t`Z$$PzFi72G&Ou(boz%UGM%GbZVU;n#& z{HL(|^Yw!wV$GWJvo~4uQ(V~px5A>JZ)0jqBxq~>V^ICiXVCwgoNOKbr~9p>DT~OD z^i{0A;?k}~h1yycMyAb|{Dc31%;{DO{Rarb>3OV{8>v>W;xChR4+HrKbn<ssd2@N* zd8152lr_w}POKQ3@3XGGjwdF3-ak(%{Xn?H1^S`_)VUI8Nd;AN4YFO;(ILr4)TDAX z@#T^UQ;ev_)%3;C){8bLFZ)mgeS52M(*4z4F3nKh00S-Dvayl0>Q(A3p~i)IOHYpS z%rDp54psklsm^Q9|D`&cE^Q{&tUW+G810<gyRSs(9~);O=ZKYRo?@;rZg62Q4ESC% zIU(oB?$oYMzSK)G6wATecJKc|0iZ{5<SP#fXly#fC5`Ab+7Hz8n~cDr8ToSYrYhDp z?I<A*6P($IRg6$ga{6YT2iRAfN`XeBWo{;FuwmrcyT4Zv;>@`hPudlEYAWemy+s+r zCTMYuGKz$jAlHF5|8)FNn01(YnmRm~w^fvv2&o@u>>rCQ$cejg)SeVWRmI_v9I?s? zCa;}xB9tpe-3Dq_MD&ma-75A_Z05DQr4A6v2|_y}Y&P^xY^ENnhmj|tu#?X{3!8Wg z8q0Stzt0Pg7u=Ng;tn-7yG)pcGNWKTmrc>k>^IVD>1D6AKm<_@F#EYEb6tZ}<9*Pu z#qx21jj#(Be?@nYlj>c=bBcaoSEAV{Y>!%BaPEfEVeO{CA>v4Aq<{IvIErE6TK2`x zXm#@GBN_I|6qRH%8o`&q{wXmXnwoL<8vGOuY>(p9;ur!sqPdjb(IFbh#g<7(XAk9i zhYv^F(#d-xE*+xPgGbJh-s{Sh-36R95Yv<R<G7|=j%8brgWoAex^F5c6Bpk#L*Wyk zbc%HGqU(?3@cTWSMuG#UY=RGQpUDFx00;4Crk?)pU)lfPIsSiVKQ`6@3=%2;0K`w~ z|F5vh!Pvyg*wBeq+Stj=*66=9<U2LM^^^`9d5*WzS{V~E-~@i7E!BXH65&%J*srL9 z6Zs=pjFCvi`$rKmo=yZwpGy?2waHsTy2w`)H8u?up=rszQ!TB{%`Gq5EU8}RS6-gq zmBVH{XL(+4q>W19y?Dt^YJYuy9P=J~nZ94YRQhuJ1caH~CFrE{RePR5zZIl3&E_23 z6{A-BKF#T#@E)F4+q`ASeQF<l?G~B5(YAifOWThAC~SW=i<ovONmY*@VzYjZOG=i( z(n{%I^g%JG)PyLzJB$pTnxt$nqq~d`5?1S24S-;r>(Cq!)a>H_35@LIN|ZcsMkCr& zz<(S)w{yqXJ&e0R#VIhdYDgKrQG>6QH5nc??vP3xH4e}s8H*6VV_F?Ywe#<gi5pj9 zP4R3E0Jf=0^h}yjiUga7XbCAny@ARmPf^FvCCi^!I)QIphL{wtTg3WNh(!Tq&OR?% zeDDCA-hXB2$n`_LbE2i)8`RP1lN3HOzH88;p)`6WuA7#KK0oLhoBSKB*qMRJWb-g* zQftpx9XI-lQElun87V|K3L<6UK3F6bQ&ihTH~;5NjA>(Ka}^<`8n)3%udtA33FEAV z2`P4@o%uwpNfbe9{><<en>nva&eF4`n0aXxJ(9$NLtqxW-ePa}5_@;aNLr9>701%k zmtih0b-YkCzukbd{|IkB^X_e2uw7s%KAo95#jtlHDz4aw3t^MKnIHvh??+HNj&{1D zd4462egS=|xJE6&;5B>6PL%;DoY^O5=scBXig0p>KSHsF8^soy*2Wr|R1bA)q`^b3 z&3cS@Y<wF&;u>II-~A*lqD{cwEd7^>XL}zW<tUNn8oWf<WvD4IxCEq>F3e*`4-i!; zZYKBdzkSBn>DpB+?yO`NLAQdOeU`hPaol!sGUJmX#&V|bMXAK`YKXBHVM2n~*q+h= zgdyr$w|4pMz&I)^iBOGKR$$KPPXaNsE#d{*7?=DF<{jCi^GK`k(8TTgYA7Dp3rJ{p z7Hx-{Z%cU8t(V;Uytxp9lTtNavZc&v5}<?(Lwff{h0M(Ltz4ov&kDMYjllAZOtLeH zN3hY!Snft2+${3p<}p^16&@+cBkh9y?W%;dys|&qRdp+3%90H3&yj6jA9p5A3XDO^ zPvf>**t><D@-<#|J;$4Tks+=bRw0)RXf)BzE`#~IW(rLLy$qt~{j=DkE<{fpo@BLb zIIx$(%%<tQWZ+Pl_Ym|@XN8Qi5U0;sv~#U6*$EeD6w)JjW>L(}%}p8eF8rC1Ls4a~ z+AktHzEkk|PgL3VOTmbDE9SynOREc;$T7`hTVw;J!F;x5uPp9<$j<U?^G|Y?E%cdu zA;(}|6!94SZL@02a1u>Tg8f=X5rXW3*(h`jDm^7qCCDrpQ^iv=QPK)tnVi(jQaB;8 zc|D|7(C35%cD19;nAXbCQK^;6D`LgPaEfp86XT%s0j(I_x`qwDS1dC@`IR@ZWrwXY zNyC$8g`n$Q-0&f6I)Y4+YTW3W>9=PP!ieqt_QhvfT?B$Y-+<2wsiu=vc3e2-kkwH^ z`+07boO_k%>x;&GMa#kkyDhZ}I;>fPt-r5Sq7Ow9IM^pS52He$Gx|gVfYq?AO)SvT zObOHCj^>;M5@IxOm%~{I!c~c4u4JT$3m0V^MIH4?J{Gnl`!4ge<IpBpKD~;jj;zMC z7f^l+AyljAxveRpG+Jiz>wvQ48Bx((>Na`Z|CVE2lzSS7QAdf3S5Ko>;&DNd62KlI zocE*IsJI1X+UjX||AzT+9N|<jScQ5&607sJXTnIR!;WO2=CZ_@R?Kuj5Y`_tX;#8W zQaI<{FtIi#30`G?Dw{wPzb_S+G#$}#PF9K&UA#P|fC}7xzp#iEUsoD9vt5P+HC*1{ zIu*{@{v$Cn_({Dw9r~4WmX)L5DP3!WMW8Bl@F1UQZ<kFn?gSwpIfUuFCDiU@Q4%|L zD3Qf_j}lEg?@no(kOH^FGBk!zdTwk251xFw(O1dAEs?X_8r{!fdyHKwLtf{^E?J!m zdU`LlKRrv4YkIv6M|CO^0yXSxlTxmsq$7_KnVc5t41eITRptmvgS01;#Uq|G$38}% zWrGrYl_U*0$t)rbFMgG)>3oGy%R6G91v9VBL8?}+_pKwbZ<FPEYm@cNr@J-&&eSDv zO!+Fvq5HGJcx36+Cj6p3zC7xpJNM#IJL;3gOC@Qu1B~G-bd32*l7-{fdE!IACTe_T zxRPZ%#L*SpyUWsr4a%PddpGRd703&y$>iedl<JVu3q7`DUc0&5WR9_2c25e9psOc0 zuxCvD$HP?pjZzq;b1G*~kOTK<-MK50HyWez-t?uOY=Og9W}zkHnm_saIGzJ{*VFln zYrEtg^`%rsb{5?Ijo|6XQbA083T+eJMiX74fv_Im{p^ES=IjBuOLw2v^22ZCnG(ZS z`53fS^f>fIKMQwP)cD1c<1<8O@f8i1ZwYfG$Jr;Ud1t4yi`#0opq?|1DbdQmiY{QP z(+lf2e1y{n6kikyJ9Wpbsu<hp2OF>dgEP-|ZtB<^!?LqekZTaf#BbXE5=zI#@*i8= zML2tJvY3uUe(eojAcZ*$!SnU~+RY=^<opXOKaU*E{nX+t-7J9?qs6ic*F@`LabN}} zD)Y1=BlrHbN6e-w^*W2!xkpXZYRzV}#|FNrZl0!&ddhH~Jg#ke((iDS9qxIFT=^!B z!7px8o~1J2*F>&Oa~%Ozxw;lu%IXopTv3Fy9M6Tjh-f+;g8QDH1F~&0T~Y14sw%q% z>GYL)U$}`ee}}Fhq$AalxjQWmct&(d_h?#N+trN^m_OgZhq<vwaY5b&$$_FjM7e=+ zQ(@JYz)k$#u@qBVdbQ%`YiXi>Gbe8R+rLX{s9q$0Ox3ls^El)i)bPf6d{chpma^iE zj8xscE7)ns@PtT?Rld9cVn?72&!rUn6n(XsoOjaV$E#?*MYqHZtR=8Ihz-$g74KF_ zY2jQ{`y0q$_m183aiyLTs$W$`q9?cUA%g)+T88R;OhL4XVj6{;_DBBE0fCg%%e$|r zG1*z5mA4lW&QSm=nGPVk8R5(y{)jskJxezl^w3hGWEkFN<+)X8=G$5DP|p>jU!6)n z|H=PY#hls`%l~%oF!`ffOI1jO=NEwWT@ecnZ*<UBk1aVB%6-A3&(}c<?JTr5Gd3n# zsa7{jmSMxCzRLOTDdS1D6*L1w2r%{Ssk>w`U<Ts??r3K(DvIIA?>^_}pRt<PPUu39 zrIXE`W6!p@CKx_+gM+pV&up`L%KXVFUs`Eht7dT3+BKWinBAL~q8V;?w%Q$S`jU-= z#&!@>s{S<&`lxMOP%)7ZcZXOmN4s6p=IXh|yiP#RD3qOXCRZn-NY1+%*-M5T*hpgp zlgVf(e%5@Klo<55x-A{>nm_t7VW)D;z*{@Q{uyt_gcaNHRP9%AZwh*zF!krkjB82% z+w1q+;NfQrYy+F_S5wOrMikBJgdV>rK^?7CgKU|tRouXvo2!}~+5xOnN;>%q*72#- z=sm83IgoXK&Ie<JT1;t6)1EcTRa86U4ce`sn_MZhD(#gJ<p_U@9GYyKxX`*e=oL<; z8DTEmZ%97EhAqCs{z5z2GHw>sl-e_fz<#@g2%3_t5Hy{$T$u^c+Y6GU5V@!}s43hA zwq<=@<mZ5%6N-e!0^W0*K<6}ZlX{w5HsYvPAVb8WZ4y?4gu+H~ggwrmKRhEg1*WMQ z;xkrmEDEu>P&T^h#@@pUTES&~f=c~+!7WMUd{CC*;@^(Sc~#7<*1pV;%U%ad*m|d> zKk7*BV!wA42sS06rNs~WQ2oS7^~flE26!qccc(8{2ss(tB*wE2#WN0dN7PrQw$B{o zxYCzK_)ZreIg;cSXeU8w(wWLlJ!i%ricbitZBaSI|9m2-q`e2j0X#gSNc>|YJbuj~ ze(1AIPf@z)wWg1;@5&w%=aU$cgk&Oz0)BX}^!W>V_2w6{ty@&cTh=fD#Fs?KE<xgO zDU$5)$TJ$W@7i_W5h2EB72hL02D;O@2)~$|rPa|qkEpUwiY(((I@-g?gP2sx+PseC z+O_-I^_9Q97vD2K*)yILg=?t(2?|E|d9!%Ib&u3`pu7z5?sec>=s^kYtlAsB@{FuG zMyF8ysVP!n&b)#Ly8gYTMZW4O@B@b43%0hXFTj+oUM%Y=&l{tQTS9jKC(`F6Ks6*l zR1x_DKEUC?naer&P!k}xHL%Cp?}rAEQm!<=?7oav7clRvs{Ft3l*A8A+JTK22R;Zq zO^5&`eypkxH_N-P7!Hs8fUzRW^&;=gZ#5#UdYgb9+Oi9v#jB1(fy|thvE{!tBF06h zX3VtS@m_kk91H{rzDW9^c`e%TzcNK0+=0sB%hB!i3qfecz~p1Cd1A5iaVUij$vK54 z<Gk=G47{M~Sz$9@KR)LWW!YmVTnX877|CDXjRCS{Wpwy-bY8MaiD#LNZ*cvqTMRn! zVGm|7i18?InJ7+fIO_<T3*q!N*zFEDfWXe<xLv}c17qQA{YWtLMoI2&Q7{HmW`jGT zlkFu%Z2mSg|0`-Mnwjorg+tak8RROPojRsw;-+U9*f#vowgs9s(z}h!e*n`xR3ota zB93)=RuSXz{Hw&t2mXl{a?;HrQ$Tedx)(L|&N-u#4u5mr!=Ky4IrreodkD#61i2Dt z9Gl6_5GO$t<>V*G-*aF4E!+G#H4WVsc)VEi+pyREB%-;ao$5ZR@gG_~W@DNLqnvhW zNZ{AMcwARrIxKeQXJB*k?*~E8MVStInBdnDd4UhJgB^51rKSOkZ2^iC{7y3(GIdA% z%6nB>{)v$C-Vh5L7$s;HCFo<oBvqbqP45kzC^2NRU;{%~d3c+B42rzPm$$J79%3LU z-%utVVGdu^x6CF^GHmg4I3gr>325+9H-y(!7~%vA+|nvWEk8-T75%pH2`#LF21vx) zp71e5*ZESuouC5i;)4i@`@9P{jmhjWMA_M(5I>EgF*{mmDQQ`Y#9-?f>&7`Psi!>F z769*niMOos4jG}&90#z&^;Jp5z$psH@-m7_BWh%UcwKq?ZYjeTWQ^hJS)(uR#T!f~ z`tP{pn~a4X-@NFLAJe<-vaIcV8Z{2911CWbL34)e0V1h{vN#@V0C)PYPbfVVb8zXB z>AB+?OJHq2S3*X1M!aZD6NAXFT#!>Tg`vm1dgmet+^T1_;OU@8u&d@wPN4C3;amj? znL$w<<Cky2Ut46n0P2lrCKF>i!GF%tlphpwOX55$6wU?(L__`@!qM@8NEA^U0j_L_ z>e6{N&!GG(;1ovT>Skh+1O&zA5#{Yv&7BqyZX;LTb>8BUF?pMXG7(RT#`?jIaD+sa zxg7wZ*eC78pca_KCYUgmvbs2KxZI<M(f<OQFQ@-@7f%yRcc6DqbXO{zD2W>b!YHE3 zza2A3ub?WBFeY9kb5{DhV9G~798pTp5t%HtKg*l0y<sGz&Vod;$lre}!N?#0UY5<M z1eN11s!{eir?*MO>#eT$@yjVbd@OHlV(2VENhM36u5_)Zg!E)5+ais7?K#4Ko^FJG zY-n`EZH$C%-o&gWID}j?Z<7V1Ajm9pPDC;B(q#zKP@nWIX?^9N&|G0RNAO++OY2PJ zs7zWXOV%VyS1RKpCm2R|5SV@BQ(m;vvW?e$uP|Z+X+Wqt2O>3xX3AbHUE=VHIYSgR zlWCl$pI7>%Yqk6J$CbV(n47=k6)G`Mru&|#^<ygg6NYE)xkJtRakfhos$EKeR?~WY zP>f;>`9Q8JK)WhLyQ+xckR!ctgKu$6)bFJdNy(-pc#K~o;58{%`|pN1X%gNA1<sDp z?<`SW`nix$lsQ%Cjl4kXZs(@YCF7SawaLP5(|O#6lX-c$h^9Sk3O~)88xFLp2kKh= zF&Eac*umt>DgadWG2+RZq=ci3Ba5IaCznPA?m;$Ei$km9d9NzMhJot`b4L3)2SOD% zPE_oCh;B@i%pd8a51U^+G3wa~N)XMI51!@pj<+THTC)2-&_mu3{Wg}Uly#9-=QMc+ zVJ~!hXYg}LqVTG^1^5!Q(8@9MV2AeUd0gU=i6v&icTCJ=(=#lG>=uJ=La!vw6tr?$ z?z1%y9BS(Q-3I2!=I(4UBdYy2jAq63M<~(OlB7RDEeRWJjl-}MlS|E}!W*w#l+ZMp zfX<TRp9!V--1}nl@)tdcYz>2Y*ca;QdWLKNvq!V=BO&t&iVsH`F#iw8NEx5FoUrpn zQR`$9@%_Z`>m;8sKjGc7fd3I2wE==x%)Eg}7CNo0WNLO^5x;69mObjjT%D;Id%y=O zRA|cnW4MNNrStm+&n1|!-HY=yln2G<$)qI|m1OyWyB2LF8&U3~k<=thiJTWLd(eCb zV%h99I7jSU>Oy*wvV&GiC}H8~h7T)VH=@6B$&}=5O2QpN{P(n3%bg@f<wpbw87=UV zF7TWx994H7$)WO@oK68{;`W@+p{o<$EB9vEhyRs|PRV;B>j~gt?84uV@NDI+LR-Hl z;X_-Ni^v^0UEmrTzqVe0b;6~FULNB>?=c`xrXB7O-Xsz{JX}I7B739mfEdgl4QPo? zlI=i|e0F2b9`bR(iKJM~&|~+)&q$!(H?n3A2kTD!xGJ6u9etVXdhA2!6vN{O&E`ZK zeNPb8AGm-j0^gy^ZA<0%z)3&=V<~rjZF*J!;x;;Z7ZYQ(CW^sWtczYC%A5EYHeID| z>{8jE5V*wFQI6{$pA>%XHWR=sG>mb7#Cp@Tj49-hDU`4e6t$TE#a-*pirLFUQA%|* ziq9Gl9HT92wU<Kh@VTRvNWjghJ8Wb1Ga4T%W*Ny((z;?+C-$h7-mNH3V+U*o4>$r{ zE}`gCVpO-AtZ!|5ZrI<7k?|v=NRm#3gL=z<_OF@S-rhpWd+c9enK1`7&)R;88PhW3 zlrWd!@tZNN_c}P5)VydbyhZ~D9xZ2wqQCo`E%!hOTEfo$q3AZL<6V2M*v4lRv%H3E zThxf1CJZ)7-iC%b_sUM|TtIqw+Z0IfpuX|^1nF$hk&xSNeCMY7Y-VH|Vn|=QEbS|d z!7t%Jfr|qEWy~azC1!kPRIXAoW93Xitu$`lsKGyJ;m7hfsX@82ILiW>c=5DBGfQ~+ zFY4UnnN^!)WzqX$<cYj940lLv$wI4>LY63P={@wxQ*V@Oo<}#|c0m0mEUGuWEXWBl z4Fg3&s0txem-R12MvU%jJiJ0-ZHVUYsyIR2hG|gRx#trmJ*uE_9m#D_rGh{FlQzXr zk00B;gZ><E>TiIbGZ2(zp+_(XDkR%K&|`Fem?hSmB{q;HHpeftWrAw%&8+ER7OXhO z;vpVhC#;^7cv}T67F47|P#EJgs-(Z@3minc`i&jw1LSk=YsUg7^8=7=@*T6hJZ8Qq z3e1W}23Kx}Xna1p=~iB=k~C%Q&+X=_Z3!Ch=h(@G)=8O;2!}kw8+LaVN6^_a%OYhi z!{8fi*dr#E*?ecTS{rm{^bwl`OruetIwXtA8ev8SJozfL?2O5;fn*Uv0GS1jMU9l{ zLr0vvaG%g=X2lOo<@dUTLe)q}n_$Q**Iq(j`K+ft@_44jNu_)n{u^Bp<TI7@JevY# zi?H+s6t_(l3;BK*&=v^nQ{@m>K81A{>tt*SyE$)Ya25XOOyTZeVFu0~mURN_WMQdt z)e0Cp2J<Unt&Xtw8a_sVPSPa4=nHn9EGFO3?rlt2-`r#9!qhH)-@Js#k8j|As0{zz zS^rPZ{U0hr1=e_u_0Pm9_=j^R^uJA<{!h<c$=&YXYZgSR=2k|A`VL0_{377|^I-fx z!>1x8OWAonB%iI?%JtHAfcyzg0viz3;TJsgGzc?+x*kv)dLj~Q)#msr?KYVQ!f!Ez zL?J|9Ki)C7ttxawRO5IO?(0ML=~gb%>+0=oUm&$U2PpW7VYorBL>1XrT0*`E{2*bU zXDL1zKdK$}ez(7~Gg-{-#>(kXjG>2whXn)~5z0x}pMhnTRUPlGd8pv#Ys07`H|6^1 zHsShI37e*1RqM!E`0^}N-hY)<olRBcr8&~b*3%8HC}Vn`zw~D+(Ff?=^-__g?J2nW zG$L8r`tfWulCLT<B<jl$Pn1_(%IoIj8q#SjT{>+vrD?nSihez7^;=Cr;}uRI4u@#2 zpI6<}F*eLxJnjc8^G2bzY-~3D8Iy;qPrLB@)pi<YdWK-8$xR?7&zFs#gHAl|6(@=G zBIIx^a&H)Rg{CZNuL(2y)Ww^z>txZ6UALXQ=$oXOuUCuRerWcl83-%hksub+9uY=} zZ-A8_h6x8kMUV8YSU%~|ZzT4Fa|;Io?`oHl=hR7#_q3%$Z&bBL6*4GqWbmg7#&jkG z_IoB$ei%CTBr80CNZ5}@Av(Jl05!%cRfULTlf+yVZ+s-A(D9cHw_3#42E3a;o(dg5 zWi50cQSoT@4vNkDFWOExKRjx$!PJMMP=mnCEjOfj>r~lZRYsgk@VUUz0B<8rp{7q& zhN0tOQc8q$)2uiD8P3zFcuv7TS%hBvm`?zp+Qh|ciKELxPSd3EoZN4}^OoIPyLk@~ zhk>`<gROdO={T`ZHfTr|$Vq}i3-P$GQXg+(>5o@QTf|wUkKv8zg(0?|Z{Y7n3;<7g z|4HxvPU8PNy~9Z&><p;@05BZ@0O<aIrT4$*sEeLI1Es~s=O0a`gi#}WOep+RK0i7} za5y|MK9@hlLD)u!p>#cb42TSfa1oe$0gx0`I~o;3+7=)IYF3c~nw9SgmA;ymsO=xt zjTst2*O~8E9qx>2K|)sD*NSe}U7W7$&s5!>Q>`gE*<MFr07`eqnKdcg60yT4w=IYf zD~L)Sb9(P5pW1=k!q?a67v>(<tSf*XxJ+u4ov`Q^=z-WS0<2F#f!vbU*Yo>e+;$IE zPr#%n7okiyv6&ZSp4lFqe_+xsQhQ_OZFyxtN#DVfd?dO%Q>Szccnjvnl{|>EI>&S* zO{?o!Pi{#*Z%{sOntHeLVsqyAwLLmSV|8cty#qgE1HE^GdYL|Tp2nT*YIM;r1WBPv z9-&RUi_>Gx=C)__x{HRdOHZ%EM`E!rU}c^}pGZO98I`|ixq0mCx@)?N>t$C>7p`p| zUfKgc1Gl~lA3w)?d01CaWm0>)h|0gEV-X)-#{6QjE{LKX#(MFwwK8V|Ia>l49T#^r zI5LNwJ<!B3T-n?(7{WPgVP#7~$4436iUUpA-C3?hnAsmjibQds<7JD0Je*2IVM(<H zHXlyJV+BaB2P3gMnger$c~J>hI|h2+cR1X2L1~?De3UM(cYrfHqF|X?hQTvhmwUYz zx;A!@nWpdpVO?(UWm<w%IbP*>qI|GqVkype0whf54T-qRPw69Y3d(NTVR%B0up`%c zhvm(=l1OF@^Lt6z^-*)ADofa2S|73{xN?^+Kw)?$drJ^=avX2aVRZHn7~QES*&}i4 z=WAZE0;ic@xPGrj20Z>f`;h*7WNQN@WocGnx|5Cq0g_I#^iCMZ7sUT%<(trr4+qTz z()`P6@@@)RuU>ESrI_UV$j!ORy9a#o1>UTW9##5p8k7CUhB)QW@&X-MmHP4a39iyL zY$f^vlA1PdX(UYDGv**4E;bZMfgu{1F)%8F9BGIu2%6F2FG2scqmU&3;@7XFN3{e+ z#H#yc+6PvUQ%#lf*+zb%O;to24aSk}lWI*&G$m9UGq6wsgSot=3a0e{vl^ZN#kPRB z+c+^h=@Bd=Gj#|G5a-K9SS<lX!*KrCr?s82{N305$sih8y(Lz{&Onnl%t5a-CS02B zLM{O+39Erzyg1<%ow_oT+S3!4;^;@LOZ0gfV?(>_D0g|^O%E(Fm>iZ^H*{;8zB^*m zmL<l5Xtcv~C=h{jVMlA@7WRe+e|YFfiQk)R4T6MXRfHU9P-hQX3)#gPi^yLMwIfOq zaVF)fFU8DIbE>Stm=(0f1>NM0&}-}w<0H`_>r#Wcx+P=+<5AKU%Trbf6rRf4GGQpJ z>Vea&FF+g8_MC=xo2;YNjH)!Qj-}*UwyUYFO(A?_5$738IAtg$2}R3*E=(W<laKPh zIb~SQGLLM{k}eUI*OAqUem3QlRLlN~b{z`!k4B>>x|oRl;%`{96EtKCBB0~cd51=D zKYC;6q+B4nh$3GJhGXviMY&9(smSzxG&IDQ@B;mMs<YMw_M_;Ru}95VuqzA>Y%J6d zc_Fy#D%}C>(FRrZ7NYW?dt@Ez5*Bz$xzAPGY-~5VoOOiREJalBS?F#|gb~Fe3j7o! z_WUycXBB;6)B=KO>HQoCI+<B}V^sdzFg2l*1TG0vqkdquT#2bM_{-n=qhMtD%&mA! z!5Q@<j)lnfG(GTkQeo>VWGVS>fx|>oj8$pF2=+-W1?3r6uEjP&9+I;}P5W4bzrg#C zdWKyy!{uDqP$n13K==Hg-e_y?mIk|yP{Aj@F3vKtk^b2DCl|;JUp0?5mg4iLyk4Y0 z?!let>fzY$;i62qp;eF-<nW_4i{dvz%gMD>Ys=}xHQdHLma^e*SSngIVTgG+D3JIk zKS$0)VO5sk1~Es&36acvs(!u#e6mS0SV{6dLQs|QCe^H%)$hj5;u^qyhjvpsUMs`( zh3e5JqedMvcr$#ER2cQX+j-+!613hG;`OCy3!w;tG}-%O$hH#FMs8|c1z4ePOsvs% z+lLPe%>;GI<z29Xp@yV{lc()i;<y1WCu@?WP(pt(B+`1Vs@W{RG#ISn2|ciIooF2_ zWuYKY;($!^+BYS!B^(wfx;RF(G?WOTPkfBpjtc7f^>d0k8qCkfNrJ!2#h45vNH!KX z%Y^%g0de}qm%mwnIl<hS=0+u=(h5Nt2BGp+5MJluUS%Z8CL!U-fe|g&5Zh+jgj>K1 z#K^fZDj-D+jbb^hHF62hv}c3#jHFEG0I{Q0^$O_x+sQ|z!nQd$t)jUHCQvJ~eyqO< z|FW+4C1utj@u!A}%ru~HCrrBf7-T5ON7qkEEBl)KHn*eB&ivViV<x>buJTPVUo~|l z{}LPF#gMM$R~Rcp3`_+d57(Y{F3BYk6&Nez)8?MSf({W>P&D*}?t@XtOiUlWft=<= z(-7SL%{iqvmNsulL&c3&Ya9!)j-4D7A1eSKopAEks#_KG=KrDW9fLHBx^2z0tv8*O zm9}l$wr$(CZQHhOTa`wo&93kC?Y`&y=^Gs}cf|g^cgz`UjWyOY0;$&<!5fGen9QTb zY0!VLi(ae`SGHW8!Z=L)=c^L}E&#hdk{yJSJH)KLuQ)4z>l)C~By8X?NlBeftpYwu z_RcDMF`(aE4&;{!;6xHp7$frrnbLIp;ZB-&wzu+{l|o}t3rZN$^Bm>)4hObenz^RQ zO0X%UD2bmfgrV4D);{y3s7nfI_Gn8)2F^5*Et#NPc|jdVvt60RKpZt`ta~rJl7Dd+ z!Kh|i^qw~V<3spy9Xe^kc!AMIv%X!TIK?Vu4#LBkI%70&9<Os?Q*()LVT!@iU}~bb z)B8r><$<@(dd8qmLbx7;_b`vF_$%D;54Xy-UCx#!t3^KKMRyL<Xd_yiKQ9%a#32+w zzJDEdW=C7%)C3n<P2gj_vluDCug!8OUM!^dG3~mB5&halwBy6JB!EhlZ^q9B*a(hX zo)vG;`ZTpbi43wF%x9|K7?j0XDaH(5*pF#$bY}*1&CEII7@Q3}+T|^<jyWX{AmDs* zLlAMIW0(Av*jYZZyE^-qag^eR9^3Ny=n+=O;!G{aSozm?8~h^Gm4a$fWs~uu{Ki|V z@4cju1^j19@g0~V>tti-;8oh1s8R_>jpO@cycSaCj^eLb%^jgqrJrGUwq-N^#4k(& z1{3#n2n|IX^qsH%FJdH3mfl`pUv>*Rx#rqdQ0GY}aaIKq6mx0mef1;uFBg{p@nYxk z{egeb`pB_(cNY?sG2YO{Fe7K3o^FVfY=Et8C9E{GVkgnkrV^z&HUMOg<Z)dvE=v2B zockoOZ2y;Mngq7+${fSl7IcHs5&-j&gXf{*xC_qHjoRJvX)3wq%3QeSdwjpzy~+Y} zvgU4WF6zA~U;?lTjy==f>BaS%KSoccLAilXc^g;r60v4bygvP^sB?V;@IdmYeqp%v z%4m%Ck1u@sfIiOV8!+(2&ZT#5c(?%us5^ve-Iyrf{{w72tM<S`+nWlhbBpykwf~^w zji-7zmPXr~yN2VP5XE*IKLBWVPv>O5ho^Oi-F3Yqjs36}u%vBQN5>JMe$9<iX)K_1 zW%cm|@so%TIuf5oY+@K$LW&lS2aNb$Ld2?j-d)%yX@tKikBC$M3nnBN!#T%zsW@VQ zZ7AIsVY^qM?Tyeo`;+wsPTL#eH#IVAI6hYM`J1_>^IhD5UJ=)_b_`wb>QCCO)JQ@p zH%Iu_i6IvC(#X9=zyO`ooz16X5S{bgU*;q9;cTji6;MDh2!QoBnY=a%d}K|rjWs&C zI?AES@OPC5(m*mPIflj3AE;-9S_DHs%~}tqf^|8~P1A@65CzRY2!OuO^7d4{(?4qu zITGU7di+>8>0lnKcApT2i!sf?AR8L^$D>)>!{?UfkyqJKH-aPkY==QHWD00>_mD;C z=;$L+tM5f5Mo}Zm2P-3t3nEc{A$yXU&xngl6A*nfBX*~5zsQ-xR>SB86FY5hcW8UV z_RbBbHlzVrLnn%5eI2hl<m#=NH4Xz|)PD@6))fJLS$l_nUKS5|zionUT<$*J+~O_R zts2&Q45b9Rq$1T0xh?ex0e=3$iYPFEDD|3kJvlZj=>XxOnB%8_n1J^`zQ_Q-_%?d- z8?tvuA@crx%8fC__23*>E<$%Gizo=+im#Dx^9Cq{;c~>gu!WYG7yt^JNrX>f6pJo# zE#=Bc>c0c)V=7(L*gsqQaqX`~pA5K_u-875QG>-MaYVTqp;$y(qa20>;v8F}v|?jF z(}mEPSJ00mUG$O{TGMaPcR?hExZe^%H$=^!w7gIytPNA+*ABpJO<LMl2(4Qq&-BZk zTkGhwu7Iwsk-R^9Le>2H5nDq`P`%!KeEWYOXB4Rl?g<}zy7=Fb3Qw^BTNAeZIm>ES zhA)jD^wz==qM*j_?O1@9u`&hfU(iyPedCMA5PVmE=I(EjTCbe%h+h4}4v>ZCX60h> zPuI{=CibJjsQLW}zj@$U#tGmLMN_frnB@>`dXV}tlU+$s`p@Q^0}^A4inSIK=#nm8 zD~p~zOel8hKb4ng(I(C}WClX@ncEqD(RR{FSmI=%Tz<4p*&eKk7ZlsqY`t$fbGXa& zbB0q=Uy={A8H3;jAbyBnlah>krMkrLm1Jp3{B@dA%ryZcO2WY|Vo&Pjt=AZD)6!TJ zz#$P2O!Y-0{={9v!M3d7Q;bsehao_z6CO|}i=4#HEcvl0wq|iNaN07-YBf`Vok6X; zb6GI;^HEgo&FXG2Eg;tMvCVsGwPHPQkiL%wVidEmjwJ;Lw?S0p(iD+3l0H2N1F$4m z{GyWLik&cIq_j|j1uTXJ;Zrj5p~bF7);Nle373X5au#xN%~}^EATwTtL&JSdZW4_6 z&h;Z3mC*BUEx74wchqc(3qElN&T~HKh6&*=L=|eX#thfKsuA{<BPYy=N#&B(9!pM9 zNJ;2Kat3qbavXf7P@>4n;{BmlP7jOigU<QoiIGWm`sNUcN?%W15>q;!MJ$Zb;Oa<t zUeI6qdf@xh%E?4ia&&*_m@W>f<iebw4ztnK|068LR=0mvetsws*T@Q9WQE$^*c`<4 z!!#!z`G%5STVst;X6B>l$Z(!V+k&_f7=u#zRLU=uZttg0`8PdPlLtzeH0<JH=txQe zemN-NO=iY0pCqS=c6n`DKHb{c(T9I<X<Av?*|vQ-d2^73xts-zF%(M4w1)IZb{=ix z_ZzKk7h3|SteL9_a43{59L1$)9)j(Ft4H;st5^DGG9^>KQ-0ism#aN`Bn##at{hR0 zZCX<|I;cxEMjQEJwLI~BFu#%lYmHT`5=1NmU3ji;KW;_2_2zKw<_qQJ?J2_SUjXS5 zxnb0b+LB6vxngLY6He?16r`>3AW;CyI;;p#f4@vFW2&g(Ke`KCUfkiDyf>4#Rc=te zF8~%dx4#T^uOA|ClKYm}w`*Fo9<f{oyM*HisEEIyRo}h48oha}n$Y=TP&E7++!WOv z`x!KR5ty1G`-Fl$yl;VD&p%QKSh#zv|NM*atZU%-?i=V)l^%b{Zp?N(-!7~UeX)Fy zf+|}*K^C1><6tlnu5vsXJwrX=Y29F4*Bi5wh8K#1qXY8SoEOkNBL9HE**C6i6-*)3 zFT99cxN~cmqXrB4@lqi^R#fk5jLLOf_OO`{rwx#D6W9apR(0yyb>b~eZDHD2$r^j8 zw3p}+fl7{OmN~->V9!n>oS&c@*it;?EB9GrNG~vo#fEQ}IS1ktbw?o2D_|iTU=@#P zFI;ACPXvE2HuDQ3{0Tbav^I3lMYek?*gm`(`7;s>PcS~p2FeGdN5S<+Jgg$+iZ{yz z-Lvy4HL5C>Hc^@p|1FhO#|t-@CqdqiZVnOl6?}3*O3$0nT=vKZr0fx(z9<m_iFC1W zU<;{}Rx<FmH32zo3!oNj_@gFI`zDB^SBSHz%=pWh@h2JjY@2`uYbt4zv_WcDj%u?l z!pU0y81>yr*ZvV}GVK9df1LH0`m7zWmqwj>z+Rlu4(gTb`rNgD(3Px|;-$hMAOD;A zu$Gi*-4Nn|7<oZ^arp^(s<>iLfmSLb!pmZFb#{`xe!ul73@>C1e6eO&^4^1>FP-?C zPoNV=!?!~+!9A0P{`lFTrW{A6v_#8=>PVgK6VjuB{<m%{=T@4qBa|eTr2-$sN~abd z*jL4fhcb4*JxRt&=$5@zjlAmL{y@nP=C(t2<IbgE#WR{RUFR~qAYR)rE*YqXur0#k zV47`XnN9r6p5tY=<uU4o>R|l#@Gu4DIRDvPFtRO3+Gl3$5nposFnQ^@!t~rA#%Ivm zdL#O1JTXuY<k5OHeG)J9kw@&vbNKe?9_XzNFMFO3@a?hPFvtzaTci(k?nz#>-x{I% zjrg+xM&wYC!UmYQV~W_beBi!td;-P%7@CHjxV|uSFn8RvGF3>f&<hmvfZBkxdf5;L zq|iJA3DiHhp>|HqX~*WJ(3w1OnmmYFJcve!C|!W;&eUi0BkbEq;JQ*j@V8gS{gx#9 zLH{*)chH|?Z-gr;+}Y&-HiZ+rfi0B9>rplXp^7ypC<w>oRI^gKbc5PCBH@H<A?R6i zj;8{<ypea1MVV*7aDJbl+%tvdhFLkrPqTqcg+6>ZN(1nYR`82kyaefLy1f=<Dz24_ z`h_F*w=0NbyrabZT*zjxRpPYQFJy%3pJu!kbWuI4K^ckxc#FFJU~W%9(x#;=Gymgw z!@S@pC4(XRYNzIa6ew=RVlpL<-rU-=V1d@m8kI!Vf~Yqs<~fvTp8|2P!q~Jb`HiNS zSeb$akxjZbXv$^&gR{Nkzr`Et(VeY)|3iK_fS=+90e=@Y^iD86_-3M;ZTZ$veNxJR z<OVVA4%i-^F6gqpJL+Q}gBR-hDCHK807mSM-W_;~?!M{3%p0wHVr+2BJ23u6Sy=(G z^2Dorky4wqVUoXMRFWKf3YRxTum58ZmpA1^J{bFz@3qSCJb+_U0e8k4eai<zpjF;B zPySGCv;aluTjGqizXmcuYfudCh!<(|UP?(T`O?17T6wkNZ(w#C1_Am?CB*|l!Zh@< z_%&w_Wo3*b80}a>C3DGS#?7?c7HrZ^thbqoOD7lJiV0HhlV#eLOEINT#pLwd^c;WO z=-<h?>griXvj|pFf15dBgCEZ>)V#U&l_dnrW-jwiE~?}F3!`J<j|57c3dZ{wZy!3e zt`_g2#?1p{eope;nSO*mVaiPlJJuKCmbQZ%T4v3CCwb`8LKIrTe_3iN_E?k$j>?0u z`SBkG!D|9odf@2XKtpeqm@{jGAiemh52EYCZ2hdeU|S8|@T+^{Yy(8zu-qeb0co!# zw+MZ3yCe5>4c~2_Ft0p)nZSLiCij;btf{cCGS>8cAu$JS4G!wLgKn_kJJ1>R(2T*1 zrUM|D2z`T!oPW%!uaT>2K~(OAK3D5cC|+5-gAr!TA9?(ONI+XywVIvk2O3Z;6s0>F z9<{Efge44lsKWLP^uQ(8fnIr1mtR9^G)Iy@ZsNlxePAGjI^}QTz-{L+{CH#0<y(Md z3&OHj3~=s>%(ouUXpfyi3mdYFMPKjoFmc?nlJ?Q|L|QA#sc9Y&2L*q~cjEnrAMh$@ zmW7uoBg$KB=v&lql_tVsgD%9H!SksE#ycT9k>_uK&C<I27|N;p2?WvoFjYRGmG8(D zM*6}iznLpv1%@|<=HvVbMsJDeQ}`g48o0Cg5T8CVgJ0!>ITufOA<+AWM}6B(ek91D zXx9ZN@NUhvX)?%1z8sw5iuZI|eWNPo^zEUZ9D)dm?>kA569cn^OVs&*E=r8Qetuu_ z1@w*Y{6J&PM>A(|qvgB`xQgwwKk~u_(XhfdG*#Sl?D5KNlblHu0Qtc#zHN<X<_XDt z(`tTx&<FbIcYuSJ+xVf=0*$ygjKn1)2yQpvSvWx~2ITo4v?tRMwuZ_r2))96ldjRj zL6*wO#zEq#KB|6POTpc~>RI0vpqBX{@12PI0f@eYVwsr;WvL4cl3(d1ZMhr_8?|i3 z+qSd+<gp){-O^QD+7Y#x2YIhK%P|Tw2U~JE=ZS^JVInAq?D>=$DOw{M&4(0VR$<}+ zER`DPluw#UvJ|y^izQVmo4slDL~!Zm)+i?k*g#3Q3#WOvSOy(h=g{6ZQgvKP?98mq z2#<)CA_wFp^RpCTc#?hR#VCRTCiyWd-St6w%gBTDOBpc(B}temgbZL)=~P7fSxc~8 z$&2=Zk8#}vu|Of~KdTvmW66`KvtR_-43s#z^;6;-QuTLJ0t*&TC0L(o(GuRYrb|Ty zMcb~9%Pq^q?@N~iR)=N^JrlF7B8;gIgeKo%2`}kN@;V`~1P)ew7pFEI4M}W^$6tjo zBY_6ekv!zuA{og{yIiczN0n*R*%7e94A}46E5R2lj<}$RDp{_4S-~}rA@z-03Y0nS z8Ok{u0hK$Ry+tUXR5LdEz<L&8`I$z<sYa<XMYh0q43YsNTX^I%r#;6Y77HsIV$8A6 ziE~OQY*!@XO!6ncjcNViObCrBq6)ei;bs+Q!@ehBZpi`s;Jsm#zU7J+`KlVQuqiI} z(iZ+Kl2C$@n6>iQ27un1{!XuCDDHCRp`l4r!YLYa)-MOEZ??@61fhi^O%Z)G!M@vI zsAkoE^;a0#NEt&u+b}wqx9hf}F1^V#N4}c~{wl8Re<9`}n(9PjT2NF-*cL&05K&lW zk+&Mqhel2K7|1WaQf$vsJM?2E^wYR8n;Ay&3`r-};HS`=VtO3FUkVzGvn=VZAoe%j zPsGNk)J!=GsyEE(29zo8y@UcdekJ;0QFCi@3ab@Ep^+O%QF{EHOUk^?emTzPq98GW z%ZYqEW2kFgpz}s-&M%Q_oys*n<=Lmx;x$$+4KnTCd1B_G9)X7L;$10K{RP_avX4z& z6kH4Ac7cY+s%K?ap$n5c^b#GAG2V4Z&11yk;ZVX9r2QO<{zb@)ni)!=5O>dFHUFuw zn&<QN+~9clPA0vSZZQZ+yP%F=F||+<qe$bZAaxH%(F(nYA~p1`32bKBD#EDQ60&ti z8FKdh=T8waA-<S8TDGQ*lQYt*uRh1deU!&6FeZVP-YwS-RmO9u+n(7*gE{iPVCRzx z<np@yg2!X?YH!evmn7tBz7RvnYx$ZUsH0SN1J1{%^#3sU7!)@{Fvp<GC3+eMfRYkJ zZSAo};obry(+2D6LwWch4K`%`nbCc2NIw+=<fBIIPZc2}NdQE_mV3AC{W|U;d8|Pz zpJfYQ^xudvjr?qX-}0mkGN>P8|JnO~2|zt@los)=%@a&9kuL}NgPN_WD4Dwqm{P<V zm?3uM#<*&_x(x*3+3sJF-U)Ky5;g2VqQF&R!6shbHX#r#w>+*G#WLl9Gg5_^Kgni& zRt!EMA%2r&?TBCKj45;f;wbp9-eD%~k3m%+c)bx7&@pQ&=@nM=J1_i4EID6S;LJzg z?J70`@2VVRPzw@W#N=jxmloof7A!Ecspcn;*pX1DR0EWxlcnQk{Y?WTV6wrdz)>pX zAs#dkn^oXL`{7PZc}mpH{g_TYHS+Oer(llTOA*bVm1}Z)iv7FubMx~tU+Q)Df8GB2 z<+1Yk2bm8}HCXu*XVm8(lSso3ZC9gO9mWnaF(vegjYw8{7k(|@x^&vOrPsL4tH-$u z>-aI)ziB5lW2(lrxgV*L7%_~}rIKUnnmId4HfSr{3*I*D+`>4e3-32mVONai!N{JX zuQbp+a5^?yF-7}f&?YQg3tRiL;kfe0AW#b$x20dXGGxDc3*4*<<RI<}Ec^x1dbR2x z$%XuS=-*n^xzNkygnA`Bsw2tQn}CO44|aVZYV=W~{o3Z3l>B7&(4@3RUO~rk45>jj zSSKbtK1bUbhFBPn9qWMAnZbN%wN?<g^ZLHu-_x;Us(J|u2}uhzx3J?vX@6j)xP6d& zB{ldwQXL{56{cqBp@m9yPXzv1$%NG3UaU*N;je+Dn`F6@-Tz(90It*o?c{`&T-h)O zYO>C?;kb-Tp!!my)utdt1YzcpQz&I5E{%p~jxZp^Wx?~?IiASC2bG^gRz{c!qWu#+ zl1l_xP&#TPcSy&$^ja>853>=g%#mE#{Mqb1rb{l=M^e+c8L=Dr0IZBiO`lL9rBwBZ zA-<IxdT}eu8|q9;cbskZTRMWtKddL5yyYmkz>YbpJ9|SSy$XU*M+b3d*>hZFNWR#X zKgll8z!J^0a;9Ez2a0M%2C4t%>7p%PVJDKZ30UPsacU<UnkOCd?O?cWVtUHEoK;Al za`eNr&^Hb05-4(hnri)*mazURTxxbT1knpxWgY32Lpb_jm&iD7m4J!<eVMNy4kNjz zY>`zLqk0GSn%F(%!_jnuJDseIWw+Qfe`@5mdi4?7j1{mX>uih@aT1zF4?agDs^c<_ zO(UJrknkcaWS_-9Dr~54k@DZBLI|VAUhzHQPpTDXc15)jQE`?X%re{Dn9esmg|hYX zF35^5K*dLE4rf9|gVI`RDs$%&wS{>ib28~-J^y07#bW=70&@!Y4=Vdl68n#v%|n{z z!zuCH9^@&$+3Y`C+!i;y;G#@!c1Y_RV4^4y+wLlVm}*X9HtU=#*p?(Gec8|gI)!`1 zl7l2MDbbl^_4&-zom?g@zT_kScp0=+ILCfj*_mq@fJ7Kqut^{m{0U91;s<lNoR*J2 zC38X5zSUz{@u7&N#BpmCz5amqI2Z;aF7Gg0VU5NmR&SEDzSln}(DXG0f?TnJS+!zN z!OPyeUZl$fK4cMB_y7|W6O*F`RdXYQ1-C@#3*XP#qkm}Mggr+pPP9%bq8;F^BT0>p zmACtxW2*6ofwI6@d!6IxyS$Ho{FCKkNbC&pbC&cL2FnVQJU4=s+?Y&XfBPjPSdd_j zRH|SPveG{Yat3Hm0Jt~$@6xeCS#&oUYG6?q1p-&vl0n%o{HktVhhlGEn+|gYTN2|V z2HdSv(mjh1Y2<ZT&IZR)Ig1cjq&E{s{vvap+`&7tQhRDVjTj)X3%&%@yu;XcyWoks zd?dgkWYE?(_B&1{LP{p8sO34m<W#7HCa?4gjDF`TDu!i`euXO7R11oFNy?yS4PS5z z@O<>mOeSQj1$w;@4%nJy%4)1u#O@5*wmG}BU=1O>BE8_0@hQyLW;AyWWwypqG5P}E zcquf+@E`Z4Q-dpuRzAwZSKauN$$t<}+#ne~;EZx%<xn<W$R2TglzOc7A_$q~;K;Z8 zNC7)0iF7lVx-2p4ik_OL-{Rs>7Dd(`CA*1}W+Qcyh@37mMlIH<*$2AbOO_BBLNECR zRwzoG(vwU>iKo1&$$Cqq0R=J;X{_L$7D@$mtnia9SgDhpzp`dh8CHHt$iofH>>1XI zvvx%AoXdm%_)6?qI7jGF-rbl)JHze37NM)o@{d$*!PlJlgy6=F;Vg}-s<+H_zakZS zA%f|j-4TfO)Y$}pz!3AGi7yst?ju#7>?ig1iL*e<^|j;jNYtQ+72=LF*e{l8<&inc z5Tt{?2YV1rk&kOO&2@`2#9u2+TZgpZ=dEjK61oEoapw8E-!*&#E#EwhdXURTw}|9h zo(2eMfoN<hlFz3K@cs3^wV=`uKMAw6A&Fj5EpUX?uWf}$HMb(n2QN_23WMpvZ~gPa zN(0tr6=NUQ3Vgkmso#eYQ1t4nyJen(83(bg8LY_`7&QYpuQ;BU3x+vrt}}&2(q<oZ zYBKI3u}9D%9}N7rccK~W2}L`><dW;BN-gHY0M&GYQ1o+(9vT!Vd1lDxfnCJyk@d$h z0x|%u^EEj+_VSa^c<0V*4jBor_@|FYRMZ9hMzT(KD`hMl4@0^4^cE511@U$C7THQs zs+sq<U7f~=K8xJG=>7`>b4jxW?clfh-fYv~GL^8iHBg}g+_9N5FVqDCVa^r5vxO{I z+w`2JZ4XPTz|J|Xc~9T5;5Z!R7ED(=s6QY$a*_$xM8g3<YFE}QUQgM3MKMd860Vr< zQ%&f-)cD;HgwPT(x(c4cy>upq-!bMY82zpza7L31=m~R*XX<$tM6^>V!FpZG7(*Bi z;TyJ1e=KXZhR>m)9Pi<L^gOFqNTv~PFo+CSYS~)ozwu|@o^ER4DiH3%NqE7>tlNQI zYW~oNNIf-w8RGs6tUL{A5V8vLv?)}cOk<z$9G+rM5QoB}XYU05h*3E#e1$YtZfIX} zOe8w8nBI{*iWa*(7RhcNvSSV2^^1dPmK?d6l!B=iuik7lLk~h6B9dewtay){n(?>+ zMWi=yg~aCgtS01-M}~cMIBJ$g;Arq$NLwjhi1S~M<|Dw>Zl;JBg_cPU-LM~*<(Dga zYLywV_M>I1XrVq$ZS3+LYh6qsX#D}ZE$UbakW=P-6t!lx`)P|{FyV>EZJD!W$nh>d zrM`9+>WVPcT=z(&`FX|DF>{uYZ83uw{vBQi9qSQkQ$zVb17bs*TzA8s!Fu<)*0m9& zfz<YLWddw|PXxC+j$^Z%yn%0Q*I-w;>CJ)b7jNM@B)#4TI^|SYy~GELcC8PXn!y|P z-?mmDbptDra4nM*`(tYIw%si-whZzdGB^ib>G;2Y?t5fzSz3oMdBz%S&keIYipJV8 z<JJn6)ta6ZFVrSM%N23rd>ksgx_Rxo6n}7PUvJ2t{MPGo)X~y3(X#GOZI0%s-^Q}1 zJeji~qAg|KmX29rPEI}I^o#xV*H7@pTc!itw?oIpkG-dsA=qp)wIp=GQlvjEZPOlv zB@e-IWS>i8RJp)8udfku1R`b&G}Zp|o6j;s;z-B~*G-B%sHyK9@U4uU-%E-@GGEX9 zv8;na;)c<hPN!7ohE(NLA}f(zDZpeC$P76LfJrh(46Zp6nPi|&2^zzlO(ntVfEN*l zM4}Y1=t`gJ*?*m7K(#2WQfI{py+>@EA!;|SCplFl)9y@iLZy-9te*4O=&As3kq>8x z{@_Z-x&m5B31dmgH!*~4!#rBz7sa)A&kO9xe8+Cndv#uCuF9#NDSUwLd*QPG?e@=g z&nnW2a4GwX5JL&yk&?&caq6Q@0g~uAGpt$)z=9!6R8+9&=BQi0DSDK4Yclmc#fw71 zj72F+g_dB_ZbE%?)1#QASC2BqxJ#>+VYdE0MuNriLcsY@w?8`2s}mp|K1!rQx7#P% zL63o)qSHczFRDf<CXe(PWdC~nEnzO-*c|6!(vmh7O=@Uc{)=)09D}udPH=Qa)O3SM z+-H5{wl}?1Zm_u<Q^3EpM_AUY>S#`XDG&9<(5z5OBVgAMyw;2D=n#;@?Kz^h#iPVN z@~(I^%6K&DNWMH5=IE_<23Tibgyb;fR0`TC`5j!QnB5E~Y58G)%EZR|`;JlKkE}dc z1Sq#yclbQXBu5YT8M4dEW98%XV9uu_)7eS$O_l3pu+HUWLZj#SB2IiG5}H9rT`%za zIdW7dvo`1(lkg7Ea&;V-3#fdPA#|v-<I0lyb(-^Ry68`$(&BSA_p5HGbf;m$d5?T_ zM8RQ71mUR)BZf2^Vq{$^vU#V+bC=L4-s8D-h?Q`6xREXusIZej%DDJE9fV9Dn1&C< z(fO9WLfT<qEx%9)3guIkL2)nW=;hj=@)u`%%}q1bJ!96Tfq!aR#Lt0YYZDdmIzrm% zzhx1}+Q_`#Xf;c&yLUH^sJy+l7VYzabzNY{C1U@q2#q{BuWdgfN!K5s?e=o*tHH8e zi-4y3Do9WOOtpi776Zg6f`u*t#9&nS#tP&<Y4vWv3MK}bP4%!c+?3N37c$^lP^Ay& z{qm(SbqA8@(T<398*%CBreFI@K)tlB-}B30J)h4K&;1FKpi41Z;?L$$&bT&IQ`P#) zczSOAKc33kIxAVzmqL{f^>HfVyTqAYy%oGGUZ{0B{Emn3bW;z$Mn}@lub1TlMLMJ$ zH-%RhC&oeiW@u6wm{Hs_QHFUL$Nan1kq^~&l8MtLzij*SZ;Jyf9-}&BNQ{&EuK7}1 z)3$K~y@c5#L#bZ!a-;byT<*uzT49EGAiH}gi^O8>$E7Fb=k#0;I=g3c>i~p5HKl6q zIFSy~<r4Av5!ZD@;yn?nuNagUT=dF*0MYZC0kAIsy^<fn$tA&hzg0s#hKa|CIMxWD zMO}O}IV_2ODCpiEZAxS}GOC-VbZ&hLELNgfTzP*B3pbd{lDom{?+bs%O}Hn4@d?^n zvZTX8YZsdtTg^gN)0j1BYDzsm>J4wG^cP}$-4Am2d*1x*H=NOvoVDycv1`|SlXQ8a z)p(e|@5IKvhceaH;A^#glD~l)9jS^O=LFhQ_7?upFl?LAC@)kUISCSzUeJ{{>=2yC zin=uP>&#jPUY#nJzqh)Ss#V83wI?@|t!8V`ly*`j3rXR8Vo|<ONZ#%2FUjUf`vj$V zpoNee=U6ebt;p%O=J&mafN`Rkr@{m;j$_aK<By~<s*!D}A=v_>_0%n)sgY!DKQD6M zwiG<(wV^I3qW4)iHHlI)UW84H5;z&-ExguqPzv~x^IJ6;X}qXu%SWdL=9rfbTFSv+ zgi`0h*(?Vc#-C2ML#oF&4vF5{`u!a(6VzmBV4NZ+OInSyHWQo5wrfdCL!JryR>ni% zh!F3iy~&wj^0&_rPBD4(dk-M`6wJ92^k~>d;FRr?C_L!Zw*8B7&X|U4#GMXy_<15g zp;-p_G{9-KuXV1jjrr(KZI=+A#a{xv54;lP$IsICPj`s4L#@sTHl`Nvlc#Y4yxZH* zueF3l51(Gi{V||wGdCje(M*mb;6lnV1YXB-+1Z9wt>J*f6e4i3V0fYp<gMYt1YYrN zvuzv-$!b@nY4(c)QGZG9nR<aI5UGdkM|2m)2Ecd1@-*RH`A#KNrp6{;Bm0{Di7Xfl zW#asZbxw4C2J-mLJ{y#Jnof_vx5G|H8na~Rp$>gmzZCNj?t^PzA6D%bs6to`xz#$T zd3kmMRLuqSv=?Nzq|r6=QML@@rLI3tbn9QQfp;C&bBkwuXX?!tej|0e6L=GK`-Rl# zl!mzneA<w<ZqD=f2k1Wr=KpR}{+|YB^xIR%p@05-{D1y@rvEPkv$Ki2Gu?kMP<Boh z&L*OEjy49)|BE&F|FEFc)-j^ck#Bv2cJ<MRal+Fm6@-$Z5-|^lTJa_mUEP|xSU#y` zib;82|786P47>gK%Z)NMO>No&Vi0pU%uc-b-e$9#zTPjF%zz%+i}W$oLK%Xq3^M@N zf$FssN3@a0p4e=Q?GyAD_F8M2THCJ9OYUz+grHuN^olI-V=HiOQdTbR_fv5<w)eYp zc5oC@P0)k!dRr^ImX%X4+Ab^2TbW(M^xZTxYGB2wE<$c<n5Hm61wmvZG@-&P*7l*> znYOoPIj%8VS(-H?B8*M4zgZF`d;QYw-JHV&beR5@R%&SagjKmT?T{W@N-<@^;`^;w zYn2vtam#1iD>HWAr9_xNdDx__Atp~G!LO~xoCM82v$lPpU3Rai1F|2DrACI3;2fG- zak`c5P#{KFZnQAiu(L>qhV{tBxrUAkHn12QiSQYQb_Rje>K<K?aVU7?Qyr&cbxyxJ zeM)^vzKoZ@NZr=H?l7s)iXe!k2&?=|jmJ+Qd(vZ(cwd`^6PDqtgn*70baS+Rw<L|y z+_M#5tLRLRs+V6n1(HW`+nOZ|nPZ5JFh*2R&mIP<rv`UT(|_nK3IDTON?MwoMSv76 z&jzMH_^n_+8gd%)6XAy(AugQ44>N#+W6cXC0fwMdq>mGG0O(7(g<agS3!I|6RFM%& zxl}%2R4FgWR4UKNeslw4B-DgIiYV$xKLqT7BGF3|9EhQ)=|IIKi}V%|!VHb)E?>+z z!2s@zMabc)lnq*xn?N)Q=qkz0L;%LTsXa>Bkq<<fLnzW9C)E<u0terK(S69T5R~D` z6xu|CZvanYiof1~h<4%&OoMJ}V;RF?Q)P2hSFt`kYHw<=23<dyF}ZNyp@BUSigxk4 z5lXipr%_|BVn>uR;G8~)0&BFVJlAuwF&Ab7deiKjjV$59?ms>9-#g)d_DIqPI*kD8 zKV~%f|ACtJUp*q??rdUfY+@{9;^bst_CGqMMg!Je*(}4iuOnyT2ux5PBtQ{_2FZ~y zL~s+Lm>-HH8H_v)%@S6Kk$8#pA3&-&M0ce`SM~2^rAqy?sZIC1q)nE8duuDq>Pn}k zo7$SyT1{G|mWz&>6-n=&-)#0j@Kh@=FUim6+Re}P-bbGA)ADIAkbXlqN#M_*+;6D; zz7~&#LAjw<4X~{{C%m7+@ENJikCJEK64<`wlQoQQvOtt>>jO6A=KVHg>ERpdPdhM^ z*PPi;U9X=qv7h{zAFBs3o9|*Ry@iuGPH&a0zO&n86kJoH@bK_Cls?%$+*BYx63hYI zp_Jg}hGyu?>q5f_@dnmb5|SfXQgud#K+o>#pv7?M#Kv&xR0_^$%erjbNoAYTf7|hy zN5c$4GYv*1=scZh6Go{rDk4U$6LO-ym~jrrS`sH0Q(g6wuo6mYSZA-6dj%s28{rG% z0@f!qz1gBg;{=kZAxB>@n?~Vdb?nqo!w!Dh<x=wB0Er@!DX@|ZcTVKX4SYE>l!~L) zR2C2oI&uq15~dAx#x9=KB?83nv%wiRFkSYyz<l$aN}5Yo8w=aj7#iP9Ck(f`jn&Og zqqR~Mtu|J@RZ{XTdzY(DbsstE4V6BUELq|%ccq2Ynkw3@PAi*B)m-bvq?SN=r>#sK zt1K7ire9aK42L-212bE!wk$z!+<7uKktR)d&WSinceTQ#S-W)UXWJ`zGLOq`qwmuq z5w*tDTY0gttZ}+JytxgT@D<K#KGk%q3wU)m;!n?t_Du($@7CUWt-dytJ2+FdF)qeR z=U-E*@!v;IMp%|KQa&cD#EcC*Ja@8@%}I;Ya>S?`=z-=duTdD*0I*EO9EW3$gy^=X zm+OeKwhM<9^~xaC@C6LquA~5Kx8FqS@7TDkH&dfYId`+G?xd)fkz8;|a#eI?wQu0- z6H3t?T(+2SPwBm8gP$$~9cHCP7izzci$XT`(ooHBta5+2FvU5{-E}|!`aXMm_O~~~ z56P9_A%ml_Pft%*FWh|N<<e$vS@{z$3;JI06m$9>M;`8pO`W8<=i+4V%SPwrUf{i8 za?%s1MIp;Z#-V1BO6S69LIJaEZ;^t|Bm$$)rSC~OyQAj#Eh^{E);|ys<wGEC#}55H zBXB#ydP;tzSr_Qa(WqW7euZUBwbQTvggm>j0|O=MoCrHf6BJ1)jq`kVHD(5~tG_d> zceIkKD*TPdhsX2!y7J+F`wZ-Q7o6=TQvaPfV0(r+_+YS?TBy=t(56zsx;2=pyT_4C zWz;d=U1_dG9;?tC-l*P?J5g_Jqu#`jHPOW0MJ3){I+2xmD68J+rCeXkZK<N*@Wi@n zF?kvR!(PT9$F*zfAC0r$7reH7HRMjGSGPILt=u6f8fre4J!|uHlD9``OS(Piw{xYQ zyDAp-Sqi{Plpbb$<4dY6vlM1|gd|!L-oOzX^<?r=utsQk<<O%p_Y{;92grKT@UY{> zxx^-T99TRE1Cyyl1l~DwrkG-tjea=0{CyqoeuYP-Nu~zrOh|JX{b<}__WoTFGTHQ} zk;$wrp`J#(yLbq!IxUhk8at_*t|@Frx6=3Uvb$XW7Ogv50Hv>#CdGQLTj6*q<%`GR z9%pl@&&`gz=G&mTx%i?bS&RN4nSror*Y;Y@<S=LUZ=jA{aLLk1*Ii<q@nF5v-&M3O zo(5@GoyxFsqu+-{%w#2a6~?ThLtPbuL2P^ktR<eFm|miiqo(;mMl>7XZtfLs(}VYx zGY)3xrBzXqoZa0;V<SS*mNVp9ieKlkubaV!0q5WbQ-UPs6Is?8gn+GfjE|NM75nc! z{{XQ0B?~RpNlKix{ISt3_TiQFni(yPT^RO~+_wb%3kz$5DNF7Fp2g%XrrqJz>I74* z)r-;7I~yFmF(=mE2)m6}klf~D6pb>OsF<?5=omuWl><*L+7V<e)_rIxO&g1(m_QC9 z>t^{OorYX(O3U3fWH+X<ZW{?1MNLb}96<#vw`siz+q@~25}K@ARU9(=#Zk9g9WB-= zlUD15nrfj|>!iO&3Y+IbMoE=1a)<N|M^JQIi5cI$y~>%nZ4Gi%)aPDs8?SJ&>W&>W zT*hT2YU}r=9gCxfm9b;Tlv=J6wpxabW2p#?!@6Z84q4;D2-*)2iOn=S7o<Xo^~aVS zqlx%ho+K6$lc~HNs`OUDMv!(~V`A(n&GLRLG!vJGJQ1_m_m1FAi}}?GoW`M6#!4+T z6V+>3`$9y!9-=vieCA$}sT1ccb0yRhn~QX78;(6!O(uQJ8{!3VE8fPZmD@%|8dOkK z>8Lj;SV9GjX%g*={)3a3s2kUlRxT}#MO>++k!Ll|%Q(v&ui2S=k*8K-2@_@;iCNYi z8m(H6Q8aCn&kDZ0q=S>AL^avj9^n}cbHXj8y=<nHosceKd~|3~$IoI_qc`^W<afqt ztF8PhQL#}?6{M4vfofy`O!Dz5$Ngc6tjy}n*<{_h-yKZUYdQE{Xrna^vb$L0#J2g= zO>&nDTPx@0@b?+x)-o?tmKB>7jv-AI+M;pJ#{(_oB-FtkgV1sx$3@LqVOKPR)vQYI z>2YqcJ`V2b)y`MhMf0Spcs@wcoW`V2ChnTZcqm)rksv+Blv~y24%1o7JzezP)KFB= z71XHNI4_*N^M&6_ePoA}G5nqW0`S6;WS%MJ2givDa$J^?iE#nB92hX?vUirVA!~UU zsNJJn-SIv`*b7ySvDGpigU9Q?0GHlLB#eJ|9)sa%47@8O(Ag>Kg6Tn>&u8m_3uxXo zDPJ1~&)Aws7gEM!l~T!URx*@WELuhzwUuWXeRv|O*{VwbJ-b6wa8#!JJjyx?#?g4Q z?hLx~0+>Qg&No;?o|1&0hP77Lf2S_iN*HQo$Nm)kN{Dsyw8%j0vG#*#Lhg43LY5Ze zq7BoB6yv=*dYx%s#L*kMqrG|_6^J!jKaAmGzn;b!<Jiq&yZ+P8WtY8Aa0mBc5^2xA zXLXWPvecYhuQ$t4_^TBwR&`)bCBMA$gxnaaS8V3F+CT?DE0$jTF(c4~ymsK(|M-kG znzHSiw(S{NLvS{@!qQTFLLgNGiZP;KnKH{8r@3BI+Jj?H<VLlV^;+dz=Xfp(m(@aR z;)j1s{3da%5bK^ygnt~a5P`@hRG@E5I)No7(U#6-=W^o>>jz5d=AvN_RdBH>puXZF zS8g3dj@{9hEeh&^kZ@_}s4e-fu&Ah8i3fvEcl@tvlQ)%WKRvWlaB4qk)$9&%7b>a_ zJc}HDseiHm7UO;joj$TTQ4ABG?{Q8H)IPP>=iF!j_6Q9dB4eoNG=&;jSrMww<3CzB zB;Q~NhOW7`+j5ZJ7Eq81qpx7F$2H;l6iVO5JX%g3jqe+%ghKdTiGv>>85xg7^VW>~ zfEY@r&--I~Hm3EhqOzt8Mg<~7ZbyL0>(P&bhiFjAvBqDbdTGCjM2Q_q2~xs_VCdOw zj>NRN<FkmFF#2bkr=;bj!1HKYBW7d;eMBgI1G6GLTbKfRUVDiu64Jrd%SOZ)scG}l zc_a}S%*9ici%nUy=0hJG0_m1u<f^j)b=QP#FG^#K!7R+u80s`RN2+mwJ_BcXn{e8z z@pt^zq|_E(=_aIXkGu{tJy*GrisKH_iPFN#<6dQux&}`;c#MIc5Hd%F>S$bnsD1oP zqZ*Yvj0;-(E7))J19JtDyHrpSM*7d5i^y9fjLIMI=yN%J<Sjo#<DR(D9#AEFvacJ^ z^aw;l+Ur3>Z_FtPR~Cc<EP?^k?HQ++d7+yUwVgOncc7cmG4~6BS#R91J0$!eAc#9? z+#xcFAEj5o@9)#s4{o)-u&_HL?tiIZ3ZM9SDM0v1<N=@D+=Qn_@~nT_wIk-F0J+J$ z+$3y=QI0sdscwf;j$E?iJnR&CgK9@i?y3+R-`u^Va!H+?*Pzk4Tz7M?kfr1F9UOw! zwZ_JXi9cJnuA`R>l8*?Z@(dR1?qsKt$DrkdUAJ-Jx3RF~Q(j0XGE%p?PN~<qQGCzY zuUQm`2d)>>VI4=OK38uI>eu<t*Tt%7Q(U*cmh|B(_o|k6w4rKE+kuD)xh8*-IYxV) zhK?o*T<42i!<Tsnb@E1w&*+I*tq*Kr30myq-rVX!KB%|ne(9JaGA;idocfJ{zt3GC z@i27s-opAm{U|1-HaVQa7@fJK$Nhw6N#h+2Ns#>o6X;i1F1W;ZM4HipHd1_gSY9@i z_i~iZ{jjrCd<(3!(fk69EvocNrpGn|kP~`PIyAq(J73hEZMcDB_DfQ0zqjC(1}reY zk6)HPp04E&18SwtJ=A7fGcUrB;Bad>BJzLgO*citr0tNRGME7bBX5u{+7D<THJQ^^ zZ)sV}pVJQPYzVl|lQKl4^9e#wi|(mt3tvw^9~<G4&`C$ao%$3fQdp?t#>|swoK768 zQ_9xyk=*cY9*oTl(R@<7Rt#YVemos&YcvAmFc>o4=t^gTs2$U5omBeM|M)be%_LJ& zW;18Ctl6|XIXJ@8`lAMNVJ4aoCI}w9kpCb7rW4!TKC`YK(0`~QIyJY-_V~9ieMg!I zzik(^Wb<1}RW>b|yV#h)3In|8dqxRNQhW4~0IjRSpaDBU?cranMT17>j|_3NR&c6d za{7uQ^{uh*dcJUWF#F-ScgdacDL9I9A-Q3{HH1rOM~zLJEE>U1#}${Sz|{!>g%Y%b zrW&^CdIGJH^|4qMY*@6VL4L73e56hyOmhBxNe;MqY_IxJWw$ibc9}uSGpGk#A)cs( z1Sx!qsJvglkHl%`?gHuAdV~#%sKU$D!FOPmF>l$xiUx$*YgpBS9E4(?AsY$_(ctk$ zMj#pXIFk7EG`;8~--aSp(afO`^fQ<M3mqTwwcu9AJn8x{YYNqz+vXGvr9!qU*80$K zq0%W;EF!kArRKN4E*`25u~o-1sAElLu9l~rZOi_BwJMYE-Ii-zw+V4yB7tSgHF~ad zqIjt@j!W}o4C#cY$9t*s1DtwsO^1Z$1H;s8jE!K|jp!UltlDIoad9r&#3=_@sRgfN zO7D2H>x3O?4~End1aF}~qv4n7^8n;T-*`;To-2|$X*v)2za&a<Xjy&cFiCkN&wJ+; znv|uCyLrEB5wM+dL&hl@$E2z18V!@_9sCp`)h4OPVe-Ua<PNdcTBUUAdU@trH*KKi zDT!EZ<~C#<RFWLjAXQj8%Pm=dnt#pkArUubxcp+T)@4Wu*suHwFYuWF`s4`WaVPyc z1u+EIL3N~g$}QbxN+;I1=*>&;!dso-)u#MdAZ263v>kL!eZ_<|N$ZAJbCL@^W&-?5 zo?klqn=5Mf!u(FFR+L0Ok|sSbO-TRE=ry2?&p8q$GK-iRGQ{l&LWbu}%XfsK>c(w# zi{@lClYnao?~2;g>JiVfZw2*^BY3e?tGlOX1c8mFy6nhr#VOZw+I~^vwvzQ53Vs>u zDzXMrP|@tR;?JCakOq3Ws8GPiJipMgXax8gPe|&hJ-E{9FehYmD0(!4{$#+sz0R^@ zykUQX1fbz`n+U&nE64)v_A8iy;8%G^l*O4)IuU`XEnhe#M=;4fvgg;%8S(a6iq`_! zi_#_He$M?b+qAet1dzn8bHtY^vRnFqMP!fkUw@%^$>J6X35L>+9E=Lslmgt8Ui1od z2HVr=z+*tAQZ6+9YRp;A-SdS=FR3&1O5VIQ8Ny*oK|nDR5Q{5UsURy>ehGRYV)J;6 z*HAwwpka}+x7^o9fS?|Xsx?SQrhRzV<rBY<eqjIf$~vE+1;srm&XhiVqn}`*utz?j z*H-Cu7OHYFX#lZK8^cVAEPM^|VR}@{sO2U9({|((yY!4#yfb;f;4miBqD52Lk9f{6 z|CLVOQvt#rJuglv^^c@ICcWbw);l1PxHof(XK%PoJ9Vv{&bljfTDXPVrX0(oEn}?8 zJ4e-*w(j@l?pJGv3e}&7*VZhqT><<STJC#|X8b`o72z6>(&;_`$=E_`k@X=GE04xl zn2^r-XM*<MBS2A`KJz>hqfuucDoUDidiP=P{-Xq;ExojB>>5X1Sz~9U{&IFqC?{mY zTX@qX<WB#szOQA6G=W3_NQViF0PoQUyOytXoi8x#5gBzoonggi^79WC&&TOBO&@>T zCyK-y`onA89qV_mj_#;eyKC9!?AZmQWdT-A>3ZcH?;nf5$a9u)?W#+=eOP%qkzb^z zVD-_P%Ju}sr)B92D`t3z@Od(T90riQo26*md{+9h;uxat!N{AXxVPF2I+s3qG!8x9 z$*nQ(cO;isB@Za;&oH#V$KF?5!|StV;b9$x1jraG+4+cgLl{24DQ&q!YXVm_Ul!Oq zR=csb%v}O!0}j$Y!+M+@TPw!^hVmNeXH<jSdSENPhRg4g@;6!g3@mXl?4tB%YzXm2 zcF5mJcDxg?W;t)YQTn96)CUa#f24lDN4}68Lo&}G-Vv#>NljDeD`M>!Xdy^)hpr;y zagck(5Ml+-=~m>wkD0!O^!-<u?|)b0{<lu|pL7G0o$iNYP#~bEe_A%*|53|Ua(4V* zR2ky`{i<kU@c&|Fa+GAOaYWF*O?$FtJX;%*LNPX7mgf1tgbo)`wpmGt8#E^r@=*jT zHgy{t*d|z?Yg=^10=$UZUxcZMeTiw$3+9VKij}kFfdlyap}_)C$q=Aue+_5dt+qNw zvR_SKWxe#i_}uioUG2rW0%Z#>0F5m<q_d-!Em_=sNaGs0tBMiE;v3)(VKro<yPY~m zU$W03Reiuis2a*!xz<n4qt>>^BqYIYXz;1eZn<=I|2dlStvT_E@m_gOl{*zO<C&fd z8E{^zQO(xRE}ZSk#gV1Y7Qf-4W|Gs0@*Ob{pYF_kFl=f)1EbsecRv(v`rV|9(+;xs zH7>gH*I4|OfA`UPGh;f*oKv9TiY+tlJ?0)$RKkvWu_%?=7eq-^3CW26)qPlHvmI^o zR2AL&Q+PsduPSxQFuazrd@cIKf}Un!%Y{4Imb%MjbBP%v(~%&CXcsAxUP8PYv?7{s ztw!C4z?pKelSJ`fR9Pje=IKrrwqynPu;<t8J-EqP5w#;Z=d(E7wl!;1iN`EVf0N%q z)e$~tOLy53(A;zO((U7%M^d^Y8hy)fbTl#_GIfjX^}4PX1(#l=qz=QwXr(g5^JDhU zerbuq<H5Cge&*sg=+UN?-G-1#235aA6r^5M6t}ysf<-zDXkSXDNGSbG@x?4kWjvu7 z$ORd4&;;<sNks(C_VVq3J_hK;%c7j?=JDrFTKgMc^0yNh;^sHS$oJjy?_LaU5$*l0 zAvJf|!-f30p_MO45r!h^ogNwPT=G4G1N_Jdr&mqD2I2=3$Zr{$J<Lqnki9@N8#8*O zifgw+JXLho13Teulp-(Zw*qEwP<!M$>uaFA#NQc(NI9@c-hvX#o9i^#9N1k@A#1j0 zxz5@YVGY^L`@p{$JZraueECGE4Ff|c)2)kMYQj@8HN&ZIeq-eXcQ6uCw1JFMnAr@) z!zc>!R|@$hbAo?UP=5mveL5At0mkp?976p<oIb6lZ|&?e{Gu*Dxq?5vDCo8fcWb|~ zL+{#?yF-nXkwkJujV*%R@iI%Spcm4~ZjF`w*D8RNIncm{VhFhm`y38s9^I%m(s3DW zw*yVLQ$HsjSQP1<yK454TF^fsuTJ?4(|>{wKh2C^=`aubTxTQ;W?KCZ#ZjRLq(d01 zmojoqg{y>j1t;{?TJ}O~dm&j?D>SX*eJ?Ga_0^hK$U&0~F`aDI%Z}_9aVxXBO7C81 zkxF=Cps@&lmlc*77=stl409dg0sx<KkN16@$=Eg}5VG=!!haT?tH_1liM6vSJ8-V; z0zb;4mW0^BJvwrSjTX}u_M;CJ_Wuj-^WW#j|C}fSRX~@>3_w8nK0rXU|34<m|9vo4 z;|=YNGxGG4mEx*KHQ{zdl!!alfjbfF#6EkR{_oj7`gN2)9Fej<&=5nD#NPpO4h$}N zE+Q`ei(f`c5)_;aDHDh$SkR&X&GSn$zZs3(Ob&|U`(|b~cJ+QTW^yktPOPb^%Wn6h zm(6asJ7>pCj?WVfXq2kS*|iIRxpf&*wZRK&<>qdH+Lg5VymX+Wye(t%BLA0*^YSh* zuGZ{Im+pi11Apc9=>_Ww=!19V`lX&=UIo(S*&hIMC6Mzq4-0-pNQqxsxHg8+Fa+Th z%p=K$yRc#O_(5cNNWKz#e&z7)BWNbKcoSFg8i5!&vm}QsCg-*8fan!k$@hOz_KrcC zL|vC?+2&KWZQC}w%r4vPvTeJ|wr$(CtuEerXD06VP23wXF%kPj<jG(8W9^+gPwurA zS;36*9WJ^+;l2m;?fKr|w*7M>rgWLQG}~|d>xbIhg&T%acmIe&{AXh14>EKHr8^pG zy<%;>{QVWxkC2ER<vSi~UxlG>r8`LKFUg?_)lTuD3)PSC2oCSdnM(%#XYzL%bUTl= zjY~Z4I}YmW{C!>O?S-{>{AXY_fuem9>M!{r0p82p$9D$mFS(&VrLU_K{Du^z&r}Xx z36>?!t{Di^yZ#`mjMQk<I;yQMVo&|*VhiY7uvd>4cl|?;R_^&Scf|M+i1{iXVMPgh zfq2rz8e_`!XV<v>&J04sHvWwThsyCKG=a`!c{Kmpm3s-jJUX3z|NMqjsdQ2^li^(+ z>)n}M#<-}ov$;HvaCvGo`c+vM{^RGxT4mltxxDO%)#Q18k+QtRQK>oQ$Hq8XYG-#5 z!O=W4V`Y66(>9wU6Q`+B+3>gSsZ-NTL&j@kJmi=Am3Pxo><gU7#bGimz#ONY!-m*s zeBBe`n!adK&@R$Odv!jfX){<Go57;e+QxcAC!Dvj(IzM4v-!sap*qYa_TY+*&W7$z z3!=Jy?qu)t=}OLB17oYR)$0Pnq{TsmrevWTxy@Wu?^ctw{a}iY($2)t>*RQRIA%C{ z>c?99O1q^1&^ZE~>~LAcOvLkiMQ@cCQ(vl`RFPwA6|NsK&k)OD+i9+33`r3)kS3H@ zDe&UlP(iaDKHN*_<V4%OinfGirnqKK;m^{MP+j3tkQD>qKmS#5dQnecQB~JGb@w}l zs(h(85mrnFTsl{tqY`|qsfB&Y)~X-IGFgKchs-j)uDSYpS`$PZQ!iS*0sU?(qB)LJ zNiRix##3hHvI;NDXzi2@ZZW#5PMnp+#@NZ&Om|b2R4Z$Jei?1UR{9r%d^D9+sX_&d zDT&cQTt*MoGIrz$t#G$HPmQZ9yPh;(3^|TQI4CPmRb{?Ehr7e9^DvGqKW|+#xspph zeyw4{7@)`4hOcK}1??iDrIBseL2?gW(%goRW5Rj^I?{k5W{)fTN*fDpwJIcp{nt6` zJd=n?{Zt~|Rq}Bug>i|OR42Uo<nb9hufpZz;Q&Sr6SuK8j*_-bX1p=(WPyZJ5WM3# zQgWcQUd;N?8I&2ZsKN7dbRB|GyNm{m11+1YGa*7G9m6jAh<QO+fJYoFREqT~$_7Be z4ykpW!}{#P2n-#f;j&R``=~Cm!`KGL*y4E>y(3M?kXj4wxahKks4KoWU*VVJGxI<n zTana-4kU_|0Lk)t@$+<5H0w2zbK?;&WB}axIBpefRnB>~MNv2~!j`*n#nH>}CyB#9 zhE<H{$)qBuPV{oaW<1Eu3dLe2lw?>CPAV_)<Si%3*`G@m$ovBE{TBDUA)EHx98p6! z^OuDM)^b`a6{(7o!7<+OTbcM?=%x<~oxbv(LcO@{X6l|V23e;}cs?}TYy*|c@!tX^ zmkn>kcob(<b?naKmW5nwCok}b3|DbP`|Id5#b>wl^|hU*Eb^6r%3Xu1UrbE`h)t%> z4q91{4$JU>s7w||Ey*SlWxD<4ZkB4&FqIw=C%GcmjA}G8-rqe9--)zacPZ+L(w%%$ zLKTgJf5CjlB%$9}QDdQ>-?ODFZiI@%t1QDg7-C&m9f@^WF}XE2%;372s84s1OHM<6 zj7WH1qqZt#|1Qr+x}_Hud<!sbD1_(6+oqH)A3;~9a*J~0)}bQOd1YerFi}ofN7z_i z+D3C&qfEpynLeGh9XMryv^G)#s;;i^h(AWI7dn0oZp+|gX1L4NxUsS;0fI?pd09$K zz2HKnR64P0egQVn6da9>qKevr=DEWF?Vc_;@xK+rD>5D>(YSA0DoveO=q$9?+l{gv zKw9=#<neu|J{XpT*P@SjXZ)Fqv81C4dFFMo8|~JEDzv++<rvBVDk-k!i*b6i{v1V^ zvb*qSVkmk}Qropng-be455e`noA))DXn5-t{|RR?)RfuC%b00=TnaCWMLY1OA6u8$ zvE6W2z$Gn#I<8<{nA>bpl2Q|gXW<Te9M5-tCIAT3L%2Y08!I1NbrlPRE=4K%D#4ky zBVBs)m)eb@vy;f~BGrMbUE;?IJ$}}&ldCBU^IaBc`#H1oa-yj{BY&lxZMnHpFI0sE z$~#xQ?qM}2smg}Pg4t@DXaLh`)u|0mhP!g;2X;++CXP0T5`9Ah_>GH8<BxCHU-}4B zWfP*6v~+TZ@R|y*z+`s=r2RsE)A9b^$PP}dg00=O+DQdsA_aG;prd_Tg4BL)=H_PB zUoJDl&&}>68C0fI=i%Dfj!i67U8?cZ?nOKvA$DWriK?IoP8ldT%0LT(lRVKB;|VrW z4KEP)8fJg^ZU$G@S53)5!%g*#Q|b2jkF6c^?mb~-u{$b%y4_^0W{TI_&L^Z^-)-wm z@>Bzw^|85C#j=B`W1}P9^jsDV!hh2%OrzpBmeyC6tDDR6So+MD4MHmP-z$pbj=1Ot zO5s-y*W7#`sW>6O=M|JI*+vqFI5=F{G8LdURfkgCJ4_wZ)m@6+37J-jFc}uueuY<X zxxod*q)t5jgD5w04!(FyDIRvW#?nJ4(YD^zO1&bsrYT_ahQS>{Ok<ICSXc!{$)K`5 zduJ3rKJ8}O^(;lSFdLtrOnHzHp-WA#qJlRJ3^)2K*iig^TBMfe=HcZ=F-7yESqj~O zC8EJX$)nBlFwnB=O5J@Gnz?7?`-;DL5~`6uf~X&A_qvy<`q)n-unDrl1jwF@;&Sdd zkYS$^t=V2AQ`zu!N9wMj3H+2+g#NeYtX@H5*rOcfQ(Mzux2q}PCv7R+dP5FzEn0ZV zWAu4jz#Jr$BjUS&*dxrJjAB}<Po)-eKF-+g-dY`XOG6TVB+x&=$)1facHgyU#?jBG z`pyyZMn#)0|6PcP_1>D-K%jhwk8byG56c~4;C}ERI-zPy_bvgx4#oD$-0(QDxO>Xi zT>|S!V;sq-cp%Z&locAo|NZtYgxyz4D&TMt<x(bGSt*8oxV@J&iXs`N84K1F4n0{l zitJeLVSr%Qu)IrdsHgOm2mL#L-<X;|e;*9Jr1X^^y`+pY5Zt((dAcS_gZxxFUcXHE zcXGIOYPBj!)HtaC&baiL@T~K7uonPM!NQl^kH%pwG6(j9c6|KPnil<F6-?lreA5<n zBI;0ycDZlgx7n}iv4P8)9-YR;v|c~GK=!G@X%$U?7bNy=jXXr2p68dgxz0E%ab0wT zyugMnh68moQz_R*9rNa19V2p$A>+}XJVQCP?}@Hu)|53jga?`hB~{iKE$Znz8WwxM zyf@pWWbPhjm9m$Hi&gpg^Gsh?SPN>NwT}EXt~RC$uCZA7LyH95bhfy7;Q^F0a(nXY zT&S~(L79&Ix~e3!zlTS|&oMF%;CqcAZsz+J0ftmuhYHlebiZfx8l8vEVJ}XW=sId` z*XrAs0MhB<)>$<=nHEA=XyG;|6oJ<^*=SA2&ws$e<cWp?b3%YaVK8-SQ`>3{?=E3e zXY{mMDs6`nOwHNM-WSI$B!ELe_o=F43)@9$)A;}jEoqiz_TI-oV?KynL&MEW1T(8D zQJ8rj9iS?};|)B`Gmh3Rz*~e5eZMW!G8Mboaw$sGU6Op6{yg5;9tf1F83a(OGS1%t zSAv>-``qiA&;>uG(Cd|qtefa;t_N*pr~dAB$2UzJg=Yj9wWvz?pp|qAr!`a*^4P-v z;tFK9J=7b)w9^mI$zO=Fw8&OM6!Gs{+6^&U1zzcG$`c~;#;P7zz5o{Vujw^t1-4BZ z;n-^e*c)ug<%8P|gav;4CVpS{TQSl1-K+Cvgk5nO`{9q#bAgS6e)Q}9NHt;Rf%9yF zv=~m==|OZDB7UKSZ-9r>xs&N;Vse31?_TAZrY?#G#FiljW{$RTws|YoU5Zw>_kudy z_L0TGZg8G?Ke!5ISbDVuz1QXdU&85Cp4vmAer{8}eS#zu<47p=%pJsq6W{825elGO zfwOg(@Cg)y+NcGj_EDnQtGW>~tQh>^$p;&Y4q{k)#UlHM1^$lAm6&U-IK2x$7>nQr zJl?x&+bU738s0NljO_vS7>FVh&9QAgpp?w%3+XvHbpnO^B>8Aai_(%=-Wt7=w5yQ% zai%k{_|O%T<(|ORHWHtBBP~yllm!>T5AO>$vkFeFEotq+sZAc$21VG5sK^7UB!{?v zhiG#NpKuAkA7a*j0uqA#*L>Aq;l`hoKbHI61E`z9_6v5Nq(KXN6ZDH@R~wHP?8{h) zxQW0!es^H^%AeZTn<GggpewE}0-+ev>fe}R6VEQfO(?GQV20I^JjVssgTLIcWfI)( zucSw=N<Kv3SFWHvOhynrKgv!h<GoZye7yiE0OyQfsv-UteaMb|cST%F8Rh4v`J`=U zJ)o`~;RpwjNc56BuggY;Oj-sxDQK>PrCwenjOm#P8z&HwRL>Y(54+Br6{}WY4QPSX z08zTPS~R6}LrKW@eTy;37gH?2l7)ckh@QK+-wQCJ0s`su+6@cQ37LM&kJbwr)+f=~ zfznBis_h$QOX0E0OK2)Q72A6*a$CD=%9BtuQJ9r1$zZYtPo}C5$OoNPa5nIj&nwLp zM#u^x%nF#Z7hl&$XqVa#^$UaX1;Z??yGv=P7dUon6wql7&oqn3{27Sf5R{lXaK($0 z%@BpL5oNZn%zNy{a{e}img>jqnB`971HuU|teu?0GESqHv__I=LfeGzCIt2<u`x%= z=qm>cO*etJMxh6gi}=Yk!SBSW8bQTKlC=xndDVUaJ|rJk!qG+xB2->5wbCzHS9ve% zfW375*t-?6k(J}SFe3HJT+w2P6rR5bQZc%M*H3*L{w#{*egz7>c)k#gUXS!y9vZ+q z)*?i#fwQ;CkV29nI0^tOMEGv}WGu{*02CKw*;`tBT&DFR^SXJ$T>VsD!|&TVy0{7Y z0F-6Ri!Rm2oXCgC*tUN#g->_We~7tz@Sx*AV<W&sy5e~F(5%bhVafYr%T%^-Ux-_1 zqTtZlP;t=;r+_-(xL$c3?YT_qXb59<!GkX?0n@IMElX}l0%WXAFgeEvlcDSmSv<AE zqx;_NT)E~q6!Exv?{FWgwQnAK4$`Bn#RuL-qOl>*f%wuu=#Ii?H0Bo^gnu}Q`)Uee zY@2_D>q^WxCaF3Djd0n$zqTsM?^n@Jk2(d!OT_b`Sc~Vj5eKQGGW#If!QDZVI&+xJ zD%oxm0ZgzR#CoGCNlL;Q3(x`~4ZQlMo`oPfew2QFDNWr5C|wbwjQQ*lI#wV~;l>`} zpikj|DVHRXFl#=eW-!U~uHkYiP-}efPw;{d4Fr(ezu|L73lszmFlnRs5&VacEgfn~ zq^bklf5;#$Mt{pN?=>_!l6{aODu)mJy!hJE2I=_Ba&G)9;`I9H(}EshFf<;84VyCc zQ6!0R>|ccEsB!Y~(@YDOdR_(?-5nbDk)fysovIxn&G|U5)}gXI66oRB$g&o&S-}lL zXOR#N41B;GR|`++@dK$YB^V>|f=w?SG)Hp$#Ggs6e+z`r4<2Jbqiv4ngk-L<)MkF7 z;Tz2K7hZC?XMMu?PWmDUnDzK!u0`rFT-dWu_;Y7X>G$GO?00?<OLQZTJE;GG-e5PD ze5Kib2FmeCZ{dqzY4^Z87d(IDxP|%1z}c74Y=NsoYE&7mN9f@LMolg&G3Z3-G0xp( zz4f|Q1$+>EeG9#PFZF*T7T?}+%F`eUhY7EY3V~>hSk~isp@-gEnP1e9aNDgGhxGZJ zbmCfn6kh(0KP68!8aUv5a=6doKb%V6(<S}J2V8>UoNaa&!CQNy>!B9$h#qQ2+_gfE zsJ#+usov4wO3W5Tco~ig!3@j1Ih!K9qH@OY4^_(xvGc%-!Em;Um3PGm#W;_PW88eg z&%MWr-q2ijvCQ#Y1m`>JP{+u483OPSF-Hcx3<rf4zWzA~F+_>l67=1{`Mlx<A|Rnf z%_Ye)CRvZFJI3wsQYu08nUfI=Q-d>#Q3YU)8<;B!vva9Sa;f*`GI^Tz>z0XQd^sp> zCp|=FW@>h$iPfUOya@kF$VsAPR*9L6+RGN3<S{k-SHM!vM}{lUkI13x(_}vM{gN*p zCh7trp(8JccomF%NMl8^heU94+F=n!B2oBH5uvK3A0x3Xp0i&tJz!E!?AVe}B^{wn znhuTfq!-B)LNtl{NBMzl0i1I@CUUe@t6rZjML%5;;!hKg#{sD*!0dyr?=`fai(P8C zEs)}xE)}0B6@MEZEC1Hh%PXnn1{~kJU}GTIpUN1DfprBkC2fzCY2;uO=tu|62`i!v z1Y}$q%?@3a@??P26kb+kSvb2M;g|-q_uu%5L14X}Je*5wzX1KFR3ciNRG2KAjIkVh zw1*&zw|EG0ANpm*ZF8J&PS{Xqy!k&vN=$JpSo7qn=3k36UJv~|1sn_?@PXdJ#&0=! zZ&{2Xe_f4BSHTnSO6)!Ly-tIfUiHJjjk$gsW^AAq&xw#!U=FAA(^&}WM!f2Vyz0h) zp2G~@N&_l&!2gafG5%TuW=Xa(Xm+HdRqrO8A_GFlMFro|O=rb@Pl(WAN1bb)NITvO z=(2+uCSH{c_p?d>vx>P7N2D8p0^b~SJrHq{Y;>&H!zdI7v1}E9AzE-<tOXZc1tU%b z?SpK<i_n5A75v97d<P%2uMIWSLZsh@?lVD;OV^RFwHD}W$}rg%?hQR%Fg2b%TXq?0 zdqm%=#kBI&M5)F<ZA)O^kP+B`B_uMij}1M=27+Dw3&J&es+U=4WG;DTc3fUCIrZRq zPjK7t<7f2)ZSN6|zX6TEi98}8=DWEAx<IE<$BB|&7(GKJX8L)&S!>;1-~T)z9H_X5 z-dT8rLW8=89#9^$P#!m!ug&DU&lI}7a(RYg&hm7IZSSR?;^_(B+|oQE)MN#_y`ENf zf=YeI`Y)=p#jTSg<TVTA^V;R{{t;^G3b%ZxDZipiy0B5*;3;i(n-RA8#?`d>eyg#p zkj`%|Z(L+|0BSN+Eih0m$P#YK4k4lx36AU|O@%FP+f+PJHtd!Oe9+~#w#PEdZ~l|h zwEjg`)T3W&6QOJKtEjoY+Y&WA!6Y}cl52&qlO8Cf0*G1n$CZdW0A$4gjV`PpSh3M4 z^H{p*xLA^@I1k{}dR*|ys$pn(E%2@8^oxo$H96(DT*YcSm?$1rgm?u2)k>|@=|K4- zg<k{1#(~VH5uK44l#v;gk@+Lkx8by$@vbTPt()Ig9&{YT4d2qBv~HdB8$p@{@uM1I z)OAXt3`20W329s>(xB5S+(uazu7#RPC|Q!?6)!|Py{u7Tu<;aAx?{bXl?08?lLIZ$ zGDh(1T!fLz&5=P?h=QpJvv{p|*f({FRG0j+IaXTE=Q*4Boyr+c*dAEep6IY`c>u5i zk#@cgMWf54d9@CP+0HJ~P=U2yjnO*q60dq1%qU9zXbC;C1cFfh3#N-(Du38uXO}r< z654+fEdIfRxD{6Y;ix)C^BU#A>Q$MYr<=L$Z-c&!TTjaBIKKI@DqoB$$5TgPoxY4! zPYQjgZ^FYywQbNd%BZ7FV1D%#W1kDvq^mB3l}@V2qzkyUlP>g1TXn!zb;aI$HJ<&X zOO=h>LlD>#^edWtg#85QDf^0dL}3sRFIl3?vxy?<p(_e&>wL=VVTI0$hLFn^99DIW zP~AleS~#IJ$~vmhVofq>7X5OtIH^0J_$4+{*UK6NE1}dML>Kb-l#@;>ov9fa%MoCS zC+R~$R)zy!#`4*U?FyK7Aar3wr;?^Yr5b*7U^{1=v?qKrmsSo!Gp26~P_PfaZmq`r zO`gb|6Oh!#NTJLpU&IQj%<z}cl-@Tisi{_*K4qX=GHGNIVNkE7%Eu=mO`*ET+p*|< zP;$o~kFzS<Gk@Fv>)ouwRk)mhn~1UB|1>-a%9|AFH59eX@KdU-DXHj-O7e38Yw{Pu zAjDs=hg_=OB80E&%|7c;1Zfr5+c_Y-j}7Rke1yZ1A~54vpaX&F&Y!1NPfS?h1HFB# zL#=Vb8=aBqtKbqtE>p<z$UYIg>_qF-ddOy}p?KpN*E6>#+)117$VThTaU^Ej@mIBi zQ7$H-P)4}!z{KE;TW7C*7yq9d?zr~f1~1V?xSMVaw2p)>2ff#sZCU@>xDvWt_+5KJ zI<YKy^ZF&$^e18;&6OBBKc4CV@O4#v8<)v)oKI3AHxEk6<B8F;->JV^-|_gj+EL3i z-4FrSUPPB)^l&3PVefvA-iEX3KOEKl0mm^3u7$Y=rek0li6}bWzvldt!^tW!)18lu z9dZ98S>c$mn6rt}zSzGK`eH<jL&XUE$>1=O1wdr5n3F@3ov>(QRFOvHFZn@iUkZ_& z3H<Y~N8*kO6SfG=X;Ih6tR<vfCF*HYwnB9+$B-}IPWR#!%-SeO8$7bsgaX!Ng0}}o zFLz6KnM3OvPLvDM+`U(ZNn#B)XNY120^wdBMo(bbO+&~u3^5G;`Lq_KfW)=gx^)|r zAk|PC1qNT?qIeOK6Y;1O-HzW6)LJ``o?|Oawo2X26~5=k0WGSF6_^7lzx-(m4)}0L zc~@KfyofvdLOtx*@k4pZH7t5(Pz-+xziu&6)deG}t0F=buOpoH1G^)onj~EycBcz6 zn>q?1u*cIa8qmE&RfUH}#z^}@_#+jDjb;RMveOt)c1_$O*vcxb23)t~c?_>op2O19 zAY?0jZx{4ooOFyj>X0kADiEx6oya)t15;csD{a)v+4lz_>X@2Pq%uBXF>SctN(ZHy z&?&Odyqd73b(}d*Hh~%PuPDwN7^X(?d_-HPNKhvtbRa?KeN5fqkx|MjoK$1B#{$Yd zB0JH)LLD~PO-lrTCH-N!2a-BupClVlvSoZ01YD!7jL<=m=7Fr$K~s>X?_5GH4?i{> z+A&xZQbJN5sfcM5hukH{EQ!)G>_j4ND)+X>0Lo3G_pYKkHIyzLAyt1<UxaR6>Wd#w zd+WZ1a|F87KO_F4MJFN=T?npoM@mJF_1|5@YjVgq<VFp|>{;4|5D~4pfrg&ssdf<K zt|*v}_L!Ix8C~jOLOH>km76r=OgxAmZISCR?d|CQ%v-|K$=+v#nPUBY4p7H=gdb-k zFcalrrtm+0Bc6Ja<QG-TI@AnSR|i<TKps}CtP9Txujvv+ctu5OhwZO7%bHYlp2QcN zz>3YRnR{d9cM<d6Fl^%AmbQo#x6dqVH(%0epT=1hnur4rO&(?^hfgm@On>ArQsRq~ z_=0twBWp|euEp!;NjCB0%|VWfPefC;gj>s)+H)j5m^#PR(Caqs?fQO+E_IK>Rc)S0 z-~aK}$n(VY@PMda%q5<j>8JdtQp`<VPA2)lchIEbszlRnsU0RpaSsfUN8stx)lEu{ zB<<I_3>jXRgBsP~%q2#2#$Cbhve!dAeGE$C-Eo+8nkkWHC|$A?gx`V|6SMuWfhk=k zdDa7LfvN}tH<f8Qsa*i`<?Ycj<StxX4A8ipQ=V;z*=p=p`!(|~vG9C>34en2-%14S zsZlEF2O^(eFlzaL4wwH4v3z2vRs5u(RoMw}Ip3HK=(#%I*~Nb1YZYQ6Kw}Vr)*#LU zOOBB+{sq3ws%k?+;M<5}i#H<@ztAHE;*qE+Y7`xfY<Mn*tL)T^06eqn$z`A*OvM9^ zAA*FL4fNOq0oh)!Un?8w8<DC(;Z>qS6>y{w%<Yo^o4Xq@Cxb4WNE7EZfA~~7#_+dl z42YWauxN-sq90YcLQL7~{4L06N483ADz>5@ZgieGUvwe>S&Kbt+0n2v1#)SfFs<Zh zz^Dp{zXV;lLH&n(^&(9NroSBV7Xyb$n5n6CwRq@v+0esZjGEL}U4|z2uE876Obn5{ zmpLOQ%epv2StMpPPFEoGYANM>^)G=^dt4j_?p0cln|{Z28)Q~Dp-MggbjpJqj8!6U zGCMkOHbnZmvl%4qOC`D^)LZMIgLS~^<M*I^k?A4AO0r4{`n#^`7we*7i=~Y_gKW$# zE2Tn$78P^1Da&Z$j$St^^i2Nzgs!1)z_63@xN0V1c{3244N-k3z_E!;F^?`d&y^l- zAw@`38{x#9#-O<wCB^b&BF-G3T1$<;iQbD=t&iCPAv0;JJZZX#fL5m=HTHpa-dcnj zTr@L}K>oqElCT)UL@(W%S6oCD%<5JIp>iBTvOCmmOnFL<=FD<vK^OO<q|&!8W`0}6 zsJ0OS(%gqqHSnA2MA~pVxj$=SWfW$5e?b&Pw`lZ19>j+T@~9kx<WJ}9t}kR;e@7ow zDur1e!)YcsVyj!A0Iq#a32Z27$%NENIL(W2v=5>>2${8HFB*m%hP=@q4dr5u4jBJ- zZ2xtCL0wow8w%OwZYZZlhCYZZ?$t_NMBR0bUG6K0*J4+a&3vDw<{vXcu>TQ2@K)9d zwMn1e+|JtJkG#hA;`ZDlcJ;k>(EAb^_y@1SZ)OW}z%H3p3wQFvqPE!@Jg90cnfOJU z&zACG0>*Z-<Heb(d<d!>WRh&;<yGO98aoKQQoGY5gz$}9P}lfiFRp;1D>01@#PUWS z`>-wOhdCdHh3f#=CNG1?XS`PF3;&BIFXY1;;?bSJ_r~|#&~@O~c-Nk(2HZqHf}c1j z!yt<{>A6*D_3KUcpM3(^9K+o#()Az*yC#JaE>?w3R6;?Hf2Ndn0jqBsvFH7S8gDA( z^uTR!;QHnGpTKJ49d^n;SWWW9S~dtX+gl-jzdunn(WEQayIztjS0Ph#iV!R(<0aaO zJ+GMwIFAlEZ~W>+IBEOmtGe@gqiQh#U!t{;yTY7Pd?WD`*pMd;iyEx=fv&m{lt@Re z7D7wrB_cO(%AT)<%J7`VvL@vWR5A;k)$Aemer;tHX<4^fpheqBT*x6Jwv!4Q4s-P* zwBm>!`hMMhT!y^``!lqidmT#42YUZRt9|qA@kqrLtHl$;V$Gj^!!k{g$}2*@>Kn;A zDmCRKM*-LQzK0tlp>~T<3b%Bvnr1$YG4(#(xdU3Q*a}UtW=|=YIap_%5u@>(#g)>@ zBSjFUM+O!6h~$VDlJChR`b5Mi&JYa!#+X)&7>eaSh3k{#oc0gN&?V~xI>2kaj6X6| z1?C6z+aAOxQuRlE5d)bwh4h@jToiuGwk&_sR!ESUW0<Lqk*I#FlcF)ZbsSJ9MBZ86 z--{E38bwJkkqc_p1fcNZmnkHOm-O0?>7|?0Ob+K@>I~|w9$JOSf^O2m8RA0pv`<8N z{|o8Mk1wsj<kyH?F!CkEMW{lI*A*RD{7p7)?X~cf9+$r&62lJ*^R$LEf6@!(L$7-N z@b@p8k*1@lEL(F>i2HP+KQXCmfSKQhO6=a>*dMP8T&c(dZLpET1TK0>`%4A;EVx6M zLnpF(5B&Q!n18$k|8%Slm_+VZzxnFnisE<YfH3dfQA7-cla^q=&M6Csk%^UtcgPey z_xefy<lEI9;W3*CU|C~iPA$-|s3bb^#BJ~sas}(5U>@rA@hIvtriR+J;_K>HfiK?j z1F)dYmrabhNqAFlC4jFCwR$dtt=lH^N7*b?y1vLBk@dx$YebxDMwFh>OXux^sNUo_ z`zJYokJGng$WNqmnKV2r+pKeD`*fCjF=<sZXE15`OZSATQ{0X7B9z^&fwd`3I)y|% z27;U_kV2G&A~`wO3tB1&N9y>weihz`3A7-Byy2ZvT{i|R4v_ZzuUI9{$%GLkKbg1b zqDWFx7}ue7l5j?bR>6R~3f!w+uRVitPau)4?zOt6VoJpQb8Xi75?KBXq<bqwIZq(S za0~hff+%ya<dAJc#$~MsRLIT(uQH4=N(%V`$xXxh*{3|VXWM6(#EDDB1t){R0v38$ z9yYe}?h!x{H%1XZMnIA%AVi)UVCc@P^<5S{r#xn^%8Z>HCH~HW&5ET<yAaa|C_Ev9 zy|nc^uC+KS$lp}uaD!=d-GL{I_mj@#8#pR{E_9b9!pOO%3A31FD6DV?kN&s9DEbW_ zHU9_p=<UX!{L9OH_M6hp8lmrOU#I#}$$ba8u3V3BNUJv`+<ODWmON>)(sbgeC=C+Z zjl@?RVJ7eCQL!3DX1*k-h;1w(1$J$-ks51W!Ww-gtx*n=OznNWt*o#`=|}XZu_r%f zJJ{%x5ADha?TUm-oooHRO(%``@FZ+C+<2x&+h|F$j@rh^)PJ1M9a*GJewT>KE*Qze zAIfE}EV<-99{+b_*&7dAdHN@cIu$gJyNtr~FI2r=b(sDwVQ7EJG<A<Q6U`${GIyNB z?U#orkO39)_`ysQ3g9&<L1$sJTohxXUcQLTT)tRig=+0uKYpb`HWp`z++*K<FPtvm zd5No!qxmw=)^*fdu+4WvA;B$hrvfq0-hs7kMH{fFE=F>cJlLow;6mQKe4jjAaTP)B z*y6)J0yk6?LH(L5)tSr3UBW-3zXes8kici0Z#^uD23SA?a<~EK>Cnb}PmEhEu)jTj z4=~T*YM!LSGR^R=?pyd(xpz-Ago)Hc2d5zzw?%T;&+GT=`iB}@_bt*Ho~JOnG^l|T z+q!o9m1*~)1+i^vvav3q-!fNQyVwQ+&-%#Ln3eQRI5%hbz&ywb)QfkkJV26)a+fED zDT~=u5m92cS+*e?R!WVX?%&(1HEGFT7h0NfQRU)3$-kuMu-K87u=7?3zGTIQ)MC{0 zT@dcJ0fl(+Ll*L35-VTiW5>?iS;vVpV^`VIar2=E7BM%+$Z&&6uYwEDbNkD&M;YfH zpeh1|o=$kf_r%V8(jUMzmpyj#g-7iA1fT&r6eHepZm%xh!YrYsL5}nM*2vtTSH6hY zj*=m_<O<^R^KK$r8mA`1TQJ$H_hBJ5(#k(CO=t>cLnxgEi%*P3ADoF%bQRCTMbb}D z(hk=`*qx{*pLHN)cvA-)XV7bhosw-F>f}eWp(8y`f5dLsq1r$JXq7EoxKo_bz$DPQ zJd~mM%&hhB!jHL7b0r0cYPyh<amYmW1iN#uTZ>^xL8A5SI%58|3;dSHik(ODo!i4I z&N(=Y!d=L^FB%Snn{dB!YJ_4=E));{K_G<L<@@c3v+ckf)bX!1Xv3h1t2F)YE}P#h ziFlodOm2Q<#$naD@<?|;5yLWBzY?dKv)aGA+XN<M9^i076q1zRSGoriX6HEA?=nP< zJ;~(dqulPI+<sB)d{^uQrQH6c+(uOFg!~Dj^M6FLPrP7knz>h8q=A2tPk-HDs#_sG z&>~v}h5cphFYdyX(c}j|&J_&p)kKYiw&)>CQ9ym~2D6l2e*vGB^+mI0)+ZSTVoYKE z=aD10mLt0JgxWY%lDF!F8{(1U&y-_k^UyCk_D>Y+Rt^m~*PV`xB$K>J&bnc@PMufj zNsELeh4-%08g{|v7fAQINtQZ`CIec=gQh=}VQg>l((mC=u#GI<z0UB$%Nq7;SkgO? zF(3ckoH~rL`y(UcOTgQk#PvVOA+OcI%IjA&>Cdr{ywj}|+}jVxyAJ@@E7;W`SdzQ^ z`XDX|7nbq6JP3WM%Q}3Wm}9+&J@cM57Za)>!X=>9mGzV@jdql|K7Vkusg6aco~6$} zJCgM49sKKYzV5udZ|Uz-3^&urJ3>_t?EPOoS=UQA2oWFmgJQEN;qCERB{9O4FyY=( zKcZm(z%HtZYUZoIE?FRhXgd{!0n>_~Ea;=TzA9j+CL;8fEQN(5+u4>Yc5RO8*6^$P z3J20#$WRt^sZ=PdSfpDCHdvE^{oLBY)BjODM%(pQW|kjwuL}&O!l`$IoW>Hh?vfD` zWBsJNOUuIxMilt;%)ZTzy%6eHS|8_?tHk<LnR$)W-Om^^%iHX=0j9`3MmXWTt<>9S z5VFjj9Hte44&((|P!3Xu33=%At-%x?bE2SIKzUrEE5k7XE0YU5RBCY%E8Q-C@5@_f z6=~5P13Cb2myKQ=_B=>P95*7$7GS6Yf<DX+h<vg<U_Ofy**BzL3*p=GQmt$xkJJqo zV+^`b<~E*zJ4Sz-WO-WaYk%A8e@c&<z*N~avO%~ua6q18C(%cH^&#?y9d7OhV?UN2 z@qz4e3Dso_mV`IVIueHLH%egvKGc`L4awZRs8~{L!k7g)_bokCFc{#x69eVm);%0{ z_3>Ha_YB>dA?WW$o<+D^ti2C_KQv{88hV8Y_>jZJ*y%TPpb3iBRkYj;A-wT-82&k| zTZLSR;xTBiBRG%lFo<_RtYq#6y@<wdU2VnO*X)^WMXc_9wu-))IH|W{EWS9NF-<Li zZO<L4d=w*vEoK<CnbAiohZbpYPtibRX-n9wg+e#$#*sY7mUiHLIKXy9QelD^Kf2qI z%94y!bcy)eErYwXl2zGFLgo6USyqP7EEh6;?3LD_Toy~+RO~6-2qK||CiYJpDyo`& z_l-CYf3<Ah6#?gs*ONU*<nd3)sX*-MH^|%{;1DbZ;kG-OG^5V{<f_F_V|o&A<OK;| z|106-mm@lpj1iY~QDG>NCBp=w!QtMe7*x(MWmYe2TAEF2wE;w$KFwXGQ%6S`W-}@1 zOFKO020h>mv03JieeUftDwwKoV(}T^`9}_9+z7&CUJSkvbY%CP4@aI?!mtz8W7td4 zpflEXS0qc8KVWWnhbZF7VYsJ=1d&)fg``EnKLsa^@Rq5i&w`63O<c$<1zbc!08oGd zhe_7AYf5EM8}jYS^<ftAcclq|F^}ks98JCXz?*;nCg88nXI}~^5&xwJib<AC+FG2s z;Lro|m#?y5vT;t-mCLmz@)V|LFJpE%{4&?+XKyCB$F?<;rxW4jRG{(=A>aVM7tD@- z(GzmO+YTwkOQd!TCj_Ii#Y-j+bwl6=4?@EubO7N-(jp@=FA32d{dXj=LPn1|h*K5r z?FtN8l5ip5wkU?tB#)byGfU=H-&mbFDx}HCas+!d9EjBtBCl$!y-XU}Ps`Y=19zh) zypGRJa4XFTGoOH&#ae7G!tZ>)48qEtWY&%h(e8$J(2aec2l6gE^p(Ar^2WRLk=_sc zMwk=wqM=KMGz7WMa{nTGFhLmMrVXVH*;}#0J}os&CjzjIJFu{OQmsT=OmCVBZ9y@6 zz_dGUcX2*SWG)l2+2yd|##-sK8Re6syPYe@gM2DUZXZbEPqUi*39Taw#+?Ygc_6t< zExy4}bz)w$?EVOSx(@ztZX{m@V!8|I#^2?bgB9i!6}y>btHLvH`XdV>8{3x01v&@Y z!uMC8Jo>7<&45a``62RZwci!2Pq8Zj1Reuc)ZLrnjbYlU4_MP1CG8WwzuNZ5F7b`h z={>(K%TVj0Mb?k5n%_s~u))W|)sBwgN_}>}S6tOXVNi1XsT*ZKS$Dx}k3yyQR^;i_ z`jGlp$figV3da&PxaQ*`N#0f9rk^K(9^PCt44rBHf@W;O@Ma^=b4RFbJ6Pw&i*fWF z7|lZ<$mm7_>FEn^*y9^GvGY3!eEUxyv9<Q~rzZae0Fvk#JZCi>?B8XiX5m@6uxCKB z@^kW~%tu!eaVfHc3zMvoeu~mB`qK8?n^Ao^b>4Z_{R>*bU6**|G!h^tR8TWu*e-2F zvAmxnYi(u_{-Ub^bbkfVT!m1$T;O1S2Ds;chG7h#A@9tFSq!k2-fN1HPrtf(u>w;> z@{?R+ej?5lDhg#DK|&!tjvbLzw<$c+INYlX$t`*HOxxU-nq0%1`nX<qS_WtbDYI{l z;1|Wuj~f|3?{2Wyh>!72I$}H4s5tG@4BLM3L?_$lI7KH`ohD!I+;jmrGP)}7LgZQ~ z5R70QeJ-#&w^D|?^i)~2*^KzAP#J3K57V#q*cfrAz$?R2M{MS{6K<iMsv-uL2~GJU ze4>&a?zWouTe+6DSllyyTO)n&i%54{-|AZ^IDMP>*Ul|e(uGW`LJi8Zt;z1?+#iOM zTiezd>4NsL<PApXjL~yH`WT14LC4zLW^QJ8Il?likdubwB9)hD=4<CdB0t{m1#<n? zcY2VP8uY1dc#v*a*7wM{OCG~U23zgc4SdtFN*Puvv%?wD>24~4zIJ)pwSV_C?rs~L zvaf30F9U95uRa<?pgh*a*56u+^KLiw7rScDbW8$K=mTO0UTuj2wC$rIc~75GXRch? zcCg$BLkDiL|EM>TL6z<~mD`&LB$VE|RXuU*v{&gN7g{X|nNuuU2Vs$0>b5@I5UZQa z7u)^%KeGi19E@(oKK?$ArviNu{6}W#zf&syi)`^9tMF}wLqY8yDY7;&ARwXtBiX{) z(a_e(+R)jQLCDO^(bVkcO7(x;vipC1!etatmC(Ly&A1m*K+r3jHN^yF2zp8VqVv}! z6%)zTFvN6P+q1VD1FvMW<>hoUUMV))9R`L6H8hb{z97FtX&yJJk_-r$&Wx_JUj9vU zoJ`LY28sYxXvPSR=zu+F&LSg-4A5D$RgqK~#~V&MwQbor%s6zwWin95Y%scqX380+ z$#-0>>J|=N4QK3ycbjF2!WvhMZI!z(p*B;whOkAzt@BMZccKgoOpY$qcfg&es9?e+ zqEBEbcwJ@KySZ11rIbY&-!Id<(UlS4sMT1^5x#tPJp3-)i-3?a3xPre1*9-1^L=H! zpPBh#On`<S0cLb3P=i_~k(kRgYUs}4q83M~`rr`7OE}EevU5h_TA`8%lreoEhT{F} z{s=KgY4F*0d-wB<6p7(K$<5u-3Kx=ycrKl_6}wwYnf<u*sGE#Y5|5sbip7s8qY(ua zwgyp!>_cs`B#9S>8NQip-#^>a6O)jnTI}`jXI4+_@IF*x*eJ|ebFoL~<iqoudUP~X z$kwFsjf8NuYjW#yu1iaSNdb3~`3{ewkW~qL`fb;3a@6X4@qh^AdHcVO#p0GYfxu)( zD#rJb))#?lKyVd}0O=<*S=5lu9400sQi?p&9P*27DJGs95|yGgwqhXq_IfKvTUFqA zD$kUp^bl)84T;?34~e|rus+|-Fqq~tqxXEn$r1hmP*oB|ySx><)e66HU%zQeA1bJP zTj&(Ch<zReDNO4C_GxyhQG(>9r6OQo=i#cAViygDNn}qI0hyoCgw=_1e_wGPC*Nc@ zKVbiZ<o}M>|3dPAh=>!oN^<YOKtRbqWW@g)B#YRYm@3*?*gF4zkgPmriz<ZVWBTI0 zU)M0Qi_`#yQaiwmBH0F@RRl{QYmkfy7_3^b9RhuxWV9vu1Mb%C2a8GX$9W6<ff{yx zM+_SlG$^T}ru(Vq(slmz^>D!f)S~pXyBiQ1*?K5surXwcsR7m2Ap}T+AkwbFLmm`b zoC`WqM>?k%_^OjfIC6+(v8s|B+m4q7>Bu1sK7#=5?@~|7dSy;2ukb;CdROAS^<w62 zJHX*%?v^s)Je4Z+(f<5}7IbW%5Rt%5BmjzJtE$a#gp)r18CWg5{`RC8D!r0<5KVZW zOW{8!)wN8@DFi@-&-ccr33h%A6NH-)$LPHGBC{28Fsr+Ys?BTtHq>`ZdkCmqWmoR< zq&)~XzuA*KTLpu2tP@!+{aV9X=yYY3P4Y$4l>f)jZ}&?XnX8rFHL^9r>W3W{srVgh zfr9-#nS-<7?f+DkcD#^2Z{f<WU#3ZspI1!ByW6KG-_xO`V*SwIWY9x9I{v$(mnN65 z&h42$kl!&*D946gPJOqIE(Vy=9<1^{Ed^jYX4j?}^SS&qj%o5dq$joc5p>zD;<(+1 zenV7GFpp|8M)ur`klPuFj^9eR1z4c?YtuOCl_XxFd0=ea7z2OYZY`6A8b!GaH|;26 zx;;bk0GcWK0-f23CM!TOsz-jz{Gp-ja`FfGKS=xUc>3RwX2x``pZilY-N1o>1phB; zrnI4}p_;9Q@ekm{oQw_ae^e8Utqq-={;KFIpbDY!4K!ai)8++(H0SvdpwZHTi-M~X z&uOX*1;v6rnyw>UWw^Gi$@_DBqjUqs4-)LgqTF1vi{&$kKO3HGcbw#S9Zz1y=I(TZ zrVTVu3a8D+&v$3#=3b<!{!>NcJAXp5z*|rPq%j$kxv2Y0mzv9u@QS3JZ29!v5+`R* zw&{)Sv*}U7R_v-*RI9X5Z&FQZE8|Mbcy5+yw4yC*ch9uocI;vdRe1WZ{HM@q6(;3# znDOlU6lP#<lh0_BqD-`b>#ZH<RNen(D#);^zLJDUA;a@fazF$;cE&*pbHY`WUAmB^ zR}payZEZ>Kto~)Tu*a#l#T<IW7deTzTD|82XLWUR%zP%9aLqP6@<dsspGv+?*_@z- zPz!0je`Cq_!M76eY*rz*cI(>nunlkJx8E>6eQg~^+Oo&d6Y6YEwhGiRo1`R0m4aj1 z>?EAxR!#zor~T~lMjZgm)fwy~V_3YJjxpf4{sr{nC$1~Nqbl4k4x$Xp(HaLE-sy*a zbEW0q7%gk1dvy}3sijtrpQ`qo<U2~plog&IHf7jHz%7(jbn7*>mu2FvjPJ+w#o6Ba z=L;+yn=p!h%OWl=ghP2cfF81$Hk{^#m22&zU4|7P40<P(Z;KFgO#%7)4q8MT<Sk`e zxL$;(Ef@1WXm@N|5)3Lfe1i7}LAFmLtxJ)LP(bMyYd%pyfB<a&p;1dKimvGEW;~l{ z;nY9%Brv&XWSC@{XoRU7Q*-e;229t`6_@TzSqOOK+EDlIv0uMhL)?vgT0pGfzRW>f zd7xnvjWBL!?J8E!Wyt3U|8avbJ^_o@d<5uP*zBQ^g9~9;{vJ8yZ!ap4)^_zqF9g<* z5nFf5q{kw+PmNK+Tkz?5?_>B+GW>VQ|5q~nr-4||@1An~NrvQ~WRUs4NCtTq8&gLM zV=-H23ug~CThsrU5Tpu<s!|H_|BK40YNN2Ah~`Uwv0RnZ!lb0<EwTuoG@h9eg#?w( z-N0z<Z?d=WS4UjREz(BfQGZNw(45u#SpsW@js?sAb*O2Ki|d8=CF_K%tEI>H&pWgM zJ_F0FA|qoo79I(A4)*CtC9^s<C<GZ@uzSjI?Y)!5VN&i&T`wbAL`cWASGP9<KkJs@ zB~wxP4g16rJVXQSU#Mk1{19Rjcip?d_MzBTCqmj0J63NjE&S9ca2gZ>5*nCRI6i!6 ztHL!T|BED(L-E|^A}Bmx(txta_Mz$OrNYrCvKK%-G1Nz1XV2copG3H~#b+(k3KN#j zwKJ`kMW&Yw>DdkMd@r>omp=-OaH={~P#rV@a@`km5%?_?*DRNZG@&19BTsZZFgm{& zFxtflweRq*Z612nd^V=o#&Cp>s#%M<XglVk)dAwwdusI73)iQ;f4NMpTj)I&;YyW> zYf#QiN386sT`uXyejB&R1gMAQ8@^BVBG>4UnSOYFR9f2Yhj71<kYm&p9dL=1(a_39 z9R!Dawb~g0{X!iWKa4Xy?V-&iI-89r%W3n@Hzr-$64?_iGClf+Vxo2N{rjqnQNtsj zYJskCa$5be5G$;Wr-lM_KVXxq;%hGpuRs*nC$|YQKq;1ZxMbYe+nslU8$N@^6csNw z)F#y*Yg`bmFRIXKY0`97Bbg(j@|q*_x?wT}i*~(hn^m%wpoV@Nmxno9Vn#k4$Ng`_ zHJi8~29oJFj0G>Lmr#+o@M6O=o)%pN#dI9M7&!tQ9fIdUuk5gp{yC&rI7aq;#<FmY zu1xc+S#ChK&RnKBhj-9O-Hb8ivM>j@0%I%p8{~iB{@+3UUvU3Vmw~iA6}|M+VMIUz z0rCD{!2SQX?yKE6p_(H3Zf}yM>eSd|e1)+S?jlNx?3L01+vE#UJ(4Ptf`exp(x1g= z6}zQR{H@|X)%XS%;ATF+<S#YW7XSSU`VskIvgP9x)T|oXcQ)DGantdBdEJnCk^ATS z4zBl|(ke~4dt-ZhIlkWlZ-BD+NAY%_HWKl5PXvAeX7(;)&H>>hG41FC)>>!LUP=O6 z48!TtDZR-9UIT0&y=1Qj8Y<GcW50$QL~96o1$U%y!wV!FYsG2c0YuvOGRBYlgdtJk z&)8EI&Q)>*D(zY_#FmM)?~?6i9cb#+sWSY9t<0|V7@}qIR%3<BNaY(1P4@~jPP0ZP z>yJ_b>p<_b7Cevh<VKG6&zMwI`Id8lg>-I9rB{|aw_S7>zih-*@r@_ZnJ<rZ+r;!f zs6SS~H$km9X7eEJv+ERii+YLdmZE=tr`lV;UX$DkhXC|u-2O<IUT_4m<c$w;rK7n< zPp2&h3H8&zr}70jU26FOHBZFPjlCa6RSCe~@K~b2{_HmwoKB56r{|g-q}oZu1YuwY z59iny2q;58ErYYAya8co%P(9;#(+wH4$aPRCD5C_Qo*|?0E;~gDmDh3=Bp&(v&Tj+ zTheMLecYDz=ilZH&ErxWO;&qUR0#fII;~)hsp$^S#F08Q-G9Iiw^^1}buwjwJJ-Oo zHHOjX$4{o}9t2Op{}gWYo2#{COwSJ+xU^g|fcQu+e=ppnfXiQE{+m}@B$bmc<GBDC zo4w(^9lvBz!p+yeW%R*EGjV4xGIi&@FM^&+589oJ=apQ>DlGyo3rGkr(^m8)BME7d zJa-Nt&lps~C7wFv+-D>M4xU31C4|3MJ;SB87NR?3M`FNT6)do~2VIBlL>@eHlNln- zm(52kVG1i4q<7vYv0iR<Ct{-)AZN1`%wI+BL^aLH!+f3>XQ`u*{F;|biCbylfmyk& zJ|q(Jn;B3L+k-ZB&Na7^a4x`+qrn%OQ5MnBoKY#djyXm%vSS!b2m+k7?xh78&@pt# zC`o*S6kmh7ehc)04TlY<fxSnb7RB=8WB7(XgN8Uc5C0KG%ng?qrH(Dk)bn^i-FHr$ zBgp^L8Mh%iLmrju;J~{eGyZCKI`KEUX5n*3-X<ZCHL*k1=EYb-gJ6Q~@ILaC>{lW3 zVwq}cyRBj!4QGrW`D(!*5t~Uv^p;u(oQvB#^zM8C+ZX$i`0L-iNr6bpJTVTIuR*xB zyfhFH(|biaa=?kCKJvtlHSstNDLxU8TXb;t#_5}=aPxKH`CX!adIC?aIh@$XY0X2| z{@nkM&+Y$SB>wmE@nFCcBm@ftw1o}?ME8Fz9~yR!CTh+W)=vNPeb}U7rK-Au{xzM= z^D+%bLdXmSf-Hubwzo%<7*PN&N(QW-CoV@kz<54r2w@h2lvpgMwZLw(ZO5pv5W+vd zyoym(T<oz<ZjsoXkXCe+TV1`>)V@yexzMhB)p7#|x^Hk_xHQyta@{cF>;2C2p5<|H zd6x);u}6Z5VK5u)xp~^_>#=h<IQ5zZ``{1>n>&K3L)lkFZtK(+&d`2KhKn?I#r$H5 z*&R?bet_WNEvMQ|-{3ZWN?+&N0%(^oc^N<Pq2G*!l;x#N2o=4rjlz$gD`e&%jWzVZ zO&T%2ch|vJ2pdl%&vD$f_~j^xKht^(@2!#r&wX3jDS`W%GI(!;y2Es*3vTSei7j8P zSgWRHr!=c=)I}8B`E1YHXq#6<fp!D)C`w6X9t#c{Pv`Hh*}Wjl*G7@0SZW(P<hBC& z2HMA$|7K8G!+;^TC;>9J6?u`EkCXVMZG5*qHD*s*7bOF6;O`qeQNCV-xQSHTc+Qh} zXYc${-+T^h8buQy75Pr9LSMIpA8{>zt)yrJ1HV?ON4cJ}6i<VVoz%!Pw8J{#Oxvz) zWENrBA^cv_=$lVj(PIG(f^i;U^S7k9C}0g!5=D@kL8=T9ss7E~-0gJuEoKo-0}EyK zjZ$WjK$2YK&V1ZYl3u5o=x@KN$DaAOpz=J<z(m;9dNS0UU5w@>;?uav@Mw@?CS-rS z-o#7ev<YEr%g;${axN{~9d5eazLzKi;1rPpH2zkO)zJc@sNP61S<FE~MqQ1LQp|Qw zKW*DnB;H;>ZLE%c9YGo|C1{MPA;(|018ijTE^RqJl)M=^%wg@^U(%!}z>AQZ>G>l( zxBma3>>Yw^i@I&y%$>Gv+qP})v~AnAZQHhO+qQQaFV8(M;{B&`-@Or|uwu=KRak`) zZMNRq*P>dG0{y>J_z8)VHic?ckI7T3kzj?<0|invW~`lR^x#H73$)H7fDy;5{f993 zy?p3VWk3h!g_VdCN|qDC-&(IAhPZ@2Kn3UZ%+_PdNh`*MMJz4k^W7*()=i)K_(7Fo zBuko12~7?@iUio}EufW8l$HlL=aL&;wazZ0V1@$om-W{_+S9eQ$x^n}!bEJmK&?nB z1VN`sefCE5sT~j9u?bYRUI~1TMq(K%=p7+b!qW>$W7_YLuw4&<b?gjLd?X{<?GfoZ z?wO)G?i09mMyLwzDzIwzo!MCPC!>|v4@PG1q1X<@)7%E5+3r!}bFXB!J{O`djizgj z{>?0%(Xj1|aM^rn;P%Fk+KN1LVSvmR)7wtSrZQRq767pM#JUbodXny>w#haUJMUO} z5Z}PD_mq^*T#kgg#dqH+xy(L3sO>s>lc!+=Jq+;V8kZPW^&%UW4u~{v=8A{BFX$h& zv{qYgudjFHn=2`;zROr??+Y{id!|g1l`tbnlqmc{^|UCxfmi=XMUZHv!Bw()@=(dl zQf)tEP0N~k4o+|HuBeu2$_n?-2{O*)h@{rkRp)jdLNgzHud!=djR-McM;hnPYOV_w zHW6n_?iX>G+R))qStoKLHq1V!hOBI`fd5(P`6kX(mt`d7U>-j7|N5iU{4|1bN`?-u z(V1SMy>CREWMSo@BIO*(KWg1OoM9CU6LL^4@f<QOP03r+v5hFJHd`AGl~4}>wY5LA z0%5%fE*UhgjB>tMG|O6<ldSYGD@iWXTTl@`P2G$@?U4=kn)XTPS1Pv!d~$cw1n@uy zCy9xX8~N6pW@}@z)-9HwbIL!6$gAxI<UH4Y<uGQ_nzT2H;>ET8kx~LfT^e)7*;PE@ z0==;x1v99zXjx4sd7cM2S%r_SwL0cr-$ZC_j&yx_u&Jq`q{FZIZloDXqq&o$I+8+V zEhS1tu~;>4IuD#_+{<CC>lyj%*ykDZf_!yhH%*Zyrguxe4A);nM>ikaj~<||XE|qV z#k$sAX!i<}xyucB${HK5JMWEL0~$K|gdUot{m3PCrQ?%UyzS9C${v!X&?d%E-LG<h zDRKjEGRb9&{)Ve0`nK)kc(hfSGI#rgj@#J!gn>@Pp0hIBTEcD8y365kbBkL#>V@ej ziG46=o}SawJfuKG7psJ3*jDTXo}3~|kt(yGuT{`E9np}~2!a$iiRCCtQ#$H?hr~Ty zXF`L8jES7h!=#{mfIbXeo;qEzim(KKZa$|%3!My?nh~SL0>q?Dz+C};Y(aWbhNxVw zUZzy6RyI+ms2#9u!MdRg^2Y*pz=HO<Tym@GWdHF(ajV9wO>=pVS0$F98DO?zxGP0F z25BNTbs5D?iDq!K0>M|2>JF_L@kf4|eeyCXU$y*Cv*@(4<+9gKzU5N#g~M`9hH|Kd z3Kqrn!4C~;>-%^dt5*~%<3u>X_f%nfvK67_$m@tghAnpS+lWGhEu)4^`pgunKFmsj zqjOYyG!?XodNdUWW4a|pjUd;HK<Gar>RI~eEJyOt#Uak*Z>D;k`)<HjxLa&eR!olI zN6OQgFSZ9}(N>7;^Xx`H2Jj!4TF#IGiB8dBvMW8J>|q>-bn$8vVpdV$t0#LgGorc= zSyqqOekSNftF-8S`WJzD&h6UGPnX#4=OcopRgd4fO33IP&fpXQI|o~UV63dFy=aTz zy-B7npWa`h(;W`~1nXuo2FomLn6ctbu((28;dl@5;R^)B0|n(W0=H#))UrUe3S1)b zSi@wGKR6c>R(o5h&SR3sG=tiHkX9q8q{`#OEr`mUMRDekT=pz24E@+8?b(f(_0}V> z6INR7h^uv49Uwj!*fFI47z!0k_ZjW055&qj13#IX&W~Uysiuk(^?7qpPA*6EMy!`e z1?1fk(k5#j-WO1$1yqR5%U>|I%mx1e=D&x@fAu@4#51N!v@<3;*mEAkRw7*(o-?Fp zuP0LEW=-)mk~Tj6Or%Tk#xrT~Iy9Y=FF?vyp%iF6<_S^-{LKsp(O^iiAW<uy9-yp7 z#?ioFwX=z2{qP-0zmc0x??a!m;8=}F)db1TXE56MC%PHofTw?cpG<duiHpnL=nn8Y zVJwV~DK<wv7$GsBfibf`ub7ff-a-nggy+Z>+eZ;NF#^O&_!fkJ&ILCvLr$CkL%qq! z-Yj}#K^0%if-rAFxDoKSLAhj6tyWYm8rT9ly`fPxzfq^tiI}~ivX<XmsHqv+y&-ya z*db6oDd-0ANKNJtP#5zjh&m{^ptS^H=2$KT2X)}hs)<LKNo3xDJ<D`oe2`re1+^30 z5OQ44Wnd;#SdAtlxvn2tU(;+_V0}j#$E%iT)YSo9w7*ypNz5>vr@*yWPge}}!lzTF zO~VBosvFl3IrYtb#x%_m?PP=I<O0m;m|<M&12E97*P3DVWIndQ0{dY(Z3h09_{bIE z!BakO8!Fa?&%_)~ujUz_z!zL)V^FP(M-UMX;X%J@88%@kHoh;`5bM;%qWq*a+?-kl zX+0?RxmCjyN@)__-8N&au`d3Fj^IHnho2yF>=9#{cEU~YK528BaIKnfDtP}0;>h1T zn|qbA5<BS8Few`01NKUQT|1_CzQV~bXQ{;%A<N>x!gFR-!O<aDhF#kSyqX2qTOqJ} z$VR({o$7CS;T`I$n>l%XY(Yt03egVE(TH&pdeu;q!V*j*Z9Wc%tDrA!VBud`gKJ`n z4?>C$#1nJ6LQzi;=M77<Rh`l04GOE$E=^A&M<pw=>zdPNHu~7s)$TC0&3Z6z?0!rU z1VdR0Ld^E9IpI9rv@?cZ1g_W50c7guhOFr~ITKo!<@yJ9W83nKoI9zK&Oz(!!&>e^ zH)HaUuJxgW7Ga(Ft>Eeo5r(Yethb-!wNSzyv)2Y5Q+0P%ux!H^qD{4mjas3yIms6H znJkqCszr!!IlZ2BB-Z!;8X)|q0{@@dT!`a5U<m>MfB*{sfbxH*&6Uj@eu;(uA<Vng z|67>DPE8qyOori~q02WZivfeND1rz^hJlJO|G^Zm)(N4Cf@M0I!9lUyTvC%+Agy+9 zsxK*Lu(o<%B7O)9-(WT{+<eOBP3YNVw*D#cZP42Ap6Pxx3JK^q(AXJm|G4_Pw&k12 z89uJ0%K@qb{)xYnN9DZ*7(~Oq+Y19~ysraFb|Z$0<&+N_#eOBkjlUxS!w#7`RA-;K z)twn(;NI{1dsh@x%Sn$i`Zl4o&hB6Oc5I2*GxIlRpONgk=@?7vt5NHktv$q6;<W{6 z_%$Zz)**BB?cnA0SQ%B;bf1Ivjk~w2Z#j2-!~xpG5PZ<fI!IS%N)%;A(rw%yvWt2@ zE9eoCmVQje->-t@HCbL9hC$l;a#^{!v)r?=#O0$aqK5IPiQL;_%hRXZH<l6JVsW5e z1!C7U&BRKl5M=PnUROsy&A=;MNl|{ctGK7oS#z`GdBhrvjituIqRiIPsLTe|f(N%) z_x`y8*S4;f4jtV6Q!>xAd~|NU=HoMe0U6!`J&ViB-$uylm|uxasNK{0QP#MXklF2E zZ<!jsQTBrdrr&0OwRjy(UUR@(yJDrp>CK#^mg7w2GZSTcba#4~diyBCzuI_g#qa{7 zq_logkLjrG_jesMoQFFtyBFx9<ohsA$k^vAEPMFnEIySE@bB_SHt1ay;|!UDRbkNs z{@v6k94eue@Vj9K`1D>Zd-nsJJENb#1V5|l%JI(+V)C@^mOX6L|9Ue08~6W66<JVg zn@7WvvBj{K`Sm&7GfP4Se6lI=Pt3F=cRA~qWY$y$r%8@h_<f0cxsi$n@M9hoSnVH( zKm9V2gZ^T$?f^uZ|4~Apqz_yc&qyw=OJ?PTK|;liP3po`seSp_L^R+Y%wD-TV9p(B zWQewEf(>$NuBGXLXxlQJTv`*R$^HFD)x%sXCE~SQfu6uYKyI2THp8k{(C*Hiq0?_b zGRvthx_JfJYz5C{HX9E&poAhl4UFTR1dC=NJ$<W=Dr)4|gjQull0$a4jwtoavXi!l z5}A2OSlIHC`h6c6qW@BHZJG1B>>LT}^S<v6;hR^mRRxo4tC6vI+tOp_;r`lN(9^wC zDhNj-<<`%^P8yUl8j_1@xAAuI`nw+oCK*$k&Pq{o%wHx^B=n3|)UUlsB8Wl*`XPb0 zcsKWo%#|ybY?^t6Ea)p;7Z!MY@s5X9GzXg)CnHVF@fWzmy0!m;K9>A;+Ey!{9i^Zh zH$0XRiFPH2rW6*?V9!bX^K=%9Q-BA2dZGD5jh75kqomdd4ny6dHEz<p0XapKta_sG zBwiT?6UOE68Q&TD<Pl9NqvPpa7MJi3$=tLD<cvR|`AQGM?KNx7Cjj6WT}$Lf=<cL4 z=!`xgYbRe>cJhG8NRAnO0(U1~aeU|sF<BUQhBO(!`_#`yx0jB{5Z>GHXt9U!C``s# zjmxy0(L>Qq9BP%sg7i^;(0QyB;UCC8)kk#i{@R?|GJePS${$a<VbzYmmfm0E^nB8V z9It*<hFpHLHRpu??vT3(t;$L|P2@wU>rB-hbWlZ!?p~UkGqV;`N@uJYOv-drP<Y4} z?z)6W2g%V<jNoDZ&0<y|k=AGZcT+d8F0rP6r_|^d103#xet6y#<WKV+NWtbF{rvhH z;rM#@Lr>r&D$hQGTyLt>n&8hmm9+`&T74~`MJ4r$ZIfkGtVOg?cu9bi;@?8F&!~wj zm2`FGk<(7)a;`lQhZ^+n(QCC0eQigO`zUbAT=@5e&8f<A;beURw_#2(qRm@}(2a#c zEB<PJRD^C!Rb<GfjwZ&yur`zqDZjfUY#{Ag%AUy8o;18|G*xtwhD|@*7Mm^%96Vh| zxX{O}k|bE~K45pvw3yAObv^(wBN0gf!vKb>{3lQCu0&L>y-vxuH(K@L?3$iYKmVia zL28TxY9&6EA!zEcF+|_I99_i5eHgzguns4<`2d+qBq9BkUfXm)bk(@26;hU3j8|2U zR-K$=8!w-Zgjh^NAvW31&7zOeC{BwPvp%DzCSQe%G3&29{=N%f#W=9@5U>gc2+43@ z#yCSX;jUkb3NN^)g&R$gF;IVJV3ds@hekd4wf!As;T>f?>Lqa30mGdM)?G$@4lsLH za@_*bo>rPWYD`Q6ff1b0$p}-BJytv56Sz=t2(f@V88in7T$G;ud9>gyPKeG5za5Fj zt}d!QS7>K9y+5#xeSY1UmM(7q1+*9e4AIMyy7V==ppF!<VskL>DU-6M_6maZp@ZYA z65t>Rvg#(KR*Q6MuwSg62WU%H*R#nmy@?$i^*|)$(VVm2&NITr*VrJLe30kf2q5)H zH}Z#2l1ONH*~b}iCmttmAFh|Go3<EsS(;!`Eu#M#-ap@7{EYY%R!A`{cONWu%ThAg zH^yI`+u&9@o<*>XkbJ=mbQrLl?g+v}yyc8S+adW{7F2z!-y?A~8n$M=W&>Ik(Q+R* zR&U3VIOr@5kP5>Ah*&}!?Bv{Ud67Xw3~<iTCe1=EJKcCvVzVK9+L=D5c|OxSgFYfH zx#4Ua*k+8p{@HSK)a*KG5S~ef_yaN#$TakhUr&z>LaJXehAW)#2uTdVBkOS`6Ie@* zv0D~COU7u69T1TK;X&k|m%<+45^=C?{O%FQy*GT!8+j0;E|gb66Jbor6<#i?labEO zm0}O8KxG>!M^nFHpD9AA^xPa7)xJ2SU*)tgfmtu;b@%IdUMAnK&k8p!8SP5uBxl8R z7^iurM*XnOuu%O0hx9N%V>(y2STMvJ!IoNI(=g3v2XQe27iphA&jwv#jyNHu;*2XY zlT)78@i*(ULUAq%YmL~RSG@<^!7lh}Na|Ja@UE+ATf5k`S^s7<`Kvjhm7)pCP+PNR z%;9>l!PRAm45#nY%+ffasz=4^zu=Hs+}C0Rd;<-sS~F?ULz@R`KQ|()<2h+8V}`h# zRHP@Srw=zcjw^!e2`zGEKczn^-=EXR_)KiEZeL|0rw_#CUwvhMRdnj}9Ci2P@=y?7 z;ey9Yi#cpF&xoJ%tTd>95RQ}~Ag0d6E8&n{mdBG@plXyat1VHPTT&*HFrdc4Ph}|# zx$ah2S67)vx32>MratcZG`;u4M93aWI&Q8WwKxD?3Psju{#L}!Ba{agzNmlT6vXZw z&dwv3rGqc4OCYODB1?x@S~zr0a_~fG@8PbPb%QZzPSyPQl(mzZu=tV4?hT;s1THLD ztK9TwUX7A-4IY&TZuNX9WymevSN6&qUaIeB%D50H<onoU-ux=Rpg!;?{#>==@0>SA z_Kk|uPu#R@U?>=s)$`B)S^@Y^Mfg9p;%CCR)ieSCfFuC`0NejgD>|858`B9pJLo%^ z+uHnhf#ZJ&$6_@oJ>}!%Uq^Q|JAF%nRLEuwJZL{19(SK092U@BiV%<(0rC|yfdC^t zeP|rGf2CquzPkBB<8OHLaL09tW~ItJyokI8-aqYT%jK4imWT~)>&oVyvh~|u*9QR6 z)@6UspU0n5zEi#*_g(JyaUL*$sT5;g<wGAh*!R7mS*OpfKrrOjyqHiewC7DeINaxb zG&f-a+<y=M(%?!D>~ZAU#(-<aONFX=&8Ox6J&Ra8C-Ds8&8jx)nwZA?LJLZH+(btk zd7~6ee<Y)Sigjk)?<{d<J?{eGknRfLdi!m8UbDgI-0vDPzFNU*-R?Z$zW4eoal20X z3E*^I_F#g&7DM?Ce35^C{_WA=*iz;H91VJXs*mb=h3(<6xc?p1U4G3;xU_}z(Cy}x zUxah^D!O^D_rOu@aF^}=u1WJLV14=kCgeRUP!P61J9x_1(c;$K>IyjPa1*E2X}(gD z&!G(w`{d0ceY2?N@BYKtb0QE4W)C-WuU82M0hfSV1Y9%HQq2$}YE6kEMJFN5#c6;O zpwJ9cIjiwpJYrm#LaXVq@~~`qiN=!CY@%Rz*w9=F+@E|Z+$utaG_NdWEJTVU*F1&v zn%Y#%$vCfUqRl*yQMktyv(@JD$WdPc%_hl{Yr;$QO8j=mZ4TdNc~I_V;@_vhYn<KJ zUR0fK1*tlsRIidfK3(r*=;TOPlGef^f^=DM-j-pCmYu%B{x+q)o?=rT)gqRuVVEpq zJx*-g5R<Ev9!_SMEXB1rFWp7c+(nZeWg<H{goKk+W*5nV!(UTY%537kousuoWjk|I z5le=6AzscE0+>7+Emi|DF>x7Voc0LaDnm&=E7HI~7Cnz^t%En)WD`}qnWT(0PFiR+ zDPgq8SDO-^Vi;H7$k7qVtyOKEZ64#nm~$~jjyKO`AY)x_A}G4BFx<Da8yC)MT^-w^ z*)m@&Pk$h8TxBa&8BH{K$$HWgO_XR=iss_f(pqYWgF|Kb`x3vjokC(Tu0|<zF%Psh z;>4W84ti~lyX58X{hp!5xwB%0QQFo;+v@&!HgG=WXWd<|{0LwLZEBEyg2!_DnWf3L zA(gG{VoVfWS5JfTf$W+mPQ%a<xb&bgp?B(7n@5fYrZLem5PwE84_u2VL$!>EFW13e zqO$HRMxAjpM=~Z%qW1UuO}lvJ`<S)tvdhh}B>9k)i>obTgHs84A-Vo>He9z)Xgiau z)hfIgB;Qb0XA47)d3326Dt&{ol8fm&I~{aWK^-ZLH@)558C1@(iX*c<Npt0-E0}IR z#iHI6I!f5;!==CC0o&$I<d3XnL5>kbZW|}@jsQ#gpjA70cFc|1xbe-u5hbd_bT!V5 zJX3n~mf=lK^Q8kKrK6Z<f97^lwA_qYnyUbJY6<T45{mfg?H<sQ@RGHMHqL5duw!Tv zKYv#Go@f**!f~UbLPJp@p+JASL#hDvpC;-62xH3$m%G0$`BgbT8IvijDb;(u#AK+q z4Izxf-<4AnLM<BWB~|SEV_vwjE-pp`<t@@~j?`HZ&G6096jnh5A_kakIIigIVAUbW zlj0>$KVoZUq$c5JdQ|3d^0h@C+J2e9DAUIJ$y$TRELO#<^dhjPNLFoCh16No<;G4E za`x685^HgY5Eu?wQ3k58v(TFuo(H9nrc7g$a3N7C3{wjsNfT<AiO>!0J7RY9+m#Zk z*g^x0vei?NaHQV1dqbko3+`ZK5ieDMJ07S_1eyk|Fc^$Fq6|bBi~^*XZJ?`=CeV|U zVryk2IE5*T`_h)oD7Yy#Kw_@AA<_xsAxRQ%erRe6c~-)%NfaT<W6CaQqoguICF4#& z_QuZ`K}Cutm}Y>3PD^t)iHr3qte{#JVOA+qtVS_WEJtqXmV2t7OZ<@49m*JrG-PuI z?6Yx5Bm;laiD;A69-+(Q-zNH?Yc6InN+aeaB(K^-sFnTMe8f4L!-2cG>&dql${|l1 zu4U?7IxS*2X+(b0UmRXGrkbRvF{J}8Fi}A$qaq>Hs;-)ZQnB(c{65gQn%TgIy#FAj zd+txl9uoMumy^z}^!8|CjAtUtALIuRGb*<l<fuz#jSKFTL!DKY{}?a6UeL);#$0Qb zmW5Dm?AWNxp0_)En<C@Mm00sri5$28RvuUJAXrCK%d#jubzpz~#3yfE18vufEbBZk zTj6)%WM^_U45S^mUuGo&a5>_2#uV4n%+CmmHcKlxykOn1bI}*yQ5<8%8n;k{Qkpk& zH`Fxupe=b*P4E?BaCZ3HH!$g%Hs@kAC)YD&X$&_y2Mk)IXLS+K;p`bHD3vf}l*QV_ zl5x3nfJyOw#6E0jG;a>VsP}R#2nOcTSd1cen%j@gkd(p}_in{7R!uC4(JYe{ZZ?K0 zVDcbrCa5DdcZ?absCE*!%1qD*Y|B*7KNVa}uMtPl&enU6JvvCX%~)V(ET~p`E#>IP zA76##%6Xrqvr>^zm^-R7jbe`6Up8mx?%@W_MWF+0vM=rlhD&AzNh$L-k2p3Qu3V*! z#f)F2HHh-L*O~8qXw971A^%(Ti|CHqq**cV@y7Od=k5Z<34-=SVmv!K8)nT)HKvDx zwXD^_TzcPYvyKbiBvj{$(i(NSsvDcdBhH;BLT)c*K67~L_h$Y&(SOPj@L*+E_aG@4 z<n+m40()ymb+4z<Ptg)UlTXeVKC5IUYDWY_hJP`%jYk|=4ec`brYDrOZJyMu_N?sQ zx#(K3@Evmp`}7{W6}7ML1@|{<u3Xc-B1Dc|U)zIs5pK{RQzc{eV+pMr9=D*Y=dN=D z&}0mPA*p-}n<g?c?A|f>Td#9PbMlbJ8>Q&#tmdj6N!ZgXTIqa`syhm<HNd4SnfeAQ zddL_xd|cMoT6RT6kM~y}<Qv7(j)k?JWG%qA&`?Wi`ijt*%~dD%@=jaI_5x0LX)JHY zCu=z~fObfPo2PFZ?a_#AwhQ)Wz?(M53x?x5FGYykl#GC`xGlipnjhErjkI`EfUPUZ zOVI9FiMUp2ludY4wDcX&a3qRg-gwIbLoBneaEo~XqPTzFsUghKiH&wUlmY9xfSJ7o zZ9gutRwpWwU1(<Sb#Lf*6{JnDMn_sTZM;(f%|X4b0lN)DUF!`$W>Nq3GmeUVc!Z<6 z*yboW3z(8{hGCmMu}I0GPTL21lR#_OG^{XYQm6l|+%*d`D<zqXorm2JpbB~h8^9FA z6b_QxbWEj35(vPRG3CZU`FhyxNuTpZ6!=9C@Hrp##Q^8okO+2e>4l+nYgUg>oQO}{ z)FTblI|=p?-Dc>p4MeUk);9rJZXe<Ew@3Y+JEz~$4b^u9>R=>NF>H6t>{E5(jw?Mn zmAX}fUsKkUwKI#XZOmK-wZI!pD|)W=OfLgOTfaR+%;Z4w#!(|i34C<do}oMBhflD7 zlsysF5oNe>aX`=`SBWHMp)UDv%<bS-q2r+DphIB4S)KP*Un@lUmK_Y8g<~ZVTk3SQ z%k1>EVWj4or0A%F(i}+2UBqoOtL~{QI-fv8dmXdav}-<>=bjUACH9BHb|{jdY_iW& zTqhivC^x|@uP|%U&2X2_(wgN?+~4ZpM#~+3A3D?^?v**M<HLYmojXk^cP;uWkU<Ul zwm4I|BXy|nxK+bxo)u=kBWHD`R2CX=_w1D=a~YtLTTo=~Igs4L=$fwYoNw2uE-XE# z<7Fp|tZq|G3zH?Mx9W7==}!{vHw)B-+dc`^5=;6=+dgupT~5dSb(J@5kT32yG3twR zJ|k4}ia&)^^!&|f%BzQeP4ckh%2x|b1p4TKs!ji*uvh%y`Lczx-msX|R4Hp~>xBHU z9-kiAF8d1xy2U+@i^}|X6nBcB;$)cQt$P|x-h_gH?npHL7<?pI1-Jl0e16`WT)F|= z(%@2Pv}O!y`_NEWvBzXvG4!ly04DA0$L&Vc8;I@HnN#LWByafMZo_Uyv0X!K!4rE4 zy84LCTyC=(cd20Z4vAx%<}Un-&D>)H>XHG%HT{`g;#+Ed#r)`!(UV<b=|&K*m^I}J z5n+TaI!+vwI$maUr7FRZGN#Nt!8~Nd*)k5TMVS1VlNF9PLA^yWdT5g#`B4N3$7q0; zjC3C)d{?!!=bk=`T?bHm7kM5>J&@Ue?werzDxOlPD~p<21>d_gA+A1td+OoCQF{P( zQqK5y<-xPYe^)qKkqqmYd7apF?7TsJCMiw0I9nbqpUODWNh;DySK}D0LB%GeXiMnI z=R9tdgs3+~)?K7!veKcai$XW0cjE7ncRN4QTZhRQiAKFvMeq@$b%B>sCPAuY;}K-F zXw6c}q>4thRyE5+Yjfifrgfv1Y4GbWrUrvO^VkNh5kAlre+|MoFgp(C3Q{q6!B}9M zI>jbxA)`8>+_1|9v?mZNEwZvnBV`LK4I8t$oI18sZNhNFo;tl#jj`2SCuLq+njm!y zjJmp0jk`9PP2I+oAotxDVV6jmpNczVJLr#Uh?ZY`Pw+x4UVdLXO)Xo)z{M-?PvjTS zAD`Y`whdi*C-l+rKaWH!8rDx^@kCPO%OG8q+P=95zmesrf9oE|5bPC@RD}KVcl^uX zVk+_KMlo#?6@mhdW-dd}>D_9W6sm&_74i88fqKc*&>(`t-D)$KEj?md`358Abh0-i zWAb`c>UuF(gOI^Qhq%~^XNjP5hcTjjRdYU2+K7<IoiQUX<X(30wRq9J!u!(#T`y){ zkprpF2ah59*^s^s1FIUZn2mK<iBkbK=r+yeF&tak#buwrO9WC&fq5G24{0@o=Wj>x z@_s1ZW!$<W0nqIjI&Tor?I4Lqs?v$M1~FS9?pL#x#&CgmvQ{abbClg@aoufd?`P<) zhZgOjA={z2?P#uJKG;b>ZfZA!Ob&d3xA;1#x%)V89Mj)^XAgP6#{{6;bVXXY@s#>w z6Nb>kWJk#D!TT>w$5&2NAwIm{+42x17?F5)L<MONNqeDMSP~FqhkSEDO6{S?Yjt_s z&>;1Bw+Ieuaoc#5V>fUpMlYd|4Ie@v>tFc+%6G`}Se0iZKN6#?N661PXbg8rk-2`K zJ`r(zbL^biP7j$Xc;#9jNK*^<NI0$H=I3hPBh*QH-(YjRdC<K7*ov&2cSX;Yo#`m9 z2Psr7)A1Z)AnFn|)`9+xaTwuTR*LHcXzH{yDe3=1Cs_*DzLuhPXMs}OP>`{NZ-rr{ z0c{$j$B2x4rSG#D#aRdNT)lwCPxmg{mG5V@qf@PRnlhz~V#iUTT`XR)Nr-?<R55W* z&J;vVzu{lEc`ePX617BE>JWBX^ll^>kFA;|$%~q$@KU`~KwNrUpDFd9jrPiT(;6Zh zKc(btnbzMf{Y^m{B^&y{aW>lbT3qmEb?CqAR9%Y<dXO<>qK_bSgTX}oWyu-nQ$9ol z&BHupm|J2G1uPyZhsI`+P5Y*oba0s7AuHkwY9}}qisD}xD<;^6Y~^M#zY-8v2y#jg z=2jBI6+wFt&T6Qb94_-nNl3jJG{*wnIQ^ZMLw0)ZME-k`$=-;hyB;m?UbEw4rTpNe z`M~8TvA#p|SnnK5?PZwnjYW`dH#`<f8W&5W!8;V@h{AjW{zVSz)R?zPI__CahhH+Y zxmY@}PX}tU;MuG~KUw%}Rio_rq4o*TgoQRCxCt}e7pX>-HY0ME2Hyp+LeiNR-bbiL z2yLi!l}8V1Zn$-o%D~HH66;iJJv37wu22?fWs*8Jog?b!YvfHQ1wZ&xubzl!yL1gT zRruSorVp|!GMwix5nSna-j;M34A;aMpk8;H8KZ<_RLYn0X}1=n<^m0P+U}G2KOFcm zYbu=P!4`Z9>zN#i1$;5s-0q5ryDw`+otY}yX<ol}Q-YR*iSFr}gbu1r!#@Q(ef&M3 zW#I#MKBp{p`vCiaoi}5d?;F}H;Zeip_J)&%%&7<a-b?p{ht6pRGr7CsA%_rs$y5DG z7o-kM){r=Qu^Y!btEgpE?;hDXh8KL`lstyfIq+L9*$pM7@&YM+K+N2K<NL40;s5l7 z{-<NK%-5#D`x~;;`<*aK{{K2gqWX?b!oTS{d3^^*V+UdhB{_ChdIsfRGfBhN#`w27 z?f03f`~SNpud1m;^jn#h0bv9_XpBVLsTG8xO16dA*UfMDHzjkvu8-8ye;XyVhz%M# zkv-k2y7(JFmwL6enOe%bexiYzABwts!PPhE_*_<8O%Ja@qdbS#v19hd+q*-~^!xiX zmJcw>pb`~O`rQuK_G7H0<{$*_R!?$R2CszSaFF_>EA1s8^|m4`;+yB*O&54%$gn?B zlM>b2Y#;%xRb>cdAt53tf=g%17+m-;(sH#XNNh!P<sf`hDSZ76h3<x_%zl+YE9W~+ zAaaA%wS<N!^^hZ^vOX#i7DJt=y<cd2>e*#vCYX9qHa1wxF*EceDvL`fUn(T=P<9tV z_K1DmEc~j?^(w8^WT8psg;OXJcau2>J%K=2uOvGLSfbsOGw}dAnql#z^<ndJO9K58 z)%~+xdZF$HGlpU(QZ}|zKjE4608tqNu_L42-96qhx%z^Hy-D15#ZLQXO>m52AKIDY zMivXTRVif9POdhLRgr(Hvjm0nPk2^#PDWLf9(qlbzd-&K19Ps(u>99h-9yssdz&S3 zD{7P#L$9;>O-dq1zF1(bm!vXV<M1_lDRcvQ;H)^QJMAhPDlAjf<qx1MqdCfKQb8p0 z+d+C);*n#C8vovKpMJdu%=X#BT%ZaJoL&4=mB+pOAdwe8x+~(MPL=s9d<fblW`g)U zAXhsE+ha-cK@2}eY2I6K5NOOO=EB;Xoxomi2yMvfq`$)Cf%#yD!@`@jO=qKABKKtm z#)Md36UC27#b^px57}eeX%BzTS@1ahqi>d8h~xW3>3eiI7?4mbZV4~O7d5((8P7fy zj8hgmz9*p?W_FeMykfrHge0b%J8kd6iD&&dy{dZozvwZ>3OP=#_Xw74CkNm1g;z26 z!HMj)a@18e_l0QSzvsB*e-{*5pg@#-7H2z-3`!3P>GG0q5$r3I<~N=i1&^!sj2e*# z=${-07DHR*lf*8qSLEc1Fanc}QfrDQSOa0*{k|apL9Pod#w^f+i9T%B|0)$K0xTn{ zKb95X$*<1B$}jWP!5OFORL)7wf(H0MkW?g_-cji0$9h!<pSK0E0h*tKBcjj6`V*d^ zA)n^+av!~16~1#|f_<^{4tB!*6LW&WEpRyo;Pu_+Z6dJvD5HbEk=zehr#nbKEmP?c zjeLL+oM=tx?)B3&fHQ;_O5lmo4=QS*{|X3V5^Moep+U=AFda}+*i^zqcof_8O#uHB zDxs4XsKM5}!^3=al^>6}$sxQL@v{Z^>6^UN96?OUSE%#`!ZQK;p2TxDVf)LP;~&** zlkT3A2a+o-AeW)6*|Sg(Da{gj2M$!8qcTnS`<C^jGw5c2Ql$*4#VM>eyzAwcqC1a& zt!mCD*(tMO)e5Y#)^VFhv3uC{07POUXk!^vCeVk=2{(Cm7Y3JY+y!|5)fDCV)I)f_ z^xsjp|Gb<2=dHD1rtOh}3IKq?3IM?Pe|c;D_wCfp1>vT=ynNcl#$?Or?oU7*Pdx%o zuAcx84vxNJHD<<|SO;A|KhB-tZ$vsHy%wZ_R?&iDY1v#>y`V8KX$dURSJtMYX{l++ zRxRbKS*d-cGyIV2xSPplOA17C_7ZrT^KrxVV)e4+IMW?C`|}b%3YaH3;V8h+Vl2Nn z(+z8*YS);Msj^k&(qB3^N^aTK9`svnjvkuo;Fun8iC%N6-wV}ZP#U03JGN2^+%}&! z1q#xsZ5P73Rj4-y0@4<rDU-ey=?xj8H5ZXRRh{Ume-oT;pw{n$CM}YSL}!X_Z;+%v z6%5q29<KRnTnW{>?{eZ49KfX|AI|l5YzV1yJ`~G!Pl?;H0ixm-jZ|wK?|T0tXLrk) zviC0C1;{r(U5fnK1ciDSjj?p)A^>b_;LkfaJw0{V2<bBe0&{ja-b()Jjz&GI$#l>9 zDM)(LzsYnDTjB(!)WL+5aUTik6K=XY9OljKz-D-Ryt;|<*?`o0FyyIKhuAxD(w<7P zIokcv)}EVLYySwq_R;>v$+o+9B47jB?jDv2w1s_iqHhCh&vX>9%|11)@558DM??#L z4vIM*6uVyt$y>5_NE>#b0FrCh55PNqC`a+ygp_N4z~+vVqjJZAcEz6?u&a2tN!y0# zO8MFaRb%jqgQhij2ZDBG@T!fbHG1bs+vdOjg5ssnk4OHBIDoP9obu*qI&%U3Y;HL~ zP|bsSKiYI-4PL>9yg=yO{cWZkN!TW47-fljcDY0t?mxiktNa*Jph1oq1;S>Dv$3M~ zSsB15JXQnsV%zD4kG=RO{2q@W%J$!=fd+9B{&7=XxU1$@d>JZ%!T}IVeqV(i{)&*$ z6T#W7cDYDFznxidD=r|N@K^;@XaR#SdCS5sSKhk74-t`cTU|+WNqc^`es*hlbN;mE zqWA!d&6Dl(U)Z65?&RowTHo3h0D<#W5+=TvccJZMVt)E1ncQrKK}v9rlyiGcgpk6& zafFiE8sx0-1i^EWaRLS+2E5a9@9Z$RR>qak{bo_%MonOyLOvN1%(Sv^U3CoD=QU3+ zADtde6E$|ac;!^YS=!?PDzuMchX0Hxw;hy}u3PjN=6`$X%zN_kt+yF%H9bc=Mp9H@ ztesh|VLl1^t7x}YZ%fDb!Kd$vzUu6nywkc0BZG;SXWEAttEsRrFvEn$2!#oDtRG$$ zgT9seHQ7C?WoMBEM?Nz)Hd;cGcQRr^-kp0wGFqIkajc&l{NeO>%ojw)taW}z8zI&f z<~M3K`DvSH*Jfsw=F-PWofY}}1<o{+ildJQhvh*I7nWY;caG8fNcm6>;rmS0gF7el ziz%&DW`@8cjpD<DDvqMQ=(BhxD(a#Qz#vefiLLG;Vu8*@-T5`e?K>0A<C|+|I4oCc z=+GdBkqD?sF)po6Sawah(z@Y#l~7=2T+z1BA<R5s&aYhVi6&4*$v%*zPd3mS20Q`| zdl-ffzz%+qvYMik;7Z7hozbuJIpEk8&g2|!Vdl)pbF6X0g4@o*tjK#3E9@wEBvaIc z3(eszDe@T>0Fp_N-)Rf5DhSFNaTse)Neq&U2zn6LSOFTg0Q%#hQIg;bA-q8%rD7xW ze9J7#-15)hqN%||-rs74BLXQ)<kguyApv%1JkH=XHZ&`kvG*Lsi;E&}(gWx8K;Amo z6f8@ozY$r4YsZARDW`)uTD-fL1g2vR@4{lo!W9(FK7;Z7ndtHMkyr5(m{AWkK+{;h zjY6(EEza#p3G%8)$qiv<U;bQwd8<3{5E#N8`5yo>qv>5TRB6bBnP4&j!T=b}&Zcj4 zlI5}hK83qdqiCNNyR7kc^DHk9&U>8sJN}}`pq9uta3wkJ#ft$&Up^5tZ*EZ#kz%#I z75Y^4eRzVkKSAQjq#QdCY+4!N=D|rHgH7y_vVk!wM(L_p`7YGT3pW%GV5Yggl?sRK zol`v2{}PVLijjeI9`uQXPDw)Rt-tQ&Pq_NC;B>{wUm4p)nb%f#E5jk-^w-URmSBNB zfttAFZkWc~n&bkD9GVuL0-MC2r?n2}ckW+a64NgN=f8D+T1<TL(D2YoVKfR|%U*(@ zt0t?^C?80pBig6<0}vqQ;UnzBQ!}G@RG=ee>Z)s*q-XSF&9*mGG2s=(IM9k0{sKu* z&V7f=Z%5J3V|o*2tkl$>(n^mq$jF#r+=rOKNU+fQpODJ&{R>|dl}c<uEJ`d4sGWn5 z>CYvw`YKyJTmo@<1Hu9;5Cv^c_TUJpsHfR~*K?giZytT6&ma97;wUO^n#pv@%y9`0 z!wOqP-Qjn-D1?!{x=4dmPd?&Ic2LJY(GdyD!u%G~V$FQ3>DIl3v;lV^iCWfrN7$5v z2!Y;Q>vUrOw={z^Q%0fu`m-*4;Pg%8(q2PLgPG0gcp?pHq-jbjYH~j|vrw;+g4c{C zscCAjG(3G3WOX{-1kRbNTQNdjwx($h`It6PRMbFzu8c97IqNnPtlceIEXM+yOj+Zi zz(Wn?fSQ>$WeTdKY|q`H@(RjbRsc4sJT=UXVyagR*&C!=ekbGRk7=c_KY53Oa^qiH zVMlkRa?j$WJ<N7@n#3WhsWPk!Pt%qOzi;gpIx&7^R6D@iCKvqC?hZm;CnN1u8!r60 z$v$3j$KvJ}LycFEWjya&eo*_16Z#e%-fbX1Hq0*_(B1oO1C@i9rT8H})Gav3eC2{v zINo~W$p%*Tg4!wamr{A9>MGyEQ})W7egphulXZ2{9(3pxVmB*omg{GrlG<1(#^KR` zNR}pfx0aB=uM&|G+*gxu%InR2(1BQWn@^Cn7Gf_*p32~J^^uVIa$1duD<f%dK|o(7 zNmThH>YB9r5r*P??~L$86)Y?`(7n?}`HAo?To4)VJ>*mVB>Rr6=!H{(EPu8AjE#ug zgLib78-9_%<_^KD!x>jZLWFI|x^RnNr^HRgKM#x-lYoMtFt11;9*;0mBI!JWKX)`x zyjgVYrlg?m=5h{J8K*EVOMv<*mP}8GpkGfw^Ym=C@wJsH^301J$Tb$pde1L6!gL>D zzLYcrM5U4n784iBiao8oL%)1yXOnYa8k%O>!rnIt$|P&!n3z`D;+~!^+`>LFNy`jP z-+?yIqKr;8BjN)FJF~mzJ7_lVUuO?(sbB`&?^@L8uCMX9Fecw5#?pUF3(GocNjjHN zF2>fObF~mGVDFxnn+~pyN{OU5l(sS**4`^}x2saF9O2Y|RwFXFuzp-yo5r{ddi?#u zX5l0<H&#kcmWTn5fXoNp7A<wX|N1?>+DBS3>yFoVe9g;oNrVT7VMJJeDY=KFo0L|G zbj10&MXf+iVj$)KEbPS2O5F_~xi0Uhm~V{Gh-7$#xCNpp90C-FC;kp~d*K&sGz<so zC09S^A<D5HZ14`nLQ<iNiNHif@W?AiY64z4qNbSrB+78kYQsHm+Y*Evl(Dc_g+RmR zc$hFPYw-%?MCyDNY7-RkV~>;MVNomY3g^<G#7n2Zlg%URW-gM>oM(Lp_cXFW?W*rJ zM^tDu{}duljC~*S$Ln)Oil~Oa$@O1EVcr6c?(o$DGaHYEZNe=I@$Nf`?gTl{H#uDx zx%q0GIKh2_*Qwc#a6KJsx+`CBF<HSR$@6jPvGDoKPN~!1W8-ri=GsgVN2h<UL@XiU zm+%pim$EH>S1IGJOs7d6-DJBe?*g>F%wO~VsgvdQ5KA*$7J>_yXQ@Q$5<o$?%&F9G ztg8)Lu!z6QD}zW-Y$2^?2(qi;A2ZAiC7;aVkAE-zDl&4A4SX`!_&A)hWfQP%*AO;W zzODIojP|_xTe9M{&G2on)!`pQzA7(?e{qZ?emCIrIFMp2cIKBPUX-9udM`xgBE?AS zLYN9MctH}sGH-!{JiWlSB~IMY{h3=!)kDO4FUy@i6#+aSBj4*DVbA^q?$Yh6e2Wu% ze2IM1CG&7XX4wTh&!*IP{KD^6>X-WZQ<DmU&AO)#gv+o;1d7eDR|x7g<rj-}R|c3% zzn2K=HQ^_Rb%y~s3yhT=o=Xy*Q`m~4SL*5qEvN1d0vq@c2mh$K)B*lys1E|@&icaL zN!SgyhsZ}}7XCL2W{4zFFe;h=5{c%7x+Z!H>AiV{0a{vm1%FS;2TUtBOfW`W%MNYP z%(MGUeRP6^9#G}Q)qHr$`RreM0MHhyH-I}9_tuTS%ll`&M?cN1pj{Kl5hq70lxyx1 z_6a)x`@$19B&&~L?BCI5C_(JM_+Z}VJ=96#Kuhr%OMUFCfN(n;jFUt=RF0wcBlt!= zHfq1jJWyUR89S(|5KRJrRsr<qI20Q+7d5FyQ~2rIg$FLZ`gI~0nN2HJ>&Eq_X_G<L ztq)wU+#_;)4Y~n1GYHj0sS9PDf?E=NJTe7r$WM8HJc>I*5TAlRITSYxy-$X*LLvZN zPIRf)y!s$VZX!ESb<+icF+Bf2xuMYU3arq<GRH#lOIr8XaWG_adOpJl>`DPDA2Gej zbu&g9rugYh5*uC)_XY_jjP0)+M_Wwe?xu;BquqIFSwAXnGG~mVOYSjq!2>MF1DAK8 z<6|At0B`6=RCkYtapiq<JAu>=Rk{PU(m#no=@C#{ES>~~ecdOx=(>B)x4~6^UY=|H z3^u`7-FqoY0_znJ3d-K4Us*mw@R^kQN=zoC;(0$&cbL_b|3C_JZ5qxw*=8>QLy>gm zLk`^Ty_l1BDw3U+W`Cl75=<XWEsdN0erD}5lr|~V2co0(M2xTn>+I^if*`jsAelJF z2xxrnLr#g<(Grqx2<6UMo6{^=V=7OfI*|!W&fAk7>!U;uZPcfn@u%d5Lsj_M>^Ni) zbCf_E#M_r6o@ICN=UYtcDN4sT#SWx=kkvo$?duE~o0LGPC&ne%Tfd=>jk9hzi&Inb zSb3@1%{2%kk%+`#8`7Qr_lQNyXbW7D;F+7~eFHDO$RRyRyZj;S>Cq(z&GT6vl|eu* z*W9@}V3X4?8_?UoTW;)f3DbEx{|QMtdPE_~;yw{=SD-X`A`@EK7s6|Ih&eVaMa??J zWSs`~<L8UW#&&-SL)hONM2+}~^(}OG+y4Q2Y7u}<j*V-;L!@#eE5IW+N?*>kmj=!( zy(n52kps8a3p%X3h#nf!gHZM~K1kmfKJW=Yb?}Q1{1*YXhCw8M9J%S*GF;+VW{aLc zn!^U|7^|Uh8vU)skcO>fN7TMa%BVnhqz67TLeIQ+JQt?07PK<8U`n}cN}eoG|H9sY zv1La=I4rHso(H)AHdmG>EKtub@$W^RwX4M6&Yb{R`%u~Prl~5~fKe5CWJxGfFUl*} zJZ{Ta%`sw_DuXISkN0$jfZZ3a4P1G#WiSY4gaN7xLirPVeXkMKyEM(}zYe;U3Of+a z5p_w==$;kikCcQyL4rZp6KVNidvnU*J3^jf<wlAv*B_{O#1-fp8o>%ERHX=%b?0#{ zv7Rq|wTp6cs##}ffoO2*j~L(C7F{)ldW#o+QlI3kcO4A|$zeA<gx=gT9snu(-Z=vf zdtR&v^2Kh^j~yVSdGn)w4W-8aIzmi0#^BS8`nVnRiB-jzSc-V#gdA#?Xr?jJAfwX> zeZ#4rqCEO!lvcf&$08y}p3S-;my;18c{cayaNs!z0x)`%Jeg+{EPGBs9?)tgeHfrx z27OY{Z7Y7M7<Z6BH+pCGwKxIqDmhH;-KqoLqimjtku{?mfyB>)O=qEcV7wr!drWpf z(c3|@>9Ttv)`XtpMGMhMkvB-79T<)F1@gxxQwS%X66^`r=;ChBE%}FhMwDnjbNRQ9 z1r|h(fLknoV4CPsRW`Xr7}rk%EGp7cK4ATrp?54a-iho86usRM-og`VvGcXXeHy|% zWv<AkmuI|A5zO{|sHS_{IEi-S<@{T$;f{_rADCV(xs=Z0+I`qF<anC~1S{5vmo=`d z#$0hhoo@AzuDQNNd#vZ4>M3;yJ_$rZ@Pt^ufg|oqkI?9ZuzLPj-kZ*a)(Y_T$cnlH zJ@3u#%YFvaZ-6Q`!a&|bGfIKF|HY6U`17!eW$ufzfWAua8lFAqdxMCA7O_(qVt+e8 z$XFxYXgkbQpLR4(N^7bxD?90ek|J;50v>w=vcPc{Gk0H__NpZPSuVQF3UoD^kDb*d zSFR%jGOKW>b-&9DG7hmDT6}vi>N2<Kd6Z2Eci`l~t!8p{ic9n+eL&b^_f;Sm(C#Tf zu^|@ARmU4YBjOxmtC05|NRlMO=(<BpO%@%GZU09Vd|O?V42nMf=PhxFFaBJsxY<K* za64ER$#J)&G$-epIYnaD&0{97G%ja+#MR?Y3&;b}a0Lvlq>HZD6pDxE=}MeWY;Rff zJ(^-ygXRkssD>9XyBSo=w$BeR{ig;&&Ag;uC20V1T&D5wWxEx+ml#}MhCr-lIeLf` zC|uu$K&+J$UGZr{KjEm3JdX?RCRhwmU5x1J;$f)-2B--ckM<Mr+5Fi$zZ@G6PoT)N zC;lM-@bFS}ph&1bQuH>=g#H=HpF<Ep$7(KfZGjBHTX80Z<cc|(>3)d?E$W1mL*#PI zQVFPfX^p7JqGC0oWrINFSeXUJE;Wr9sv@X)GM0m4MW**+)ukd<Xh|x&$|guxN!~6E zjlkSETB#$FEu0sEEt%p2Tj7qa=*FinAzfYO#|33_H@qDVDOICTYSU#(WtEAif*<>E z*UZE}%T|<3{{oIQHdwAoi^1|{S6`8vK~!e_Gxx!RykhjhTO<1$O2INGa%lM^AF-3- zOTwt#Yy3K79>NgCGy4es4X~HPK^D_X$G_7IYnQJ*#*O6#L*}^p2RKG&v&H7Tx%JdP ze#<<uyH?Y3Lw`+cy&B{CPm)9!A;^}`_9qCwymsmjfD3zn+M^qM^zr-w>KSnO@^);N zkv^>I6hTFzxa5UGb^)udmpl4v&b3xdg)g=N__iRcM(&NBQB;{H(}Aff-Wh}%DUm~J zXTXB9`KDV}%lh(ck&h9PqocS%K}nbQMJfcl^k^HGQdQxrX;qbubp)3u*iX{LsVqoC zW5-oL!X1-NmJ%?yCr+`{ukqXMn<A&p+#b_X$=kkM7MqnbK<J?Np||noaer9!*1;%i zHJ2UbF&Tw_Jp{Ej9`^1qVPC#989@mfc<rn3<1gWTYj%<KC#(aFj=7A?;&wnkZqd?a zX{Y1}wm@c*--)(>zIc%W@wI6w$x&UfNs(Zx#0|r+`k6wiWOd}oYzb&8{t}Rk)i6>4 zmgdiwudSOmaLao`tFi6u4lndyY@^*Rfqv^#fw(Os+`w3zBc;A%-c5S1PkbwE|4OfC z{kC`fDlC6Xx2KIj_@f#jC(pLZu$tUX8*ew5m+XQ~jz67VHiB<M0%xe?@2?v3v&dgk zVtbtPz2Er2qI;mZn=H_|+~C@OMoH{wk-Sx&SmtLDzhDaZWS>^~j4~Q9){w1_Mt#WR zI`kTT(a8@8X>@qOoavJ2ZxVOoa{i=zFkcT$bwWP4HL1Notz&e3+YeH8x;_}NleK+J z53_qBZz>Uh)r6Q@zi84P9EU-hiAy#GpJ>Fc^ydo}U_Pl^AYeYRJJf(&GB>LJO)J_8 zw#a=bU?}jLd=O3PJC}E#z#BiiY(Q6xJ4zrO^FAC<tC3Cm-S~Uo|C-hPr?>t8x!(W9 zwCZh80_*%`TG{<Ft%Uy1U2lh9h~V$APTAGi%EegR*4aVS+}O(Kzisg1#9i56#@k4* zc_^(mYJ|K3LJ_4Ig|8|giU<R!wUuHY`2NN@W8Z<xrd8`0&@1Rg^u1y<sgC$T?p`q5 z9uvl4`g#fa5EOmpb~eYyw5yNf%vG%Jf3e>BoRK7q63vF~u%wTmqtf=!Rbm-XFxc$I z`;38*plOano#hzQp#C{XfX)w5zV<+$a4S@fV-7|ekf^o(Kb*Y-aAe`S_d7`@wv&!+ z+Y{TiZQHhO+qP|c;)!j}&EEUmd-krn^_}`oRj=+|tKME+_15osu^#+|mD#ZtTqutm zhHKYzZdS=I=V&Ck=q&cM5huX?&qEn8wi+|^#kQQh*|Ln=l6g9&zvsZ*$|@wyijz0S zw<c<dh?Yt<`=C}rVAW|Xeq5Wjpd1Y!!fqP(UIqBOng<n38@vRAT%gM^@D4GY1`%j6 z^`tM4wtj?JICKmR;bzLu<s+y;wU#!DmLQkb>yx^G%<zK8xyK8Ry>hcW*EI6w)fJ<@ zIma7LMpuAG$OAv^(k#v1a(E1)#Jd7{*64k~Mp?MK?PmP)Trmz-n$gK8xGsNxnq-r) z=pXH7#_n3m1B>inloINu{J{b7tOAh_X`?-;8jZFR+-?j;dTH>zUO?YmJ9xL+Mv}}J zz4ub$@LcuwR)n^iRf_0yf(3$Zs?kg%=<*thbVNedpWznGn$+^%(1{3`&v<b;<I^hz z<HFwL#cTmG;h1^ySPX5y^mnKftk<YDxM_nTu<`?9U$B{6qH*24Oaq>HfH{CaRwgbc zqxNn7CTqd*=oPYFdkB-4nFsj{+PAp7N^JS2V9<ZDNC8fkqH%vJ$|Xa0j&buZQVK5V zOQHG^=Rz+u5!^6fwTH)yU}u&71*_?{RqWmsWB1xQN9%CeXeJN-lhYN<l>Qe7tikLq zwR?6XhA-i?osMdxzFZ?L%Nm*(s_H{VVeL5L<*d@<9$vV<=<$ruhKWsO`sM<rp|4T+ zUcgg(n2U$&{8$hymA(SHHFoGL)<10J-!0-lZ3V+Xy7~j~<A*Naj~`6`x3=<ME+P#` zuWuI--*Hd6d*XPe5fbAsF}0tB`Ux0luo(DAPkLxUKN{4&UAj?HCJX71nJq05%_|!f z&6H=MVH;&_c_}}lp<6z;G|p9?y{WD`ohdS|eRn+X8O2G(POhJC4X=2fw>)QEt~s8! z-tWeqeLGUaNW=OmRXfYVEsf;Q3v%tW0ePSe?80c!#-oJlOQrV)It6zM>bVsQ)(xKO zoW=JJkkxYT#gPp!%*noo1wdM4Sd~Wg8fZT1Rq?`s)Bx?KaFB!x4M>*qE}5ge$dKDp zb0>n@R33ulOl7!EGZfK<6JQ(h!pPTAN>Od4F~np;+PiVis{(_Vwi7EGW%s}dEN!KU z%mp(lTNx0C$e@`xtr?|PGFr-m+zPLhNYeXRrLXo0(@ry}RgPC|b=&0Oc3R5gTyYj( zg3ROc4@vat!+Yhg<VcgrH(>PXBi%}`{G@xfhL`FI^!Bn0x|C?itPd_SUCQZKPjuap zRLMishBeYiDr5WP$dLPGq&K|rLoZ0{)HX|_dO_A&W%p7mEwadSl4dO82XOT!@xkwW zRcYFubk}mPNTnMv^c~7ktNqQxlTD+0R<fO|!|jAo99qDrE9WaM`rr8HB1f)kW%u03 z{Vv^_-Q0!tz-yIPT#gH!^)}ff5L!+_3$NY@UzJxnsrASHKYe#%?DSL^mXNP(x!7w{ zMasd0{wGs$d}z=^N?(;jLxhQwBhk9ebu1`yufB<-D=n<GkU}Im<AwyE(?B3cS^$VD zU9=m~bVid`Hq~HbPZ@dy3nPGBF9Sl1Z4R<|^vvMwkO?r>20|S@B_IB}b<`9TE9e1B zyq#BexNjT<m4E7Y&1C?)ATx4ibKlMyhMCkr`3C|79bD@Pj&=|~f&YaFK{an3h0VZ~ z@U0pBmJ&`Bc)=F}b8h<#-XmL{alY1gN_{$51ZV-jubDVL09s@qveJa%)=MrE6LNI_ z%g!sDZwXMBcpJ-LJ+psi5mm0>^mD!9+~Sy0B)8Dysj6a_rGX^vBJ$5NO;su^sEDo3 zZmeJw{X-@1c5lBf;4U;%0ye$$SK^-`0fr+C5RHR=IdkAh0t-jyqJBE#85w}y?%btW z3e<3#jG8=7IBW8o<_GLKa4~HBACt0z#!NK;c>4m!mzq}!AFkSu-w5VSS>V9y(=1=o z%l>wXUfUNKU<N;>R21FMD%6!7E6>oyrM0Afhu~s4l^hN-bBdRRh_&Uj0ESg4v(5ck zzR=1~3iK4$@NA<ECQ^vf7@Kn^9-eY2x-Yc}E?HPG;6|v@N>H9~<19cuu)Hsjs{T%i z5h;yV!I5Iu{_Y)7Bjzv*$LoZ)MmCSEg*FJ6crQ)T`bZgivLC6A-iJuX8X#5HSAZ%O z!VXF<bf8lLH|+CB00jqIN|O7L1m==z=O`&K!NFtl;0pTyOJWU^`@mK;N_iHf?1N!n zIgA$#+L4uSXJvb9CBMxQ%h%yuHKeiH_r4$h2(+!$P?Lhsw#$ax5@l_pgAA#U69VWu z2qP>`SjZAX+4PB@hgEng+f!&+ho+K;Rg0f+#+hc6$>-u}p+#aDAkdhJhNz7Gn*Oov zF{)6Rt+U>hx1NTVSXuUtZSr$4+Fu$P#4>#-f)bm9{Z`pSrC8P81fNbXV|7wPw40gM z8|Ms`2(`q{A63~<(cIF~AF!s^Ux%vV&Jop9f@*O5l)><wzicrCCj!VD-H^*8$iWV# zf~xE*_2qP$PL*t0f%sd&joXLtq*Yl<xM)7Ev0Tl8Q{_1tfLU$1D$r9DotH}nO<1po z4L*?cTZG>9*YQ}!VrQshB4ia-tWrzU&w=Pi#FG9{f_bEHbrZ>c?OAA-iVp~}8K@>9 z5ZF49rfKapKuU``QWWT(dh(tf@l`65!9sQCn)5VJqoLv&(GkEC`nYt6D<d#JE=qTt zY)MKe&#q9{BJtAJ9MXCv_Pe+UL#3syGhSALj|Y1l0|T&!)8>V^l?a()5*85)i)Nuu zfV&4=NFj@w6e-%wwWTv$;~kTSxE+enpCaZdc?8PK?<Y>zMqQVzWRTn5kxu7wXQpBx zvf1)FIUZuddtNY@mGG79S*S5WQQ@Hni-|46E+g>kmttzNoB}Io-jUsvmWhKp{SYl_ zt7!;PNh-_Jzn2iq7`&fJqimptst0LH=^tB0(`qhi-&<rS{w~l{#{>Ow;)6iq(1Qyp z65EeMSL*i!;j?+1RGiJEgu@TnB)WA5dI@sO=4+V|v$XRd{a8bVeZh*Jml}kkNrqKY zZYySq$p`Xn%=wlXd6?#!!bfP53dWk=iNkz(WSP5$jB^mvKRYT<IK;7hn1)Yh8~ec4 zv60GI1VE8M96k#FD$NT)KCr?fnt!|-6SmN^O%lsmo9?f}4NnEbI%wmN6|j@kAYp1Z z%Fsx&s7_HW9z#{E?&>B1ME!zB+yT}k;(!3nT=DPbLEE8DRad8@^JV&aN5NQ?Yj?x~ z0N1ab*dL7eACY!r>;&W5=8^qMD2F9r;&7oED6S=-Co8+|z|D$Dqy);Q3}0{~#H+QZ zh+QnpzFIAdwpltM?NBe&c8U}MC%!^_!%7f{{yS5cM*6^)IR7I56)MuYU=83KDP-=* zuIV4ZBP|c4|6pfquX!ww68X$DrYyci{wNxe9pBGwaMM7W9ott&d1x@Qi~BwQ!r_C9 zSd<&N;H)@(g`-oXMrZax*jqF|`T(h@{<q9k`;-jNnwCV^O+Df!f?CHoV?`FUvlp?C z?TxMXSW(Ehcm3I`ZSIA|2WNC?-d%PzP~7F)TQTAxc)<2b6TS1t*W63)TZ_8$(`5BN zSwO)DK6T+s{`BdIK)h>~xq)g|DOkXt)VGXrV`&41N!>ryTn-PCt7|Nad7#TZ#t(x= zjt83#FaH+&BYz~ATj?OS?H4QG)pJC#+kAY2uLFu??!NtL(bxRRBMOP|YZ67FCtAV$ zaTY=3lu)Wo$C+50_`&Rp<NA@wgci0AUW`@H^kJm-E5z#t!pOW*{w?}P@x<Si7pgV5 zz(u3IxZpW8<I)k`dp5wP|3N>u+=1;Y9{_Lv`Y_Ia3{Jt+AK*Ki4S+w`1H_I5Kp<5? z5}-)01@RzWcaV`+*qI5S%9JGdtV^Jp17hP5Hx~;{L9YUa*I)*U!<}#=R?I8rnD<KF zmE#Gx^jc2;Uh0P=BjQG16?H1b7l&Ih{786UjwE#mQbh(C#{aIyv72m;yO0g=m1Ls~ z7c#xrE0#`Rwuc)Si+ms(-bFiLDem%xBI`ZJZEjAeUHc@NKUZ(vnMv9QZOauX@&J}` z5I)eil*4N^DM8eRF7HiW71?LU9EcY8pGAYV@wZpfS~3R4zb>azC>o})izC)6Sy}!w z8Qn@RJV2Hxbr{uH=)-f2n|XIDM*0|zUI^0{nUEWIIGlIBJeGKJB`}V;y^{d2%TgL( zZ5gPjA2S6<RVmh^5_VKsrmd*0%I3h@Yw3M8o;?c2U4)ALLKKZyyvA-_rOjUOCG2)x zM=_j+8RaOi+mTfqpMlosNm>p3?J3+FZ$zSEq-?!ik?y?g+$@^==ITi}S*f8^D#=o7 zb2}gmcB;&x+#GpsN+*!<v{Rm@FK!)?g=VRZ%yb>~dw>@g5!zHDx|<>g=W#RJK7Fu1 z$>LY8ZB!ebK1cc;|0jK5k)>aF_gou9NwA$89fM7L8~JRgr5^Z+KFG02D^_RB&)_Ls za>K=MaUySqgA6s)8V0;ctKfSQywfS=H@4!CU%Kd{ytUChxqV8Bkx6x{hH02?QD0Z^ z7k@y~x(STD%+E@4P<Iv#$KjCz6(TA|5qcj-)E7pLxsEpRN@A`Z7eSF2I+h|<A{n#+ z9DuOeND<b3C7C}eboSjkp47(NJk}e6YrJ>@oi0(@wA<7rTfDhUyWP?L&0i~WUiu4E z;xd$pep1h$>zCRUCu4XhDZ~mNgFbwNB_R)dA1|BEZTfBLR+wBJbvI!<ObhyP70t<( z2D{OfCwn_P?`Q!r`J``<kZ%;(!T{KOYbO#0ZIa%~h2<p4%~L>SH^`-B;s)1z4{f<O z&juTD^WR_VcQn9uEnYEm=h{xtXN^aK0XjP|w?BJ26aQ@cvpUE${Vi*Ko)c@3=eh(n z!K1g|wJHODe@d8EZ3?~U+2=XDNxmRJB|pY_tNP^B2A`Oue{+y1q#_4-gZ+`pKX)m6 za*OFy7I?MN%L!lNiBESv*Bz&JGUpwq4&>!`#YW=x!<wUUVO7R_xu>Au^Um{<C#ffw znPa9qlrhP?hfiUo8&xxTCSO%vrpF34yDm2_tu|+6<+X>-7v8<7j8%I{zo=kK+$D_} z-UJ)!{#CDs0>O}TDh0t6<>wny6iF|lYDU1OIpt^Y7t~(Jg4vty15}upnjGsp?#~AV zdK;vjMe<}^lP@%tx^Y(mm=GCrGJP|&BJuOQDq{qdZOQdz9A>?Bor!V^3o=`p2>&D2 zq`-+wa`03xxj!kD<e^Di48y-=+>Om!I<=2zi>bFWucSB2oen!tY(27NU5-08D0;O( z{<JkbXi3Mocy6mE6iT-<t151oo2i$u-J5t*BqfuN?6!j1#m|5J{Rm&Y%?#KPA=HW1 zkUrzmTiRL~-8%4Sq8qrDkAg3(#tk`M)~3h1_&u6S7Tq~q<@lE87^P0fa9&LcdxJjf zGFN9TF|GrU&zUFH^L>Yt=uM2_j|6+O(rN8TRBDdC&~fF8rk=eq@kqJcZRIjsYS@Yb zVfLUy)g%9l3{qQcB|ep7$y9dht<!2K3T)06&qk((O{J;2BW`HqT|R5hXm+6MBDcqw zJ6cTiw4fFq`Oba1;zyb*+6b8R#%*0LyLD%*8gUw5D?FoQcPxf$hf@p-fV=Y#wrC(v zXrs;@)t_#D<xctakUV>q_v~E(+FQXSHt7sdI<1GJ)JZ{bqDvOj5*0vPZ<{{<EjlWG z;<2q0$W^AqnJUPMQN^m`lARl+BxSU9-g2sviLYsi%$h~6S^8Uibkc*r#>BD|d4i`M z_XR1$ldH^1y++hyK_`PaG|6esNbhMOyn&@Fa3a-t4&~)x>B9U{i6FbKAX{cba`BpK zW_nFFIUvPG`nW}~F~XJ10GTd-*l!b276ICCT$mXUv!>{Gq8L=ihTHFeH1ON$=h%7} zt8<ueBx2}Cn1FN`m%c}u0R#)y2_Cx{?(yo0xKD1*e(VY6S3u5@;6v9~5&G~i5Amq{ zRUyc3+L8q<1F&uinf%rv1rN=tg200K->A|LJ!bjvLQ%W}EnjL`qPY=~r%d(~-UKa+ zsrwpl5*G!v!`2VgYodP<aUQbWB6`qg>B9r3_IXr>(5;Yl>jm{yP_arWY+NXCSCX_` zs9v+mql{w}rq(Bzar2~1YZ-IFDOtGH%8#{-DUK;h?R$`p^e0qs^Rq^YlA+y`?mTg; zwT3|_oVi8X<3}kw+r-)<Ba=JZg<io^DQEB9j!1IKyrzv=OM2Ioc;!c&d}1W@p@Y9< zVimxA6aDmJ`$?S&f-9TzlF^pT_-W9ZmIG*8@-ESuCIg<-=M>SL<^p=eenDx*Z3Z~d zm{oyFH|D*fDcSNPLN^?K*L2OpL31hu{hSWSY0c|2qjs5(J|y7#!wn`@Sa-+efnA!T z`3e~A;*IgC$P$#DOH2~KPkMhqX41yB`4e7Fu`{puAe$AzF_HSf{8X8zb%g8@k^@@0 zH{tn!jgN&&ZaaVPccE0&B|!JXVb1M{!vir+A~A{Vl;oF8Mh&+VU7#pnTIEZkcCPZU zK}IidFmU%KuIG1fHgha<vX0`ZbJh@L_xu50<pZfh+;y2yaq9~g98%|YcHGXrVB(>h z-H`etz!jK%0Wu=X53_|RGk;+-t`-?`D4sDd3%fOg_t#*r4D~kR<Pi$a%MP8k)gSD2 zkdV{UbdaVd0uGy2k1!E~sn(yGe;#G$VI=<g@2Oc5sehtJxyAivKoZW^XXEhyy8zSC zJS^sI1eL66LU*@eG;(mm$(_8K0KI&7P63_#S0f|JV$zwpXXxCl6jQRBb<?8Oo2(gC zTx>?6y8>PG()f>GHLK0JSNRZ=2rJ6N#^H^$IQ7Uy9x{?q2<ezu6}Y1`r8V<*rA~NY zd9)S&g2;h!BYv_Uu3%qNb;}Iv9kHanPW^uKa`LWRJa||ES*!fS=t{1zOpc&UjwDE1 z#GM<j^gf_smosA$`UHhHSmr3WDFS^Spd$gKBSWAgj`)RWy{r77__WyG6;iV=vM~eH z5ua&B=XJoLBTMHHro-=Y&pOgG%kUO-;4#pJ1m_Obu;Gdbp%gKf{(#$EOSYk_!SOd$ zW#(`3RU0t$6M?s1Zh+G(4v*8Cou!+gs~uO%477)y{RyNqqOlVpVfovW8#ESwacmm@ z^d<WfLh-H9u~Un2=Vgp7!!l_vdxmNl^n3!x$Ki)|2L{R86@hjfH!|)vKU3<_WwClE zms!itKR?nssp)*_rq3B|TDl@`)RSiUN`ZMpV-6ghk3=yZXoSfYOW#N&1#(YagF+uV z0~4;DfIm6L{ov=<Km+bv8aqyWDmFxHbmxI8C~Zn#JN+?i2tz>Z8-$c>iDHG6S`}gK znmZF6qd1Guh2ayJJo&NO>n>%@OM|sBLyHH*PKmuZ%Dq61Z&?9TstaO05hHiYN+X-* zK)Q)ex|-JIO#sU$TkYcI2UPEBENd2T!JU8_B^%E5Ms5&J`=pHr(6?BLP^F(L!{Wv- zvCU^goG#am>fUN{Z#u_|;kkle+x1`9jwX(X@B+Bw_soL|88+oE8b$yKTX@@2k42eu zNUr9^{X(`y+O$)&yPIm}Fxx^zFRtjlZRYsvB0!HM+u|=l@=2-Ebdv;9j+~2}DJyd% z{W6+p2E@P8hQxKO&{WfXca7=g4@mcS=l$BA;?|H4nrDN~`%Bv^&0K<4+&!5WUhr4L z&!m?ku_TG1sGsHiF^-pzDLwdyt?Y@T<9(7iV6PEH(Qz0=!NKJzczF~iMht4>kVEjK z<ve2s3}R$a2Xa1FOpvMZbI*|}W3A8g5jjh^i{<7c?1>r7zcP$}=#vw{$|*)YYMfHZ z=>I5!Wxvw?@WKPLv-d~<3Ys~%0W&LIRKVJOTmsXRX7eMyV1;Dkhv}5T7)af8uzq_x z+K_NM_$n)fyG{t)A%dl_Nc~H~M2{xF&+GS>0)b3&b)<x8nm(O1Lz8rLjj>}`B0|ye z16$=CSmm8D+%RUCVYDe@$UD!o3x^`7-k*3>D)E53>5;GS*?*mq$L*1R{aL(nzu}}) zDp5R(UsvG~!<M+M4`XCfT)(Tvuj-rt`_PZhd|*8k7jlvxerACtRbPWPo*m%5ezK?t zjhi=_U^s!qWSz0RSi%E(8>ej)FKI*unPB|=!eo|27Xm0T!ETU<rO<}agWjG6z%YZp zCYzrDht+9xD098m76F-6^FLJ5GRndB6a?9|)EG)0?iIw#f(*+6NJGe~#r#S1{F@0u zOZ>DAP}2-}iYliDrC!0}qrnZS$az`?YH3PsLG8B?ZGwM?`p5Zl>TT>XOr@3&3%xF= zYC70rI*@m+UNv79^^@ql2RVq=6t<c1u~0TG#|WM3VHGc@Tog7-+ApUpLB&h|OvnYX zhnzuOG$TF}kQW!;C#FPOH0P!rQP2x=&>D`0jtz|1V{7LYQZ*<j9ukra5AUvGV;J{P zi@rW89-97OIhvN^n6<%7<j4)p@KLS^MJ|H9<EbshsZ0be<w0aW%9SWeyEx%!=RG<^ z^pc7gx0oHLQk20RFI13v+FCGlpg%gC*V2>e>5qCwWgpJ0A?|d5j=3!XnEM-i&O2_i z0!Wl8Sy}(G-brB2D{NA<O;45D)^9DSZNe5sL?@B54uZ7Inc0I$BbY8Q_i1O=4`_@+ z-9yag*?UpjjZ_pTCb)!=?vCZaeIDjUsO`<xR5DGuCG%__uy)yX!~Lq7>sbDNe$G5Z zmjJ^s#VC~D{Ni(ela(~4nGs)vflb*k2nMqe{}U#Jrr~^4gm%$!o>szuZQO{=jrv_G zG=pZ=X2~3aWc~{NUBqZphSeUHV>qU0k#3q%9e{4na7Z_g38h6I6DXT{$Da5B^(mig z)<!pb0OdYX-DAWz{BxfpgGPHgN6NN9%AToUxrVr8(4E^W(#b49s=>Kr;Tl+vBR-Z* zEh4;c?_>9)tBN5fyG>H%(3s*HpVvy6^PW4Ji$W1xi)$PR-`C7AecEzUW}SDIT@b^4 z`|QK5%!{zsFKRLX=Gb(vRqENSAfH#9NgQw8Djn)>bphdIC2i}-+$wz|#E6_9uPa)< z#->nfTQq;?%&Jh4yQcH9St6ar77Lc*cEb)@O3kjGn7O(79;cSZ*R%luY~l6OxT~eo z&QE{gmb7^W{<`kt@LPD2brYQL)Gv2S8rL2k7U7wY^tb5i{*V3rPbGZZJcV0)X%TG# z-2CMIYZRnd1to5g%%KCP9Jc@;s+<C<A*Lp6Zpqe&W3yN{|0`6wMWTIW52Y?~*@)H? z^IKLPx-a4Du)v3Kx7;rp-aMIGg3aO53$$GO9QwO>_Zw}z8RG+$G?C|f$hXlnvhs*Y zH>A8$b2!-*&-$5gZy>V(`&VG60_RtNaC)d+AI^aLBMmIZ*|h5)uHIs&TO8UXtr<aw z9s=716^A>N9E-Po=(WYWru0qzTjQQCuOj^FqZTf6!5V8m>m<B<*5pmcOZbKQhQ@5x z)Xm2kt#_Y|f|G6bSX_LTRf17x64*DALEen5C*X-zJju~D=y6j#NyQ7^3>&%v^``@B zNh$wC>A_2NALGnPR3opB^hvV4lxa?8?N!vcSJY|gBdu|!JUL#}ep0ppyeP4eoq6hH z)BTn``#b7M$w_%hU^w01yb2vz^6&&r_~Vc`+?!4U;IpS!L3!+KdqEIXBD{G6^zULt zq~=4q%Y@|sVrR3QrSi=NC3Rge=m+<<FV{KDN$xWp&U@MoyU?o&G-$3X9d2EC7qZ1! zc_PgMcE<Z$f<<<$M~<@A0$y}yiZk6j+~7CvCElf8A?>I)uchEJ-{3dkrCt$lg0r2x zoandKvg3jth{xeFI({DH$7?xwL2rt)@iO1o4wy&dGSR}Gt-XN&=6O`O)qj;4`*#=G ze>&I3@&@7&ztv_EApWQHD`z_^V>)SPCw&8}Z%Ib;@3a5%JF8sEAj>0UZ^qKlfJ#s( z-&U5HX+nK}{0jTYBCjd-gW+wmnEEoIMYB~C`D@?u1tCLBjQJMGi~JzH)7X46K<UN) zdg`K`$#Ew8_s#oktget#?jPU>e4zl`5b|HK0d=_dcR{IIekP#8fQ<6WWY}q|6Oqg5 zNz;HKDt-`2k!t;N7E8fuW){A6UxB#V0&C5Hf>)f!#Ej~)W(5~xM^P#b$AAD!kMa@? zX+`8i?OCD%rN`>(2q$Q}&k`L<&5P=RdyLJ1mc&t}Y?6ctEE9^#m1P6<NwjDS)K7^% zsTGSADvg%8rlskK7Mrshx#?CTtNi%<E}g}c%w_3mt>bH{VRC^VsEqW#;YPRuJ0Az( zJ?~%F54KUX3@T~sgNcp&QFeE*{N0bYfG0U?SDh?@1V|OJ@=TH+L-I~_NXD}ZgSY<v z#(INoE&stLw@}rURiVas#H#vbBq5`iXAgnxTs~8dGBYKDzyV#oesI9;-9I7^(--jb z38>9NmgK;V_8lMtLEkz0_FD6)E6_=St-+LGBJY_$NpRT~VP1nzzBu_9d<qqP@4zAj z!i-U(uOnh6H#d~tQE1N%0O|tf1r+k`lM(-%75uD=Lp+arAgT-5{2;H2XXOiN<OdY9 zUqFXp9FoyJedQAWE+%6FKYWE+l|-+nWEV*)lvG1zl|myjUpHRc2gYSyiHTq@D+`PO zGH$iUWGM4b&UA~(X83vla_{9h68wS019~jHF0ckR&(aa&T}70zi=LotbNd#s9m+F8 zv6%RNC~5j6uV;~)R0w6izxv1$=U%4pBigvBov^a_^1j-_3bqMil-N18DXl~G$stIV z{Ut0gmh%PUrUioS=8<&U!nx}t>?Yf5+x6y23V6+&453rnRl|J8@OU8tC0}z3p1pEn z%O2}!PFcfgl(UB<%NEhJD4|ZFhWTTgd4gw7jEMDAW^hOPfM_OzYz~7rID{w5r5mP- zLKPsv7QKyYCPkFuT$=B+xHh;x``v&e7z}=yAi8tL_5$|{e9!yOKh@0s-K_r8;Nofw z+E=~}j{Q4Jo9zGO%@#0s`nTwg;3R3sO(m2N-Eoye_;wp?1qqxy^NoEBK&$wx)Mk?n zWLk-MxTM|`VIg}&wMso_ib9VG)L?*jsIrR`+qM&kAoO5>{&WCdAN($S9a)y6b9Gw; zi_YQ6$?w8r@7Zp$ulwE|A8`7}WtclPu>%BJQ#(-QnHm#vt%DodP+_=hd$(M{=s|Go z8b`GSd%@8LU~BKqhbwY93#cgPT5H?ab7|Mo11gMmJy)y02?0jstlc89l~*Oj_`OE1 zRY%#Eu$7*ZTXtr}b%(6drqdT2AGGL+KATS{QZ((`D#KltteYyur#7~oIJNs}*(+Mb z7VnWQM^-b6_IiY>&(nXhvHocH<3~a%&`jzwW#drQ@zaWK)HIqqmuIw`S+{of>gLuc zl0BprS1aE$wcEF;w)GaR>uleFm;@?WT}K>*B`2XnSrli;EnR_Lb6l(QS1X}MXe`!C zF(x6(%ID+L=v3&w45&MINX(qj?L7(^Wy_e$CGSl+pEkzK+0?l>OfqObP^3>i^PW*v zu&wnGjGt_lv8pjBy1I5qTh9N%8h?cI`qSb*%S<1F3KGgtaZut9f1BVBECMTK|3nyy zR05l|XO%LDO$s|@#~#}VM#)~O=WuelaNC%rR$XPa)snH~R4@d>($On_{-P2|=iEg^ zYH56~vf6~xxoDxLy*fxdZIvUUOA>38-T>T*DjUq{9<$Hh?JbQ;$rGFG>#sn|>#sq3 zMX30J8ZIhEnuGsJbV+I_<dt6Zf;h}lbjzUAN9LBJ67%yXb}?$$1qKBLxxyFY5)YDs zv(#L%+?Ju@zI4s)yf_o|f>eu^7gY5JQ-Urp8c*FD1S*hAt^upkR013oCA&;Ec%3`s zA|~sdH_C%Do)|nor@suuoYD#9Pt@^v4?d_jS~L`PPL8#Bm%jNxf*6^-rk^yDa=dm; z&^+U*kL+FLKVItK)8PHxPor!_12a0OE>s1cDvV-5t>E~EZhX%UVuL^GO<xNGWdC9& z=#mKq<QxRl`gr;VT)#RJJV`%@eIY=N2Eq#j+n4vLr!ywssorLws3ifHJJ|12Jb;XT zsNyl9GAiDsaZo9aOfl_2XcbvpF>W*A1b=P2qMRaRz=i6W+#nRewY{5;A<V^&{hA9T zKiN^6;{eKtPQM0mtz$FlIR<M@iD@Y@3T<-nv9mlivz(YGsP2woBR)~A*z=^7x&Y&& zJQd|echZShSCM&?7A7!48xW`3mF^N|=2#wKLG!@69)dJ3l4GT0#-ef})G@<F-w%SJ zNQ#7_8TyvNMeiVwd0Y7VkHD9I9}xa~sQ8Bx9IyoOq|bMdSnzj{7|Z`@s4#Fgw=yzz zpc67TF%kIJcVY(Se@)NHN}93&ev~gT{<s=M+oq?276WLij)13<k)Z-sB#T53_dRnz zpb_d$6IX`QUW>#HR__z|lR`T0Q(JQnlXYex`gm`4CexYM9>+gfOz-E{vAI9))-d>C zFiD(9QuZ<US!0Z=hQwKt)S?N|g>wk@phO++mDp>VsuKgX!BmVeXx38B?I*d8Of-e& zUNHn80x~HYPZ@(IhJQIHabB<#XKEO$QLM`h?jCn-polEnG>47Tw=b(PQCgd?1Q}jT zczjBm_KJ_un2XzH?pb@#o1I4K+U?k2yT>#EGLH<}(>RPF&@VFdFsQ^Ov0F4z_pt9H z#L19JIwe|<oJ<!22kRuV`MK(-_fVv+Is%rqevKD7oI54Qcc7SD#<hOP@tn$c0|uzV zJ4Wf#XOcR(C0cA_<39tfn8)=gvrij(YqP>DN(HdTLx#Is1PNGeQukG4^Q;LY@YbzM zDW8fd`3ue|sV34RT1}OuH;cP=AZyK63)B|tVvYf%^yT_6kgx|5QhUNEbSzy1maz9} zi}aBkV1|8n4Aj4&`r~kd(!Z0Va-l0n>T-MZ4ZyP3PI-kaF3@Za*X^;tZif;{VO6FY zxwe&rP`XRGl!h>P)bXR<!w%rgSjD0Bnd9Z0!Od{sRV={Pm!Pu;nB7UuU8Q=?h|B4; z15PJXAx@e0Bw<e1Z6SQ0+OHC@NqvKA>|&qpF%%%CcK!dZB=R!dyTadwAxJ&4gvFIA zuN%Cf2lWu$odS++a~02Der8F*isF69;eF)lco~G=#Da7o?h?JJ!svqQI{Op-?Qit% zpV#y&hnMxL1ugn;MwI<rG!;_}{l!yI<Kh$l_s2f~|96c46Y%)r#|*b`z{CDmfV2KL z;NNkNUnS@s_K=|Y5$L}t)X+{G<hy=}#YOfjNm1V{l$vu{hg!L2uG577l|Yt12;}R- zGv;pGP76s1x*AO9VA^@kPXCT~%<b*<0a@$IL`hIv7+Esmh(=LaP!lGQt|^|@06vGb zqBr8sCvKe$zAHM<!oj1jdxj}|uQ_<#x}9y`MznY08;NT>beXa7fQfgYa7uO&{U~{G zu!IRNs05(d-diZDDYq^Yl1%=QF<h*0D$+)t;Ea2G+r0A1OygRJ|Dql2{IFZv2kkxV z?@_)>b^>f3DYQ2^%^+;LS_bG>k>l7em@5Zy9-(HckVe=f+f1I$9EL_Rcsqd|tl0-` zw6-5ZI;@6rO4)cv)+AI&>aWVUQ9&%ba!;rVz6i@dW0KxW9_a`zD)Ry*{CpwCnx-uP zzo~a1r~t%Mj)x3>#uQ*|wsIZF_!em^NThDXR74P!C&rz&OYs*{c!$a?yYO(ng72|y zYXE10<s1b2LvFFqheY|?Ta(r&_ep}(-fZ+?o4`)#rSt<B{b8V64d|<23Z-yHHm&!T zFk<f59;WJexLAIPvHkvt=Jb@foi*)gDsTRlqM#uYWR;zNpA=M=TBrmyaPwon^4m!4 zf)HWC%y#n|xwR{@n9K1gN=zd(N--%7TBcHWe1)3Q>J}KviqR&psQLJHVVUO~djYYB zs6FJJF-uT^nKm-G+inVCj5dY4$H0(AYlWd7DAJwE+)HqWd`q{=oC+dc7zxReeiZ}s zaq{C!gO9IK^n;9G2kO=So=c=A5#4j__U~c3|KSkLm{MpdkOgkLo>reh-5ZR11wxsK z(#n<YzhwCS9pL{&yO)yjOX3^tfd3WR?EgYLTWQu7=^O2kon4Dng$iX&`EuZ5D|4Q- zB<6XQL_k%z5^W9`#+rGGc0=cb?AfrSv=B1<7tojd2pe=L*wc@zz3EK0o#$>gTa%~R z9o=4_ivweTI7%`Fh2ji;a5juPs<BIA8L2+~Nsb*!tH!`%k)baykG|gZcUUb~%dz98 zt-U4jewtSlf%|xMfUyV6I$boh&p2%4ruTv2yMWWj;AuzY3UUuc_W-V7^In^GAiVo1 zipVG?j2NdL4#s7CQ^x>{j8W~g$$p|p0j>2Z9>dta!x9!Ki?`~==U^N_P@ou1@M7&0 zDkM3iX?Wdi4(*D=Rue_tnjOaip_Fyr3lLR4&0tpALbGKU>6w#fZe8vG-K^TQ?j#FU z={W+<U(pULC;C2M8<sO0N0lPrnL{{4w$29Gph6u?upqtO+Ro=dA?{sIcur6rBSyLC zBw{1ll~@7$7JaFNngw`Sxl)S}ZT3azIdw{0Ta+8@3F%Z@wgaaEI2kvv&)r~X0$A&Z z^{Cf5LoS0cV3LiKPM>b~<kqyo8eevv&DXJVp~aOg2xRG4gs*8sz{Q9_LNu8pe=RyM zi}{Iob1Jx+OLs3(uRx>|U1!x%Ht78RE;Qph8kWRnU??=1oEzp1-Lx`J3K4sPdKI55 zs>EQI>p*yu#0cFL>LvtJ0%w)cpC?~EJh_9|o`d)SfUrRBQ;I7mf+r9)9bdgS`ecc} zcRa)kn@y+{7|+Z<90E4t^d|#4qsRd@1lr_(;Ly<v<aTBqAD8_XtpASWf5LjGB((gG zaX9cBR_6cPg~tE4&anQL7)S7FX?hqYLLn#b`5`g?<cAAP2~3cW52nZvpGx=HWZin1 zaE{ZynQ&9fjL7111O8GN)wmjIZYF->owmK6ew@CZzW#pyylVTSa!rcRzYDDdEs}z` zK52jvib8>gMrGd(bCgnW13l;PDgDOll(RJS9p(aLa4hHiC4%cLYSS7~@YoRMR?^1w zvSb#40$p%<@vP25g0FKxj=WuGa3B49jiIt^{k_I$XkS!o{9a?M2AN(?dUUU?+afw> zaw=TXcg@0r(PZCC;;vO29*LLME7PV#zA}ZJ<Y*$p6q1~V6}nUsb|LH3pBi-?s+_iD zT}gSkVJw$3VT8sIb@61r_uxAl=NUDeJ0%)vLv^|gY4R84T$E|S=1UaRV30bzI;4u; zN<cP{jeV)JW*o+iA9Y^jQXUsnIE5Lm+qGGEq8QxUVA?$Y+#o1es^5I7*#C6~Rn%#t zFgK&r>H0kmdr!O<%1O7Pjb`{ecQMk(K!OyCVPPy12Cmw7G1U3Dg8iYl)B|f|1`AY< z)!&o(5mL+_X5R5K9BgL+1KzIr$9T>?`$DiN)aFYiM|<`_wNzq*Sq1XQC8Io?+(Xu} zECkY{?iUJt`~c6KQ36`O7-#h)+#Dxb%@TCO>2rENvAfLtRgl-?cv8C?tO>0yk%5e8 zErSv5=dTCLKIhy+`qx0z8^0$<j0Fg(1NrZ{7uW>t0`~xtAkD@SLqA!?S~6`1;Wd0M z6)VdUsC51ok|RAQn)fB2_a$1#%OmwhR<H|o-|&ws%+62rj=uW8yXif<FF1Wmp{D+; z+ztI5e#iZ%(1&G$dARbbTzq5y%(M7+e*cqfKZ!OJlW(%E{x@W^{pSKBq{XUSQVjvY z)=#5JyH1l|I5^G>9a$=Pi12#xvI(bQo5XWZ^%g%o@3tRrH<mGHoi$|6JMZ1jWM=9) z+wqUqzlPwdgYBPp<W%~U^%{LYSD@TtB>a^m!z)720V|kMaz7I~MF}B_uf4Y$G1tgK z#xt&i5uXc)u0{w$zeX{d6tB>>ZN%t3^FSrAVmlbARWK=?`A*b6g1EHxIecnGL#R_d zvtcVSC0j{=CsQt;Lce?>(>50p=ivrz%$Y4d({k?)e_IIoKX7WcX!9D3t$d{DrBz7E zUW|5^K)|^#7AK~6T+b<T@T5KT>#Kmy<XyYxKv>Yi3-Vhy7s*9rKE#B#px9XEJ|oEr z*2_0=5>`aI4AE;+>H@9#NW~-I%lgqZEaC`YGsgxaQ{cg_-@2iI9~z#U5ZJ(bZV*TY zhv0$7ypSuyMN!$7ld~J!t~zS*6^-#lmYugUTb;Ott8$vyX^x`6;4Df^?Kg)=<JjJ) zj54M;Q5%GB=rw&XRBeUz)v-qCpV9g_5O$#jYD-+E%6B@`4o6vV9(bg@4<beewh*pU zfR<VvnKSxRU*-F0=Ft*c!z6~}Bf-pZ@~BaqJC%ajqd5j;m2ML-&Y5MisnYdL-GPow z1#f{e{@H*xnnl)h6^lW}y?}vk(j|psutR@NjL(s!ZZvxS0UzG41O$$|f{Zhkxx?^; z+-|#Sl|#n*$ZMjPSWYXpXR7d$I_P!4bBhQ2f>wP-YpP@L!TEXt#qpfml_s%b^Q(lD zTSiV+PHF{}TUsVJUkDX=In1Q#FWJXGMZy1_*8k*q2g88O9`?tNB<la+G421)R`6dG zH>W{rVK3v1`r4Z6r;H24{X~KR62R{p5P%2@`iTq@BqksO!BDkK`(4X#l9pCdYH7rR zZq@_OZP;uqe}y!IdcH}=x;eUfWz*tZxf!>)bcHJ8YbSGkZ*5!FHR%rXx39_XuD|a+ zJ0H*8&$)%VJU94$99Dq=wAd;3y`b>q^m}2Te2KS?pttN<elpx+k)dw4^mMp;v3wJ= zKKXLDlF&XR2MnO&ZeGAX(L3bq5oAUmD*Z+uG9!sl3pXgeub!B)RAQq{j5*5mu(P+B zvy*Q8{G>WcH%MRj2gaaGH&C^&g;9JIW5bnDI)mqozvbd$+1#gdjk}8bLRyWx3iB|0 z_t<ulZ*u|^y66r-K#gChdSCOSdMV2Kc8os+`ANRUZNDT(dQp}3h<M{-Q9r<Q$J)YT zj}$Re?cdX*sM<fZMw+*L2n_u;4H<3ro+L53+CL>m@LNZXFNh}bnM(9nnB>`{64KTC zInhk@Z=p8QrOxOlf2Q=I=t#w-E1QHvY1pShr5NcWqgok_f9(JCNg0R~-?}zRFLppT z|1gM{Dw&|xHX&nF!|KvW?Oi#zICp$x7;<jo;u<GqvvIJoPk930%2^O`)zu>q6iDox zJcoIB*M?a(tf<8D{;E+ht!?byRNlBcKfQH-m*A1HRdqMl?A=`4yGvb(Kd{&=2#y?6 zuBf$6tmK(ny>PX)=i<q+mYltC^}tZ03S2)pgP|`f<FUglt{h%mqMf<EIxCrI>*-^K z*Pr^@*=Bvu0QPBZtqgC)N55URspYB*+gl2_!6n>cSmU?Uhlb5xS><;^#@g0dt@z4e zP3>J@A8}U%cwfrMMlN3eS>2F!%-fWXNF5^8kM@uuis#;5lDfNRB-uTKj#6f-r`WaH z=~`H);)LqHH;2Lcq7ytOigkT@>gd9OaVF}N%hg!h&@gj~g3Pu_Ej3JT9A)7oWR8V- zM0~Sv;*5GWa%d7MsVQf;h+Gx|s<g*&HE~!H0;{ZMfm6W(ty<CFN*|ZU!mO&9VOP^e zspAZ_HzgI-HmZB`IM92P?>oa8$xg?9jPC~kq5@fjfGq9)aRX){FwLGV_O&~5y~%$z zm?R2hVZj8qi~wFaq`#Uv#J9~x>>6fl1YAv5)TB=Lm}LCH>>!FJ?8<~_g?Z+t2tWqY zE%F~dbkDA=-MMFBpYqZjh{Mz5vdD8f>1J4i?Pn;8)+ud$3|X<zym-e>H=Yv_-ZCbq z39}#K95Av#<bR#kHO*czin32EA-M6*SU5a?ZtXnV_PQ7+`Yi@oT33)OZ90ZYYH{PH zr7bgy<g4l%JBg*%(Y(EkW%u6I<hE!+(z$*5_y)XgU1Me2J35$Ysu0ar6*6Gs=Gi`U z?P_!2DMiJq--z1Hz6ixf_l8i{K%HV8jLv%(LIZR9=rtI3S&So?wunT;kg7TIYBEMW zI$_dam40;Ba~I{2KG;3QxKWYSI&qAHhGDJIpNR&rW=U;rxP^<1Vy!-ujx;uDZ9r17 zXnN%S?ZJB8Hf6T>+I5PZo~)@3nrYeOjB2Yr&Xps|Cu<nbklC7T+m;?yM)~^)c+grH zn}&Hy>ZbzB^&Ro|88HpxmQ>J!!SAE-kj)4+4TIuO$LguGDl3Z0*8TUkIP}!JeJCBR z!ALAOdnP)YgJD{o3zn^Xh+bptCzS8sf6Vus3i+^Y(wR)xD`H!RsHmwEX^L0+Cs!Bj z)h)A+#i1*z!YGc=HfmfmYqW&4Fq5dXq*OO9tb|0EU^g{9D#f96Vn)DBJ$aGSsBA^P zV?;!c{hAzD0}ao|UqPiv!MiLYPE3j1OU@_Qz2gGmy(2`uIb>oPs1YJArp<wWj&{dy zA}VOIHTSQ-6dPJf;gkS;$_KS&;ouMihoCbN#zPAwNO;q|k9b4N(i|{ANjPi%#F|wc z4UP5$ptDZ6D6{5N#K2=cFELX3oqK&6WTtKr$Ygj&^S+I@gFK8(fjS3IjvC@8;Z%a` zm0!NV1bGtXB8OU@@$ixj>nf17PWOP>;xk9Q4TRicfEF*Dk-On?^A_&rjF2diXR55b zQF8NIZ7sId$qQ6B+*-MLt+kcf>lbEe7#~31zSP;v9xg5%L50aqH8tWTuZCqpiw4&` zWnEk$Cl;q|L6)3j4GtxxBU|b7N3}D{xA(RS)jt-8tCjj>%R+{;-@SJYSJ#G`7oG{8 z6Y~(ca=ojxw=68_JwX}9HkpKM18zwI@Xtbf$75y`9%~y?{94QuW0&&ez2=WU&X=yA zwd=k8aG8V-@QN5fvQK~o+4kcG?nODDf6(WL)=*d%-J|3vK%K8rlcX4x&NU_}D!8Nd zArZvG=MA&|RC!=WitTG+5C#Oi=I_rbWA`@T@PCXDjD_meqv8kzRKFmgWPT!$t|?4| zq-iN}hd~Mt^Q(d5XFm5);|S~n-BIgPC6lE6GDe@W8x$C#7|IlBS{G6m@@fosphcv` zZ+H}HiO#8!8@FSf0UBCwe;`IS-N|Q4WIrfO7+QA$v|=95zj6=Zl+x}Sd8v-P?zj1E zka(Pk(0t;RnvN)CoFqV+_moNqV%Q(TF)tMubh<-`g9i<GF-M%da{|U61C~m7%MwXX ziXb`714Jgwu--wcBQ*&kQ;s_Bkb_si<JtY#H@~7zx#*K?s72$t=2emyydlW8Vo{J; z*PhN7OcIcHWgMK)6YSs>ZWTSo!Q=Sfe=~A(1J`MRQ;)*m5&@~nl=1%a?QR@2Dlo}N z9K8zNqKb=UWrDnF_-QcB$q>TzPNZf7L7{M$SF|UGYzrOonPk8lQ{652_lqZy9hLKz z1Ws#$9UW3za**e|*cObxXT81oBC~m^kp5=^ws$b`8E>-u)c~;(J=27m1k8d?fuyH+ zTT?0^&ZUCZx`XsGJl=ktI!&E-Zv&z=%<gi`fTT=snL*4mo%YgrZ{cgLt?B!2Oa*l{ z1S`!$8&Xy0;m#o9o|NL7n1M~H=L<Txw3n!0McFlyndRb{sG!eQ13aO2t;kpIL7u$g zo<QQB!ry;dF6n99)}(6Q=4qA@My81a+PX{MP?}NRX7b~d@*c*3HcjGQQ3mBi`zMds zoF}9Q9{*0TmJ1tN9k|FZ)$_S!PA3+AU7EZ~$TtgX3)DFd;5PsWV0MXRW|?^=GT@zf zk5{;D7U8Nf=$+gA1K9jS1qPs7Y3XI%HnM8o*2%n8LEhFL%0LzS^@u-1w!hUyfFeZj zl@!KDv~MW%L4t@U3a3BCL=uf(vk+eCv`<Ocql2J|c>72c-uUwt7VIbO5@?G#FuL#v z%Tb?IMmX^zby3D0!?02qbs{Wk$twc{cOEo10_{!o$Z@EFwNIU>zBTbm@=!;J+A5MI zGNaTqIaBj6J>OQ*EIeEA_kk7HB9z*ql<4AuvPBc*iME#`-FA#{<tnyuNqkxS-T9HU zmo$3|zbg(Z?gg2*zEuWprsPDLzHx9Y*!?Zi#s%q$z6XbNg=>`Ygk(bxwuQra6%)@C z7~z=-<UHx@OvUVcEYi;-(I$&<l^FDnvd1fZ#w*xXJL=b|IJ%8lb9Ffa(y9Qx<u0$r zN4OFj{-|j18Ku^n*T)mWC>~B=cRdI49COpRZTxHFwWCQnqY0YuKq9?KcUB-FDNxCr zv_#B(EWspSpdyTagI{~2-_G2%vaMuz3HI{O`dL|9XRtdA<S;b3cUUVOeQ9Q(8ivs0 z4_<LLzJNq9`e2b;dYOX3nhboj%VXzALFdTRx=PZpMB(iOxosrQiwejBk)`F3GmC#- z=9F(`R%%Ux>$C_cLwBAOaGpH*M{7kPZNah{|9@OoqdijzI#Zd`SCvMHejn~mc3M+L z9-^!fHmKJoRw{~m!&SAswwGS>+>*gE6Dytbw90#K3;1nF)IF*^7N<g_Xdw`@6a{P! z5>ce0BmqaAAT!8$>eM7*+DFAvFKjV5tN>n<ptVNhyoXzk6)TZxr?e5JT8!I8<bK<} zG%2-^PAv^ZpV^eGEU~%fb*j~((4jUoPMDE-7iJ1y%x&`3Ac!bvsxdUT-fkfvWXjEw zAUEXDjK=M<K+iCalxr77W^_E8QSv1%fzsc!`s<>0+0Zw;L|rjytv8u@lRx8<c-n?+ z8jRw}Rq+BZg5c@-w7!>)`{{bg!HTMVH@(W2xh6-KEj9$+;PcZ=Urji2A4~-LQh<{q zS)R1j-amceMnz%}N0>h=<&K8(CHBy%fj_HXws#uZ6u}zn3ENi*W|=yK6I=ywR>{1y zYF1{8FYJ*ha6mKlooATyKx<L_yqokpG}9{f0m!2m{&8<r!5#eyP2k0u;G+Y<=ObuA z2DvypPbcl^!{;)Xlz^6E-T?-Z5zZ?nvHVMCtF(Iz0EKa-e}>p(OALy1qPu4s{Y3_o zA9!Dh+3F_qCP1&g%t|SKhjiyEcdrUXdbV%H-!{TrG82L|YCag(G)o$afZ_sS)1XQK zdY<=Hy<(MYLdBw)zs@+FV$q`3$U6PUl2x^li8-@;-8@5j)hfe;%#u}|<uB+zTp$0w zZTs&H-9HLII8qnJ{Q&y$Blr9Gu6+E%*1?oc-%j7q%$Uy5*4o<E#*xlS-^P@Q?*HA; ziRn9<3ECPN3%eOwIUD^~>`k!Tq{QGa6rNU%!bj!)=rD5H4kw}18X-mMC2)ogdzN&q z4T?l5anj+h3~0W-SR^uSwKzWz*DL?~HrGGr?+3_zpijUTKi6RANSt!4mC3Ix2ZKJj z)MIR|CiXfRl_yM*ITC{c%O<jCUX)Wg8N9NOSHw%Lb&zC2nnf_uV}m|Ogoa}70osTg zOy-oizu!gQjG|Q>Z6OL$L*4A~kYX}u>ZwI8y1qlZ;9*U9nQ~;?b9V581~muTX}T;Z zm(zk9)c-u|veOAGm?t_Ad~xT_X^-%cBCEvMZL!<GlJNlNA6bGvn(I5;x7Po8&lmMS zUctmV(Q6E`#UDXy@%^WJ>EC<uzx((f{!{9@p#Asn{^j}(xA@*S|Id9aE+lFEUnTFO z6(?;LzkBw;)Nrc__Burrx=A__f=CaXGPWS1j6$qvA^<jnz0f2A8J&;vh)%6hA3W10 zuIv{zg4HW&P#aSW;cbH2%gok+=PZxu$k)@sqUn!S`N!Seu2ASUwSZ`0)D$f(2mADX z-d%ZG49aRApT58_c-O$uZ5~9ERt%VRLp^D*;}+}*tL#0a$Jvf%xWHz_=P=_ElF)s5 z-jfKUP*<X9tWfT=8=(p>7!7sZ5}0L`tP3!&+)!`Cpj$lzc*SWiqLV+2XW_(VylY5A z3j5qx=UHd>O}a2lm6j42Zt?fzpP@~qhx9XVg!#%(VUhYB*|#^ZtUId)C)gNWE?H#x zYf1kPW$zf>d7EvE1{K>jDz<G_Y}>YN+jc6pZM$OIHc#H}eRjWn@45T-`H*k_kujd} zo6Bp>DUn%XqOGLK6TK52VT4Di`XJ|j)IW&aKlTM-lKP<)pS<yMAncK7tj`yF9;QcH zKieNR*zIn<i@A|2=wgwZe?L=|KQL?VA7`Ai%VZ=|+9zvcf!AaH5JMNOyLc*Evw3n^ zciBKjqo7&T#c?>(15Hp8E<J$=)LA}5{EBUh{d4HuZwj#e5%+K>aBg;6N@@=c!~oM? zXh8T*vW&&dYN5N&8)S{E!pE<(vJ~^aLm8X|m1GgCWl=-bJ@~iD#2K*a&o`HmSMI*c zJt~$OUny>v+U@KSo9%{Vo#L%+XgyFRN+;zL&O^<Klq(8KsMY?~oWBhB@6h>oPyuZb zTa<qT%JzF<j{83WmAsLGlf8qPvyr0Bx2l4fwTXhG+kfxQDQRgSi6VRd46LY<>@A%Q z{b;BZ$1h9@|0Am?fM6;_0{`BYW*J=LT%TcW?1tNMa#bpG<uRYJnfsW}o69>k%vetk zq=wfxIe4DNc+_#kZE~3T{&sui1E4uTgjDc6H9#_v+7fvMqbZkBPRb*&GC<``M;~G_ zcG@<#Av^v~uUL~?hzCQ3*)mGEh~n43(FWcYePu;OOIL#u92b7&MDk>q)t-kga&G|r zTW#23AG=?cM#n@<`Mp>dy^<qa6=n?vq2exBGTre{Gej~H+l9wi;kt7hv`U%x48;v> zbF=X1<C;~tl6~t^It{bHuvK_&1L=7z`bDTyH!1M2#h?8u$}wovE62bkP55|Dn*K)3 z2l}m@)plgHsSphfLNd7HCkty<TquoXCD7l&O(tx2EX2VD8qu~H<sFqsSOCW8n{q}R zuFDbpjTPe7U!D;z?n<SebVsrr*1vb#X#nS_%{Ij|9--4*p`2{Dft)$3X$i2-=rvLm z!WJ`=hmFu<H+H{@e&ag@wOU0)8?v?H)$ZO}H)s0r4c2RY?nCt7_$k=4S46mG<MPe* zf=^Vu=;=lXixzR<enl21RtG7JpsUu^M4|xms+H!8eb}<GLN(Wz>mdpQH&d_oY5`lI znyWV3!s2Nx^KJBzo`PPgwZwo)e8leD`gra^D_q@k?bA6w&(dR?LHs`Jvn5Q4AwPd< z2AxI4a!lIKaBgz}D!CBTZ^bBGED#Y7(-EkWmO0Q@55L?#^(gH6<MAzemKGx&+Int= zeoFs*g^L6BQ-r5Vi}40dgIkGP3!M}U&j(u3hc8mZyUlSnm8?tV=^RTi4P394oa<y{ zgJg3fTI6iBWl^85(1!^8xvDMby}zZ_;RE=U6%=1*_~>4gzHEqRN*{XoB%@dh=w~c( z+G@z+d|_HKZNZi84#u+1>OOQOsh6J{LlwScJPHQFatmnD<q6=sG>iD_6!KH7Yjj>o zORO}78(hB(y>{rpf(?2G8ESU_a(~<;uP!PnX~eXxqA>Ox!Ze}qnN*~1*yDI&4`gv^ zHLac!Bbkt#J9Oeb1kaxe<7*7HpAGjQQ%IXB#6ROwC1%}Wb!OA_UoB$Hn&|ioe|6$2 zaB27GFZYjNF_>Akh$NaPzH*$fJjRVYiW|NW*LfkTc}776CY+^6ncWtWAKyyDgGv?R z{wArD)ehUw`8X!O7<3x=<+vJ?nwy_^{0`GL=P4*3_(?5}*2we$`HxM8zuEr3yux4M z{Oaqr%Jh520FDFz!1bSa1qDYvYePMI!~cU*$VysqKvqH?k_jOWG$f@I7qbO!CMGKo z0t5+A0~Zek%z`KOw>2qFa6CSN^=kJ6xXj&+hP2Mz{nTycku^$s2ehv4dM>q5KWHa8 zVCQD-pU9e5H^S}uylg$nd^^ib<J{7EJtPFE@QW$eL%}9;3*Fa?7Zt-Laf{ryi~lJW zosfy|7Qas(Um`9Y&n0+EHR?b-ozTH|OE@Y?Tq34T>K3%G6hBXFBBo8`mbDKP&nmu2 z$S!Fgy>AuoBDP7wE^~`J`bLaL6%2>gFABOKIbR>ht>->xpM}#842n(!I`F0?`r3E% zGY}^gCH9RGx^&%?J$cKZCqH@$0(k6gBhrj-qx2xvfS<+4eUH${pwMnX%0R<!(yr3~ z;4_j0MwR!}eIA1T=NzLk;e~O%t8yRel%oqFimLO_J)$@lCsD^lOU6C-c$)O<T~lkX zue#)AtZ_GWAvTg4<3Q@bUC{~J@Hi)F7%eKYFwBG%qz18x<}~fHTKZXT2$uhxs>8A_ zn*m4H!89BMd&1k#hJE!!YbFrQ1{zC7(=_Mc*D+hvF4S<aL5n~<x)LGXw*WsYxYVwi zb8Ido>k+!&$>$GT^f7l2ai#?8kvJ``1-kw>W=W9>x1Q%Kv+Nv{u;I4BVe37%%64j* zi|caf!i;68AmUM)CFw!HtehB{qkT$ABWuB2DeOPFcG_`=49zN(P5n5i6t7C@j)9f1 z!-^u3Z^lV>R_xR|s-)4VR_WP!2d}Y|Y+c*mQzjRGmu3YAWv`B()~=FM&zO(yW^M+# zs4L57Z<%L@ho-PVZM6iMp;$AWMA;J!reO5ToV2(tPs2RlmW_?Bx&M+>7oE7aMTsZL zYoYq?<Wg{ngA}5c#s!tLjKS5Z?M&K8PNti6=c;5xZd$}4U{$*Jzsps+x4%!xj|P_~ zSZ^2INaUV1WOb6L%%hQkHut5YSA=lt+y1l+<%esP+IJs)h{M8fPFqK{7u**au_AGS ziyYL&vW(%6UuSEDu;(1TAY>J{W^Lu(e~e!fr4go)nkw{GSg;As6t?EQSZz3qbr{9L zKZ?5>1=)v<<Ah#=QGNUJrh``f$O#e#sR3%cUPACW$;Gku&$wyDR56P6mA-%G6}}h} zW95PIRCd$?*c+!iU|BHt1Y#i@-d&p=v=^^IT?~@4!!6^_&*fh!c>zt*v&GSfbWj}R zPL%>va;EMEh`8VLs4b>FpNSur#~HB-Z0`&3P>r?6F^mLR83<53#&54NW&ql^2ATU_ zXFtWqKrM^`Q>zGIQ{5Bsy{C)?L@ks6WAF2~JmgP4#viUd6#6le3$)VbuXu)Eq8dwp zTPOm?9>IJ>$QO(<0uF^Z&(EXB-*k&_hqF&v@xlRQsOYyXHQ>A8o#&@%$bSt=38>}- zc<LB?ReKl$9_z8wb-hgtC0`xzKH(pEhY!OsQmuNY@nZxQgrV1;=@j3m4xiI4mK0~- zrlJ)Y(7qdJWze7M4__n+)d(@%T!r5^Erni#h%Z+zpL0DvHOGhqsv#WQTv-4y{C+Zc zEEvj&HmYG7Y@Hv-%5Xr#3BDjW12!NbvRF8X*%JSdS}YS>ohBFpczig(C>eZ0r)bs8 zB|^UufAO=&z68!bnLl;}K$`N?2sD&^60ChZNUdvZxl`;sxIHP5p|an(iKs&qPx>8I z=wys>5bQ06zb7tWyi$RkYHSk6NHbOFcz|Ykz<Ve@udwd~c`Pv1h!e*MEmi1nfadpm zqw#%&e8oU^>+xBS@qKFX0paWmK;@NzQH*NAV*?=f;i2a8{1O}M@k88VrEv<O_?5r^ z3uP>k-sJ2*i-*7a?SFanzlw*-kr&F^@8aS0dwMMOpLq0t^W?<RHvd@Ome#ZSKjnRu z@zdYc1^hQx-}->~25%w&$$JW0A@=|ZcawmCnZJJ|<qng4s}Pn+lJ&uPexpKIiK)jv zwJ)$3wkrTGB)xNaC@z~~U%ZPmkI&nk>rl7%*E7U6NcNwa&?rpo_3GOyx!wRsT*O6r zvm`Olx#F?o{!JdgP59(Bk&?8T6+U9d*3j_?@B{85rN?+#b8A>|>9t4_J!V<;;QAA> z)h=|BiV84N;|g82BbEFFobtpPg!HQTQ8r|S6;?Upq->#;;q{$|hUBKKP^P5wbC4lv z&l~=M;klSe$1$asu$crLA0~xSRrN2-?U(M6_CONK!RM@BQubrCWvr|LNOlyE={|HE zadtz+>W0QF$y!RD{mep?%^s@$M>`0(9<Kf+flFV%`2^043-ujW^eB$FE>q?`b7YEe zaiQBgrE7ShbviGE`b&L~9l_UF&kt#uUVKJFWK44-Aw^T_K@?v^HX)Uh-I|Bl?JBIi zz^szG^mZh7G<KXoNP4&f_Oc63wRMx2ujZnd*J(VR)>{c1*$$^OtI52w8OK@=y<g8N z7<oOKRj>3q@#W=isF^<hQE2`h5&w>r)S!H_;qU101qlE^_dj7p&{WS}!N|_Z$lAb2 z$<fTx;h(eFC`Btv1toNEX^*#!*2+C;+e%BqnWU&u6+k}-RIngx!SP^!hO4$S<@MDS zXK*3mNpI6WxINy%&|EuAEMOXbIe&C1*@7_4DE<7QXVI@`9sh}=%(WyKbbFu7yG@79 zyRNIdj%jus?bmB)-y*t>(mr=QmThbH0nO#(pkR-EnGC3m{SLLNfrA=hSdD|&SiyEQ zoa4lP7PL#0Yez@xE3>on(`7RJT_BWNOHv&=h9GML+kpm|Yb4t$DU-P%Wk8RXS`EGk zqqkpvV?rDT&XLd$>8%$cSNJMGVU}a)=PdSSFFNWAkiaJ$d<ujaXEyY~Q478+@nf(s z^fKeQaVI*9h*)&?;&-(Oj0p_wkSD$Gn1DLog)a6|x@v5-!^;+AUuKsUyHSi6;LGw8 zoF0c>V19>?1DRClzeU%g^pt9$o*-K0(s&$nj);Kr(iDcV#8btfT<?nGBw<Fhj3@En zReAP)r}@#P+RTig?I!&83aW5ii5<sy1Mz1Jwp>RcLhrY)zsSc=hoCTdEU8a(F5v4M z?H|L4xr)>Q+mROEL+pzbHz2Pqeq&t8#9+KVkJxS!ePlJGKhayd4btS8|2}I^Py6fx zfEhf97Z0G%49eRHOv{U#E=t^)LIs`3Wau0{7o#z1Dk^d{ubvyyS1ZTkFkd0#RVFwQ zg<k_HqX`fzLwrvSq2X<-6~wpS+r8WK=E9%8yf2UgHBD6h(f)4Q8$iRgKWu&fd_(76 zOmcC)VNg86f6+LqnDUcm4ZS<t7)MW1c`EUotKV$Lm8jJPt!@;tw!TkcTBDpx4Xevt zDQK=w0^gx;9+UedPhFF-6PHMd&OyRQtH0lP>a-CxdQ_k#b%e*7Iv<dxOW3!Ex>Us1 z0p`mx6@=C5F?4TIQ*B7i)>&vXge_0g*x}wD6!lt7J(RuSJsBzBkKJQUb)LL0P7USO z>Ii$w0D2jrQ=CE#M5g~n^xk@Hd8jmsUSqhjMOIH`Dim3{cG5E68b}7`PM=kU1FkhK z$%{WfcBTeV4xa}EN?iTSssGO%GWAyVfa)GS9kfXEHdKz_6$C9#kP;ZD>fYZLgK|=l zQtxJz$q`}j_%&gpED2fEnrjkb5U30MJz0iESosZ0gufxRr_Nyld2)=*>!R&XDv8N+ za~mn(<GVm25p+o*N)V$@Bd#MNs2mnSg5zrXNK~^N>l~^`A)9*$nGusqRILMrHDb#0 zH|=STs*H<U&AZzY*Cr|HM^~mvrdF%ACpeQBHR#bfAXUW9>PI*|VJ=CBNI%p2Hsr$r z(Ft5U(p>PC9uwMuD^4K<JmQz(ZaH|Om|cT2u?IvVli4F>`4X_3lI$9i*exj?T3jJR zlx!(rH{u5{BL;@PNM>C~!f4m&!Vst^KzOI*jcUuO5WV6D60Y%@$uupbN^mY77iBl- z7np(w352zmO0(kM+E3~}i*o&z#MiKp2QwDl(eJtj&u#W#r{p>cP9x}afN76CL2}Y0 zlNK5J1cc``UzzjLk|gY{{X1_F%YvXH20@%UHPB_0Xs3|eK)i-3PXi{+=cq}T92S^2 z>=01~brUP2+Z;s~toR`xg}Eok<{G<7SzXal<gu+c2x!&io{pmnu1~c$?0$W;i*6uQ z6C%uJ6-eiyhrXseEtQtv?=5+?<@jS}Jl9?tIrTjOTF-r8N8{uBP#nk{Ahfcw++;he z*|aMW@et0;Th3sZpBo_BB~!m5Q(j{%?qS=U9(B~}%syFkeQxOjY{}<s?WlRi9NhrJ z?)+@};?f?VWeeAl8?bRj>)!kEDO(s5UyQ&bEm>-fC&PRLQsc;@jXK7L(jfq0lsO4m z`qL7dveiOG*-LzB&r;17Gix}q+>BlAf?!>Id@wy{uM@mRobno3Cj}s9?qS3Lhq~JQ z2*~yH=dvbV4j;inE{}7)z<Y$S0NW>jR+Li%h1=Ex-d`o+-$TK_g2Z1XBCPi>Ljh0# zfB`rFfNv(#|L<<3fsOTd$H?Bu+L2a3&%naO-p0w=P~6(g(M-?M%-zWTpE09S#lm4h z5#75k#W-UUh<e7p)=9&9janWMA+HfgGGg!`Un_Q(c{1BtaK4aqMIL^TQ`^V)nZKKU zicT7X{9t#4HSMOnd6qYq@e^>^4tpzMve>M-66#gYL3-0+>W=5?!La+|?QjX8X@>|x z%2i!}QTlp?kD6Qhc9`+~K@DMg@Ves%0`2t^+Dmw!Nx(OuSsd72eI6SmI%=LcTMz<5 zTc8~JyIweY!i;Z<evQyFqH_Pv&v3*cJN1FUP)5Qj$kHoDCQ${)i;7*-;y8tK1VH;7 zJvzz)%BD$6!13k4ek#FP57Jb1$6t~?L+9j1nkQr&>6>}!!RifE#%wqTFdq|`ONxu+ z_(SiE%!0xtru2YPcX*dhDJQ?Ix|Qh?=QbAyADs{Evo;)aizSID+du*ptcF2^7>u){ zX(r7<IW@6y43(uZ7R2Rqn3aTit5h+4o&pg}REdZ<>x-3+WrvWRQsate<>qTR9S6xQ z;Z8S7N{K+msW9EPY$ganVd~?iBa>#I);TR#+L{!drktgYE>UYbdNQ-abBpAy{sdPl z*T3Nm+N*9lor(iOxT}c5k{e{}jbFSd3R!uF_g&V^($k>cFc84w08);fw!Ywqg38eU z+3DR&T=}umivF$FlMRs+bpwF|Y4I+^;Jai3k5>MDacROLZzih*9_xu9%#m(RG#wu` zP_`sF`i5p7m6Ldewj~FvjN^BygkzOC$tFySL0bV0vTXOUBAUp=J4ZM*+ip%js8<BU zC2KWuw3RI9m?awaJkaX$#JE;F!3b3M1!ujoOhPinm<;Q3;H)y#(k`#4q-6Mh!lgv; zkRdE-)QKrG#C(T3gIc95g4J{*sy;-+V=>5qfmI_n)W0kq2Ui$dRqvm#knfPu5t!F8 zK^CmXAujQ}k1a})L@?G?m~sER3AO4F1p`hmB=SL1iZ=(RSFQ{Qqk6X^64+I9z=8o6 zq_JE|iL@hh$*9AR6@-a4`<iew{)S~U&JNHFkn?J4oCmsjPwR9(TWfSS|AH7yEnYoy z>UNZ1vMvjCtk}ca>WtC`r|OOyLk6F6*9!x0TM)4QQVmc`-NB(sqQxyCdaOIWEw75L zfH{_*Qo#@M*oA76tYxEZhz2&=e4xU^uk9Y{Wvgv|RX7>MvYWF%1_AnE^tncV-zixx zoJG%4yTNI~e0sgX_syYyf#euh+*Ne!s{Se<excKSER0%L$@~%a&T$m05I^S?4$b)i z&HOH(b5!yHlyjq8s>XBFx1jj<9c6p<SUJm_fR52*E>9qxKnMFQn0}}WoJ%2(utmnY z8zh8~D-n@6r?|T~>5OUuYB7Oko*H__33(j0Zm2#u+{`bUi@tBpq33O?QDsc_Ll(HZ zA6W+_MfXesCyy53)7vz82sNhNQR-|o&VpvmA(JL+VXg2pgl_6hw@t@pE0RPy5yjPn z3@4POc0or#g#{>u1-P0}SDUz+Qvs6jn)g_tagw2dwC%~0J=)+sq!hZ}JCQ_H;j*4F zeAVrq&8pV6zC-uS3!ae!)S<u+wPp*O(#<ji_Jd1GGDNm<UF*F3I6Nd@o~YLf1y>~^ ztaJRl%%JFj1PgIN?Osqe@Kj*O`>(Y6qUj=Lkai4g-eBW%$kcB5lKzsRkSk1RC2J*d zEq){fzX&i}v9Cob_3z*P*}TJwS|rwsL&up8R;A>hQPRBD4l;>xrS?0eQ%*oDu8oBX z`h2ng9~t`2KK=3Y&t#}dl-f?g!@hd~M?<Lj-S?o$5UCSQI-;F)X`Rt1OEtHsn4qC9 zdsZ$Q)Fd)loQnvuVV;b$pj`#uqOrqphCMM2uSo2lCKY|OJU46zKF}UwUfdTe5neQt z$&kC$fV+xpV8Vv(!sntfXEd)hPvO-m&T|`5jMkxJf&=|yjF-_VaOLZs_`QW!r}Crk z5}7_k$=zV`HF^Hx{p&x-$S(`p*x76j29A`c@RXFK1Gj2%HJicE!Zov_gl98)A(eE4 zBvj+TVG%?|o)-1CGzdOd_T0`&Q#$9UD{!~nT8&{H@|^sPZ})*F3kwg(UmxD8R<2eM z3-;ALaGoar)UxZ!RrKYjhG0L|IItZ?50hVNR`Y%3W{}kj{PQ;J??LHb;p(sYm%ngi zXXv~B4ga2X2>plQO7OoUm%Nj;<F}Ob_ps8)*3rzy`kyhYC|>LPMgTc@>!b;pMHmv2 z(EB<|m%y??MP7gj1#xl+%5M{{zYu3Ri=@8(6prC$462$=`x*FME|75^6k-NyZ!$B+ zYuaHdbA=b}`%=p_><>JVEA}o#Hpf*O=V7^OseW8uwq$|pTpX!N8jt5wvR|hOx{V1( zv*sGC45Zr2tCS~RWj8p6NK=xsa|nT|$EF@xbG^YR9RejaFY-wo6WBXh-h^T%M4!FC z0+(2_mCONj_1=Udk@t|Wj0mBm!YK-grb`C0nH)M%W7Mk3<*<N8(%1&AK(<<X-5^~% zYR<LHx{5FucY>EQj=FVW__nb0Wbu_E9aB}xrAC2cGcz)3q1%$yp)!bIOAd<22={?C z3$N#@l!}HR%$^d}pYK5e+PcdybpO;>rN7?gm1#3C%U6`Qsgl5z!p~N=q~Rq#EWt-F z6V!;(8D7vC$5Q>ob97;nKyX>-jNA$CF{V+5x}+iYWjNZjTt;Fj%XlV%tPXXZK=EI0 zWL7o+u7VOJI2ILOLMPb0QX`b7T?Yh=UONE09bl=CA164VEvbi4npOs0{dZ%mZtaTA zM{ZDF2Pm`yf)lU&f-*F5Un45hT0noLIe$mTzvHI(J@qyGyJunw1^}S=AL2&X`8(MW z{7!Qm1<mXYoXi{r?2Ys+zJ(6HyX21ltwk<lYxG|@s#KDaLFR||;^rK$*u&TH$Men4 zy`;f|^2Y=wI4*<uG5e#hSA(&kok$Sw<b)*knX$w5VOJPV8~<h-?po(rH1ZE46nI35 zUP5J6ncIi<!@|NuH7~C>P)m#`4R&M;*>-dU?mF{fb_AisP$Etw2fBf229#m$5r+NX z97ljw6bp#pus!~ugn@@(DRUQse6a`nty{~KlJ2hY+~Nbi@v-_J%?PE+k;TpKRfPCn zjYRoU^N~GO`27d_LUWX^{*SiO=h;VR;ysBGBdc`66V^mTd6n#|_(~BN2ESV@Kku?1 zTZra`!n(<d0c_&c<TQJHU~!Ig{3qsG&l(Z(P>tjLCYlbxTZ6xD>sP{U$dA`wBy7+# zqwX2{J)8O&G%fY#GE!=tD*rGb7cN`WH7me<RHk?yU9)>oHt6uyhV6(CeI_MiE25XJ zn2Hn|Pll>`BtS!{rJ=9?Db4e|A*36|eaCa$#o0Q*rRiZlEDrg`57Xv6tT7i?PeVvZ zs=g}w){DL>2X9})_}9=%8Mi^-QGH`TUNh-Egm#(g$$n#t(8K(ny$x~aI6ayOGQpTQ z=mNIb#>O^8J8no;Gl1y&kRshs?E{e19GGz~s9b^~(|AG=3yn0Ko>%E?km&(Z3z&i| zPg>z^#5PkB?|T*(AAFXK#oimQ{h{Np8>BX~M$xCZFX-V<AkL>GfY!i<HQ!2x+eNa~ zN_yy6n;&E3;tD;kUM=yVu)7pha^gen(%Rp&L`QlLv@^}Xz=_h7Zolw>#}n+=niYmq z#T8%Wd*UQ`luo`i%ZM<O^T)t+O}3(x(+Soknl_}b`|(9?t=jg49eX^PBU*l)!2n-T z$>N2hH*a+RWea~t{J(7Buatj3R4|<4+ZOD8006N6hqmxb&)x0+mF#CJX#I5v$UU#M zT<2dov)e3Bh1x_G7DcZtkgt?Lx@Hb!Hpd!r0Y2YHqlVh}A=qWUE4mwi`KG%o!!YaW zl8Y{ZmuP4*mE~bF)%x_U>#>!?1Kbki9|n%9KNH7n)@H0b%Qw~I6kMvZg(BS(+u-s7 zrEPB4Ea#r@`Gl^ov|{Tva|aTjTpssRJ-G^+qG1B93H_egCPbgH$#KxQS_{oPYDt5z z@D6)(b+-$83AhB8$tY!~>Ea~{@yfP@Tq1hO+QV7}qIzb`$-RqqJ=gFq;KOMyzJmlV zP-gW+Zt7zS;p&t)(CGWnx<Xx0_Qm0)PaG!nHGj=Qj!O=vrM|hBQ$pU!Cal-<eheXt zFFxCkOORMcR*T_4HY882sxsO^Wk~Bwad35pD-X5)^ube<D_KwFFdD^^5jk=XdDjj- zHF}TX5JQ>N6sQ0EW*_5HI+I)Qlvb<q#Dn&2$^GaHJ;WuCc7`a%*E(h>phme5{R2XQ zE-y}sI+vY4`z<h%PT%W?hh%W@Jd<eB9l5b-^b@NtstI@kQ8qFGGv=KmP2rnFDH3X> zOKM$8x54b{=CgBynCc>!>Dr^mFBCW(1NVAY*S+yuED1_KDtkwokPZPYqqw30Ka)bm zl6#!hM!{DgGcHk3Db-~KjN&jqCNK<<8lmi({e3Yi=EyW;&T{kF@8g4QY%e&N%rEga zv_y{nLH>T46ZdE75zL60V+|EsCA~wqzX17n*!?>o1+&M0>3%ORY<$<C6#o+-CG?#2 zl#RaE7XEkWj#7#6K^jK*l;$~^y7e0bIy5o``eDd#8A-282X3&pIKUMIv+FftLPRJT z?dY6mmce8-PYUCeu+1kn0vw;rv1_zG1Hal(SVSt7W0qcMmCo|<^Z8*Z?GM3<$i7K{ zi*ffxR#sM;&6DScPqh|c4g42%VEAz7GivtCOz}<)8rF@Kbyq*p*1@5Nws}|e9+>t! zyePVx{ICL5%;~YwOGC5)Rm_=d@BswQbe*U4uz2$HnXBJH1c$c1o5ZkLGHv~V%JO+k z$20v@%_EZaYm3{T2&SpB-p5Dh?C+nu;h=T2gnBzYF!K$QWV7V%l~C!-+pa`_JY%p{ zJ2(Vour9FTf_Aio=bSAUf>zs$4$?XXE^H$OusT}G1$1^g2BI>%mUU{0mSb}1C>0r$ zM_ZZO#(rNbZ+mbVwPU^qmYmC;c>;Jm6h~`uIM<Kr)OB~y*-H6!HB~iQPy2H-Lmo2y zjK@JSPQh5QQ4&JT$_jHWBQzf3ETdRV=Qb`+`X!8XbI`n~c=>zcH<W|9lC)N$Lb=1~ zZe|;C3C-m1{fOq?Qwep1`KDE5S7K??I7OD~-#Yc)5kM|67-vn$WKoa{Ei2+>raXMv z5+#%Z&J37W_%4krl}?k?76Oomm*^J=+;h$n{At~m3lR&iLRjo_>)25mXYHI%YNOPL zUFZbq4NZAky$oL$xXDqAU8d4P6RPEDk#%arO(iUtF{_j-^J`M9%!eygNnDLjq9?XN zd8VT44eberB?CSot?6d08pdPEoRMSmbr;Big%5l#OlFPjx&HJ7Ymw{SQ|I>Bcx!qq zg39D%p+7l(lce5m;Yt;syRY^Y{$NG09Q=)#h+Brp8FwSy`@=`AE6{^;GJw7Olc6l8 z);XU(neKv$i(ZG&G~f6qOZq7C3#+#%&szSZIcvMYqj5wZs?DTgt~OQ}yISrAnXzOD zl@`*~Wd)AbwsPHFo{$TJKC=kBNEboDf#n=uAZ<4bu+7dAq;bqpg&&!>0e<iq=%a2m zAkrJOCob5?8pr`NrniMIJS((ipRqs1I3-LVwo{%Tb+o!s?w}kRhN;tnIj{zfQ>~v> zblU*mvRn%0@>H3;fi4;gmMgjr{WXhs$qo*1_b?vxJA#jXU<2<SE#@ZkwMuq<MvByd zLP|+ng;)c(#1kM`{*f}`pY-%w5X?=+Yt{}KjYO<x06YrY?<L)<=MaB!B88SVPE3pX zc<g9Vn0F*RyE|H7oq-f4Ps{DCXSf(A%;nxGZw$Db<)4cD{frVzGQ`QD8blGc{awJy z1I1j*aMU%gsc90_)1n_c$|;O+cQdILW2}gzmq^1Cs^&t>oHTS$jiw!w93yBkr#2K8 zn9ku&#hp0}LYjH?&l&qQKaB@DiO-L$^~yYS##YJ$OZE+f>|hg+3lJ~$LD{qNtnnmP zP=%{P$-3y%j_cwd33es2fqmQy>om^dgw|OK?818*^maCFNClCxC~<2IvDbfBsU~Ko zWyCzVxn0t?x9ul6*lc3G!5RreNq#)!uxL7q4mr#7P%uo3MBp4$m`@cYb(3Mfw51>0 zOdzExCEbtM6iyfKDk-G?0T_)XYG$h&jH`@ZKOM1(hUT<yCklg;tx2e`w@C@OG=}I! zi%4{A2I%_jDdpF#1F4snwdf>kLn{7xlN~Szx1@wz_`5`xw-J|JS>mpMZF@rJM~YCV z01R}G7YfC+3rvO&Z=;B@vat>3&sX_zROfsE>qknu>U%^kKMxuKs9$ol0=yZG#AM3& zoVe;LLX^V<G?kme7H&*5GOlOegJXp<F)=KyhBsg_4jvoA0TP!E04v-NTy{_?ZkWbx z=sXZXPaoM!`S>($!<59xdZ{)nnk|Yldq)#NdH#5`c5?h6qJo>{SksnSqJq3T;T*LJ zY@(c(ihw?>V^KNU1_!!1{a;OtEY#ukI6CT)<IY0rk<-qkg@Xf@CB)REMw|)r`Vviy z%+$q3oJD5z+-qrZupJ=H@x_9k#d?c7yV1J^!?ncQlvl%AfLosCV75<?={yPUMIWic z8%cihPFMHd6SzIx`crX8mL}Hf;wA;F0VfMQ;wbmXL)&D+O=t=?OvXFthr4WEy1arY zPC%5`RHxV2i@U^&dv0ZKXr)a$h3;Nq=b8DM*~Pxyzf`^`T?4xw@CGqFk-XR<RYu*@ zjWdhj-W*zj?^>e0G424qe*3Plg$gFdMWlw(#tt<y9PjVY`6u3VN*fRNq8qHg+HDEp zpmA{XHygbG-N&hUJE$fzI_({VjHz`@>PdxNN7Mn@MxL3V%Jr->z72GAS#~fu@rp6~ z1iZUp?cGQ(+9P~;$TF->oqHhdX*ED~ZcNd583s)+9hbp?k1cn0sv^TD_Jlj#Rkz6K zKN?Yi>j)gY`v-lfj-*wlSJ$n^2<N*4M7&A&V~v>Ra~%EoRi--QaM|~^-w(Eb5R&@K z#tnvhzVR9S;hAk*n%~XqhfWf-IkB_x@|JJ4+&QD&qMR)fbNIO6>JoVZ2JZb#*z+!V zH#9R<GID59p9ci<k)D`t8bxvhJt8`#pL(+@K{&~FLXSiYc(@%RJfdn*7ze#J5E5~X z`p*I+5?Mk&_Z(5CP;taGsyJpIDW-68#59Vy=~u@ac6uqoB1E%Wl<-FVHlfP|vHIx@ zVPi4FtZGw$vx6@f#OyOh?GisALKm_M#BxDB)>(GsNB9^)JyKh;3M2<XJv{ydaXJlg zcvXq~YwSxR{-t|pMB#z@88<SMdY1?NT{K%(rAh3uB`!sTW=vTr+A)T<vw#7AP_Agw z-F1<&1k~36XU@%{_SJ*+)Gd6TTF>*Zzw(y9XD9!jx5yn|@Ev~-SPS6)f6ia6{>e}H zzj+D;+#LUFQ#vVm%K=FVd3f5&+cLr0%#s|u2#A8kD$h^ZTTGI`jQj^wX;Bj1r)~n3 zl|-FJ0t{gc#cOF7TYwD5UJTm1UqO<ch{)E0sF!li1K!Nf2M-q;o2CpbvaHd|$8+|a zJMN?GjdtFzw+kFXOj1s1D<&kOsHyAn6}HLQ`gdCv*tH6gqg}^rnt>B`_iPRAnPXw^ zt`WFk5%#FtNJOQ2c_s-5<0AEj%9V3sB4>ZOw?Hc;oPPVmNcqXg_mFP5s-iDl<kmhI z+cCQEXq3u)#woJI^Be=@>>8++d3vpe357=csftW`dlFTSk_#?*bg{s%Ao_DE<nqYi z;)^lQF;#|JC}Rqnl<|=a3XH{fu`*4E7K_tDm#L23)Phh+W7oRN{rh~oL0c^a?It<v zD@!J@Op{EB*>oFQRAZ5w0+qYN_yB7~W(qp<EY?n%9^RF!2zY<>@>}l;(*sK5l?Lnv zKs~ea*h-BV5+-U*hO+l2$Dnz7q-51zXi%9~s@uzOpAj;?EMwX<l>S|g^2SUB`djQE z4NB_{oix%9f9^vg2?u4WkZ>XLN@0s4isPwW<I$$WGt>#Ocll8kPick7RY+$TNu_4J z%>3v{&LF6}qI9`3(1y$@>U1}ghA*!7i}l@8VFXtC7{=(hZqGSY#QFI)T}8AGw+KD+ z<j8QhA>)RhZa#YhP!Y>h{%U}8wVfEc4c>n^#z$pOr&wyILFns}mw(x9GGwZQ>~2|U zqU0F$RYsQMw0E}+i7uV<E|%(M@`5lrSH`oJgm<h#;CY0$pEbncF8t15Ic~@SWnyq@ z6T0J|mW`X8dYdhq&6iI3T_~3pqQQYvuqTG0Sfqew^~Vg1J9wx}eSoZWu_Lkx^hUwC z$dc`L)}+DuAt2gFFuUwTi&BToHJ$0{!u1ugfQHLC>MH#65E90OUo6cj{GEJuK+`}V zAq_gGUWo4JH+5nph1D=+SCqObj?;Ea8sa^`&S+oPtbo?D-j3}Dou#TMHtS9|LMFyk zoS#kThP@W+9{O;aDO!+OsJm^Ehjc@byWOF0$PZn}>~+>DKwxei1<9<sXaTlMU?bka zV_(VDZ8s>y?%lf7@pXz+wO&h?w19DBdENOQV|>fL5UZ4BXWeFqbLVvhT^j{eKW>O~ za$OnL!CO!s|1-L&nB9;a<hBrDMh&p8{Ny#{7lFEhs*lX-l*+mkuey{y0bQmUQ5$Ca zW1r0u3JN7*Be*w1xOsmRi}RciN<sgF{y}0IQje5G2YdL*ow^4<hf-?K8yt`uqhDJ} zI$>>8wK<?aj*!{bn-iK%C&12HF;qiU<Ss2zcb2>`IYH?CgV2#lt`g7f^5}Q^Z<$zu zIkx<#n!PxX<iE$c52%U{n*c}LMxBB#mCd;oPlAdM2o0W|G42YJr_@a4PpFRGzbjmt zu{*`{=F6K!Tf4UW9EMAzQ;-Vgar3O3v3m^smv<0f;3@KW^WSqkXJ8>N02Z+NcZ?a5 z#&4kvKi%Qd`d#9F2Y!O4b#DnCf^*a44udf5oE4iJeFiRcdoBbPk`^u?tWuWBK$<U| zMwj*Y2ww8?*rxn&5pR7fT(1WRQ4YS3mAOmqiLIj(Rt-d?I<0GVlZ)RV7pji5h{!M! z{sf6DYR?v4oQW-k3R_e_J9{KKO%7`lMu;Uux=5K8mbf%4=h*8CSaCk^cJ|FymAuYn zc*c(k-`=P~`~(ucevkp4_3)aN!{8PPF=Q$i?Y>dNf30C~&x9?v?|yN^=O~Zl$zN_u zCSPrFs>L{1Od5hcAI#8iKf!tTYrtxVi$H(RW}4ajN&OBHB*-e*kwvgYh*emN{ZQj? zBkyrQ_@r-<^W(FWlCa?fe97-Bin%heNR!;tFnpUxp!yQhsrhUXe@{IjMGRGi>j8o* zZY+uy^?dVT=#pekmXW%<Z{PUhkqS4~-<JcQ6wvEgT@GM1S-iWEv<LQFrq`H8!Q;BU zNM&{c)sx_6PvO47!~4+ZuQ>AeXz}lH#ILiU#_YQx<Mka&{>Q5uX&Xmzt8a>1tMA67 zk>UTNjhz&)Ve`Gc6*PT#$U<L~Se!UR*-R>}UhoJa1R@V5Rw)5*js>`DbVd~>rw_IU zsQoO1??-s!>ngHKOJKZ|jO8CNHty>DG{HJt|F*aE&2__~XWkMwOl&<?Ln_D~!$pyh zh`~@kCOcnKr5B+0O?ETM3A6LkbcTJ!t*iS6edMe)4A+9h<XS>oCj`1y_F*`pYOO#w zf!%Rv)4H-FJ<bKqwPv<qG-9<Djk9h*mi)z2#Z>C5f|A2qgClq4A`|E`Aj1K9q;BY+ zfTAv%k(O)q2Au&`wZz~SqhY0|Zrv<7h3qz7(cY`wyo8{&^CSP|x|75m@B>6`wyp2U zErRT>Upsm=`%QW-DXU`ejYm8@3=))RhjplL@sk=i-9PS}Os&I98E*7IUGm4yjLCRX zA?G+=o7XgAj3xU`5IyilY|y>3$eGiGu6VE!hO%KxsR1UMp>n)l+|J^cHs0iI!))!| zlLz+_QEx)_bqn%<M8#ae)co47yg(qwnSP~ma&svbvL(|PO}WgXKd^I-ko!>-Z?G(U zrwMat2iY90QUjc+1(r05yNHJecO~Zx2x+@Xgqt6sB?vaY_hgn}?B}q(4d}%?kf?;q z`ajl0gKc{P<th=V86`Y^DLDyiKseD`5!R71j!KbV$`5!+Sp23%{{vVjasg#ua!l@Y z53R;k!a^H-9fYnEdIQ4z2fjNqa0&57st>BK8#4gT<mRV0NnbayQ*alDlo4OOn#^{0 z9=nI)1!Wh)sX-U++ET&E$S-G!`Ado_k*r@%c)18(B9{j1ge5GzWDU5GgiQU+MQxw| z&_(?_Wd8-`za}(T$*&xR-%Xs;@4x@?yvg3k*wV<rkyg>o*66>)f;k^-mUuuxL5V=E zok69YL1{!lAMY39W5@gzML@}6q;e_->V!Tr2Ra--@)sI17xodoVl$bEfK6<T-L>__ z%@Absf~7)H;w8Qcsd5D@IDZj{fL3k4&*kqcHcw#Z^3cSpk-Os?MM9gu2%o%$frO1> z{C*vMX>EOR8`SL_B4a6`V*t;^8Xp?z8R;1S0E(oFgr0z=;zLCOrc5<7&;^^v{>RSU z-{1J}uLmyK>%sr-tDb)I=ra6It*pPl{+HRee6pV9Kc`XOTtp6-O32<cP*fz%Ff*7I z3(2YSegiWs4@D3n1`SQgg>qs{;#QqhSj#OnEmT=2tY5*O04ABEU>a7KS+l=&KIEd0 zXt4I3AQLbyFWF6U?lO-u>oa^lKlW$=mSkax0$mQKJt(XLYXc7yWMi{>-c%uWfKl)y z_RP`o^rQxd=U&9YS^J-nn+uPe(Q|g9nU3}^+5%T&H`^&#FjV~rvN_@5goltD?S~eh zq_i9uf<&FXG?s(O(q9?+e|N}LL6n%CL9asf)#H3JD==ZMWE!O~=F>EUXU|rc|0!eE ze9~XKWAC4}(xa)K!4urhqsvIVc#pM2MzpW!Fu-bL5Ue07Ga~Y#vsi#O3E~$oZo+uC zP!0q5=^!GtWvU#}rWNaW(4R~?f%KX^d!-l&+TZ88j#1p!J8}d_6CIRDjjV~`|LP*8 zhZvU<k3+IajVt?ZZ=Paa9}c$h;2|A9V^7gGY3tN6VV3sfxQVdZe3pM%3#TMhFozhs z&@pLClZIK?s=kN=F+{h4GPBlJVeCG+GKQM`x>9|gAyS_2n6JrZ!)zthZ6@{_7Y&3) z%rFe1x&Mr<LpKpa6cf%R3aEjt;HoyrGMw@pz9XNHK&$3Xq+OrMHpx{fxt>?D>!cS^ zCLJ?`v@j@UqlC@5tW-N}2d6WC53L+&fLT39M~t~5WFS1~6%E$XcZ1m_$KQyYH=41; zz9|%D0EhvL^9G$FIv<HC;N_5#v}38Vr%5!Lh6`afPQPCx(m}4;I6hgX?J&}ih|L1y zHQI46)i*ZtW6bQFVFnzL2Zhy?1e6-cr6N;_GN*&83a((zdj|&lA}tTn5^A0dBINK_ z(W4EMRKm^_fc;0Q2az(}N&$kn0OEd>`NjgPX_ske$SG${s#tYYvBg$hxxZs)9Cn5& zmWy2?i_3gLit0i}%4C939*{}G?@qLbQC`8VM)>0kv7?4{u{ItVJZU^_enlD>t>Jy+ z8H_+38gAi%lS`9QM-a=R9KWJ@(d)rPgXbLlYfgWjfrXwN@C&lJxUINDgI91|qIYa0 zncn%@d1{|u?0p!JVqc)%k>cT@T*CMCfRw3uTTqFh4SU|_h<@A>K5%!AT~TlMsBXTj zBjXxEbP<w{q-|6wCy{f?Ke<<VWz8V77#&V>;IHwfK41<+e<b#|9?33}M7X7hpU3*Y z(*&7GK%0W+3K>4yff@<v#u|fJzq&%rNYYlzi?yfQPsB|g$*1SnqmYm{dfpj&j8E<< z7@-|^?#*@x<EjD0yt0t|Cd&Nytf7{ec~HX{yzAO+O$n2Gs&XwYca+fa#V_c-?_tNW z_2X&b!@8vSQ27Hl?6HFz^#iR>-y`2xE65ju9qB01qMPt~dGeX}m?NlR=#E3mmuu_g zAFcGidzpXvpTA~1!_BIlN#FBv{_pwtf9!w$vGYqz|6l$`e&rv>y9H+Ri>7B?)u9ba zn9a@M{`vTdUUZLM>Cq=*9OUBaH`U0<y<mS`@7f3;pg=n59@02mIvexwY;6Lb>r+SZ zPZ;OwNe_2KgWyC!|Auv0>JRxQ_4>Vj1Iwyag*}hfTva1DpP#`Xc*{qDfy*#)<lzUY z1bQ)0u8?mjOkuZTy%=b7lP;NE8*bvzJm!V5qE&**V%VdbNlEgKlmh05U$1!MIlND8 z%^GOtF<D&V-?F}0?arF#81R5|D&-<%ItV;*0M#ifrXwkOQ*(iIeGGP9<}6xj@1t}E zmaN26XqjeFeX+LtOC%uDlT|VN77?&y%(;_~;z%G6rn<^tw1+_%nm7+jOfO0AjMso+ z|I>M*W>#k$dhk<nwtW4YKE!tYE$^)`TorQyt!%m2ro@i`FnL_~$BYejZk9lL2gcmv zXf#*a?je-w4GORfy>aLiv0kia5PuuO2{L^omH6(Df(>ZW(PJ7pPf(9{r1wW6wpo}( zI@E$8dW3QDUxS-w6S~AS0vkl?zyCqr{`XJ&?;l;iCa$mJJAWkk-s2PgPlL`sKf0)q zwUND<0l&Syp4(r6_^<TxzqTS2C1sH0kUy<WUUOk(DZu5+LrX7^%>Z-!N`C~H$vXko z;nN>FW3Tp}{K`rzt8gs&{Ne3u*DrvGvfFpO_)TQ%!eJ(1h7=aj`joxoGW9amdG|K` zga>eFOBsz`XLrwkQJ_E*ZKfHfFLLgdM<Ya!HHa<PZM<~aRHU)F>a1mgPHA<M!ewJ$ z9`AB5rLfe|QA0&1gbFi$ZOvH7(3x3x27O!i5$Ovm8C=9`xiHpNKQvBi7EhwFcgW!a zO#mjbQjST}f9<s~ha;$AkKIL`8{XJ9nu|;=Pn)ss<aDb}u_8?}eWqD{>PFFFtWl*i z_@2jr>k)h+?Ic)8BSP7RmYNLL%#%I(Xw7rDQl4#~ic<CvtD``9JgdXhBCZtOFn?Ft zAxs9f0s}fqV*`O2jcx{6j=Pl2yZzvsq?*+Jhcrf>RD;-7)CH?}xF=k0f)UvxdYcV- z@)a1WlP1(CS?|!b7y3r2eaG}QoFE+6bj4W63KID~;-Ji*O<KrKs+X*a@fU7ohl4Vt z^>(p;J=?JD5wFQq?6F~{-YZ+ws~~><f)89ibSIv8^BU4odU1PV1z&&5Jatojb5Qm( z7THX}6|i7xSD|jsCnQ4PfRGp?-yEbk!Rp>AkAV3lWg&OG0D7Sl0AgiEtQ<ii1tM{l zxw`>)zpoEssUse}KohC)W{O|UE6Cgts^);oDo^B`Be?D{v;Mi*HQ@f#wu)AOi~$$8 zH=<+0)Nefc__v^I*m(2HpM7AV=lB#p{@>~v0Sln7#g(;=<+V)mY=VysS3jd9T!gh8 zkpdKp@Rjt%XsC*XO19v=+EZ6Aa<6b^pR%X$R_loUsTdj={O)uiW*340UT|MRM?%xr zz}C)kw|~bl&fc3UVf7~Rg4(r(N_tzRe2hR#&t(@XM0&r9=bO*Pgns;k<lyf{@$cqh zM6<{N@tvc&f9Gf-|99pht7rdxI`f^aeQ&%P{=2<YDoOq&h45KLA{w55sE5faCFaKD zOFe9dOI@8B3r6l_mmyyQh^YE4VvB6ZF2-P{TKlbea1JfY@{2XgZz^`U#<xyC7$v4} zT8~Xdo;wT=8qk>GDBI(Ted}Y2J!d!P^Zk(%Ai-6GA5L3-CL&GxR{PLcxflD81p0c? z-(Q8US{DJ0xMOT7f~zfe8&O+9cEAWig_w#SysB$*MrD10cgCUVGSLC5>C$Z;I*X+I z{MdVv8AF<7^QaL6GR`8qwc#R_roSf-e93c(1%|h|quxk<0U~FSy;-w7HTsG^Q`-V> zEv^}RJV#IU7qgss${$pk&OUq^MH^W_ZsBqI>II6k;`WN_HOF`|Wta`^S*?hx0>Rm> znozwjrHwz7#Wrn=A%`&0N~M-7(B{2)`oJutL6d0Z*6bxVCquz$jAcm@e{O&<6+~S% zpQzWc%pk;3e#YG9Mud(J7Q<c_f0dJx8O?VW+uU*Y>r!lVeNhO5BEc9WG-NTpe~aqi zW$nmPe6T7cewdHCP?!7~W4~2*9Xqn@lF9A(6H>0JzD1mPa!+wm*VZ)}vfwE0PVv%q zvuWf-X`a}T=Yh488l>39w_SDe$1=wcg;>+*`V)*A$7BJCf8Ky~xHWCtI6i|sxOT61 zW?$k@x<x7)mA0wNhjnDVq8(<ydPh}090baT*xXa~E~W&9v>xBC&p5?g%am<XYYnM* znQAW<#SlHgj#O6{iC$8*1$6zF(iwDTRKFoQw=}Q+i@eERu$I$=h}EBmybp(8gt6vt zI}LM{`B=dxZbS)tOzSJktx}E6e=t*C#5Ah(*b&B)b;Nh{L@kgLGaR(MLIe_iH!9aM z4dA|l<U-=(_dW=G65U%M_KV+&bL{_YF*i**No){y4t2(xr<mg?y&x(!awae>Xoqh+ z$K8FJt%W+l-GFpWv_!P4%aMOKIUYDV9<ma61?qP!3nF6+`03jNrDhw`jR(aw#n+Rt zUp}jaNAEfEK;=f{8ct=BT#z(8&}f72iSxr25vO-2YkL-+7?*qO+Hu^lmj0zYd2|{d zg(N2?zMV{MHQ<+*Y2Y&Nk6EP<F$FBlEnYqogWD(St!Z5*3Ga}6x9(uZ)s*AucYp&_ zMD;_SL}14af8tF)vh~Usk{=)R05DkGnt1(mb?60en(#j}5sletU-96%8<Dt^E|8jU z1v}<FWO>Kn#90HrdAgAr&XW2o9eu4=H!GJMKoM7R%pSXAF};hzzC@1Tj&HVpXY<0! zjfo@*na>dy_qg+~vg6IF7CBT=tBpq*KlNTRJDw*1oM@se&`J;0#|;^Bp>-1Nz3>^V zdjQfRT0_qRs^i9h>F`H(B?)thta75|zyHJe{N2U;yYtE80Bh~~PR_Kx_Z|5E@0^dy zx155(U&q=19;cPH9M*)8xh>d}Da(JK5yM)ECGY`gz}n5hlPy!5&7nd|%iGEaGe8%N zNaQQVMN$dA4Q(C6>AIc(`^_1r`jJ<^gS#H?MTr`tUsfrqI2i@^j9+eUcuaRbozF&l zzn`sL0cH*s`y;uk@uOB_7yMxdsorJAV7FF$mQ}LFMMLhG3L()<terSQ0ZFk{8$!Xb z8F5YE@9c1Q+WUw}USeIMVMdqslHHo;ogHtwJWu3ySYv_d?yxI2QbuRUQXaog-iV&J zOfYKC;i;2X8n1naf{qC40{4OoUqX+kw4OI)lWWFysI2cca>sg2mf~z}vp9Za-l%WE zu_pb{il{T*sy{Ez^N@m7ShHDKkeRgmWiz<AW|hD-wWMWJQqk;autbG*`Pp^WAPfQ( zlT>q};q1|d7Uhn+PX94!x@Hix%PTvuaVDod*R^)dJ-(ucPJ>M3*Gm&rI1$6yCRIfg zG;;I0h})|izJx*SVi7ZcJwVWZ6I_kOs{EiVCh4wXa|J3S5u_j0!(G2o>jkQuz~6L( zXMIElJr&XZYdv$Xp9^n_VFDM%Z?zQDne3-|06<dk+70ww_+SS1Imh&ExKbqkbO;E_ z&$xt}<nU%W75c!;aJ??UJBmfaE=?8spmJ!FY)cmRH;T>Pb_Pre$YtG;VTFF#7rax# zmq%^#{t3BK{nX1dTmVSXIq~`RMRBmki^gcFu<1cDY7tMncq}^0C3=rP>)eZ<ULOmV zdEY~lry{a8z0`}x`#$W^azr$&qLw+dw^zYKPDPQI{G*fR($sf@oFPF-^VEW2CMfqS z{2eA0^v-T}8X9`I2==HSDg<s(@lF9;B<Up$Z(^oJ)%ZAsF95(>_(hXKR4=}nh^`U< zBxdhHLpo+3Sfn?c(z8>B|BJGBjIwlF)<3J#wr$(CZQHgpD>Ex?+qP}nw(YF+s!Db4 zv+wP@&%b+|+x=mUvDU|Tu9(k^8E?ez`6d!R`n~=jJYC~%2~sP!UnI>V-pn^;{)WgE z-g4sJlwDK`=bg}CxsNu;G>HsOs3+8z5y5XnNM=7Bp#Vn+#v)X~D<B;O67LL*Kk}Rb zAbc-3$D_BvH!5)sZemAVnv6%_4DrNvbc8M;<vu1D;co_F!3S~W#2Rz@izmC6;H^l} zGJI84fKkRYsGLl0MFICP3HJbCzFcqfr-b3SuWRv|Kpr&^mT)|TaZHS1=pMtoF#ZVH z@SbEOFCQcY^!#9$VV?_ix>j>Viut7<&dcLn@|)#P=~igW#{KBYAse}(c*&#(kdzYq zpTP(|N`N?&;#&p)YZ0*E74c&(<vnS<BceR?Fsa0vw91*~6iB=u@Lz@De@eo?i$z`6 zp-Ai3ZBF`2F#e;}it<-R^4A!S;a^?N|7Tq|{$I?XkWa}2jH*W=3n}T_Dx}s5P(h(G z3K}Wu=4g#LHfT3wW~q{h>j`wNr|OP~p#bnb%C&n48-!Dts(=L-Ma@66>FJ+7r&EB@ zT>IVcT?5eIrd179^;L~FYimvQqzt)b8k2_V!{IRljfL<)2O0)u{7{K1A(rZJ%%<JH zpI)y|bKNxa-sD2LY#~uDqiX~#`TrDvoNREZ;5X)#9w@J4FUU3H{tik8DRu49lmh2M z^jMEM=pm;s;#bJQ2mStZAHsCS-W`)Jrazff!r6Ae3`*_|)a>=D<C{Ek;<}&_`p%1& zhe7h=#_d$W;QTXTQ4mM>9;M_ftWxF#n#<w7yGylt8_JPS80q6$^&Ct*VqZBqf}&2< z@tA6wXrleX17HBne#+icLM!8zZ3^4;7wkgEL9^j0`p8rQ;UrO%eiSt}Ef!HwXx%^@ zjA)!l;6?}pPSKrERz}Hs1XTQ7xZ=zcm3vOvzD9&f3?f_ZVhb9srzUr3@z1c7lV^xl z%`#~Yd-}jzVWv5*I?i$pBKqNfZFd``kP(EdJRknmlw;e<z>OcpJc2fb?esLE|5s%E z^Z);!$oQ+u8Wteb{Qi~0T7Av-D*vZr<liFW?>nEcjiIx%jJ@HPH;<sZp_8e+k=0in zR?^PF)#VEXWNK*p_XV(8&C(tDYy8(P(Ivqpub76^zu1P=mKc!|&9Zz!C_k;mKnii` z!i7l|jEvcli4ychcgqh-%yiy)Nj|6WQ}V8zxma?8!YM}or2Ez>_myt8dmP{I9l-2g z`b!qan*miAzT_~izn$ZNqjoQtqaiIh7kYtxH6+qQv7Zz)_0VEaTCodfkUA~(S-sGM z77X@5k!C1QIz6&K&WSOkD=8R5hO&0ZK~;)6q#(%+2JQs4tELZiO~Yxr;5=P=<mxFw z5zS&&XFjFLWth48F-Z*zEzESftJ)KF6#>KQF$Scfc>TA_inA;?zm7R(Ym<{_k)Ml4 z5`}HY5>reHvxm*<MqOWj+X~_$Tesp*7p5@A?8hSA3XdW7rUS0G<meyHK>Lp5=3`JY zn`t#D=rHbT+I1G^Qyd*;)0Q=qPpHOg)M-`j^0*V>)*04QG&+nfwKo#qT^CwlSK*Ur zGsZdW_^Ojxx($k4OEp}s8gl3NT~_umQ#^$qWJY`X=#pRfQF29F(^~pgN}iyG<Y_O( zB!N;;e|apkPQ)~u0Q!Kyt$#q}1xEL{x7pivhM_Oe+HEckA+KDEx|!W-tu`IXa-edz zW`xPCYn+5+DXxIJeMp1BG&C3R2f6AXuB~ujDmj>PX=mI?7znQ{K31CK;GZO}DJ$$B z?~5XGJW6y!5EK%3Gz+yWC@oOrxKh>F$)qvG);uBeQW&a`)E5<?$1($d&8k!#aM?jT z@>ID)?I_%l?I?W>L@CyzzoK+i9`JU_U(~EmF)rV1Vpi)I9N!-`UR?~h#=-&whC?|j z4v2kdzRVDCQr`hV#c6ElxlA)oS6u;_k91lwVu$8kCY+@QFSpL$P5T{bgpKv|CBRTv z)caF)XgST~`qiO&(9-_sL(<1tWGMyOKU~nJX<n~);JP}ao@q$a{JfsVhv(EIwf9)$ zBW@*m&2UuGblD=<^Kk0^yyxc?kiAjXHEIMUizEK|6mf~w@*-eAMOf!_sz%0nvzAkT z6}{S<8Gh8^tfoH$3oFk|DFE|x=MPrE3F}dZ(E+{SG@F=J{P)JxnQS7MO>&1O$SFUN z8e&(q`-ku4KPE}6rzR&ZVrDs<f?PMrNF1>@JQq&wffqCc4#7d7uteCbJ6gf~Vy4hA zJV4|gPTN9z*9D;6#;~D(zW2C&%f5%*;}X$E`qA{H%q@>uU~`Gz20Wkp=R580A8atd zHihm11CbGeqaz6AhF5?C&zHG|pKI7BN>FbCc+(!ks-YIxZ{C1X%-KK@Zc}PrVc=H8 z45{Ehz2cL)LH4qxLhkck*byo*!IfbpH-swz`iT5!k|Mss)<jO!h#$dyh-6DM_TX+t z=%#D(4d{#mxdsV`7U<;jgk*KnSz@gmfk|mYgpO!|M2F=36DUeDE)e4Fz1WaEfyP7U z1_y&W;|n2b(%1tKF^zE$&^W`5Q+u3Rs#-uWIpK_2V2B;FLqbp^s97owP(uAfKg2@R zWmy0#{PV-L0gJwwTH%}$Nd{u(2*V^ZNcwUo?)=z$C-N4ZF5nmLVGW$w*cEFY@YjSo zNm}BlnO0insF~IqDO4>hO}45o%T3p+Bvu<SRBkIxx~e>Ciyf6~xE2ZM1NOfKQ{d|Z zv(84`>an{ELTPsb8SBwchxn!<-|L3He@r~yo2F)Y?9ej=vY2L3@KPX>{$c-1egCPk z|E|6=MDTnaUy~$1z8ZfR|Np7)e{1WjGqyVFM-8o|sis@jkXr$ZY!Z0&TLciLEOjWt zsHZ{PF&KXYBw^KYb(P3UN2TgD$Oh1{>P{1imR3d_<dHhK*%eF<;hTs#0NfzW@az}H z#`zJv0T@<~b92jT%hDVs&&tjh<nOfeH0L&}@%7c+?;ZOa{y;MX(wOKkf)bb`;<8at zV02N9FaxY%h=96dM&mt6Ok7}6U^|Rsh>TxJKi3&f2HHpvQel1gqUc5DB1&O-ko(zq zsAK6T1`*%sF#%2>+;>@Jexhdju!q)QJ$U_iKEim+_YMOddMrJbd)i<<)pe!41}RdO zn^{d+J(`R4A!KwKn(lcV%5I^$qfDi!1;E1v#}=ZMMF?C8^e5YeP*348jKKoEyq1(U zQm2t>B|N-_oWv(0KNDyzxvkMgWXS2Q<uM#e?}yGLH|6LoXVTUwsneTFORtS6H5nq? zg~tse!GhmR7pFIe71{MEo~S??K|3WLfWsd_A1ImATh*V!Ha8V@s}#(qDVwUV;9#<| zCbgJ>rl%op*)`kiguH3Px|3n==*k1*>bI5M+Bwccq1N$aikLVJJILhuy|dJF7>*}8 z)qch5J5}?IGSdGpps6{Dgc80bXL!Ap)T`aHhJ{TvODQkI$J}>Ytg|+whs$8rn$TgH zn+!6ox$wzi{e>GGvhP!4(P0{D_8Jpaq_k}8$|5)h2fMi^5u`)TKNwgd%_$|7L&ccD zYM~Pkm%P2qEs?U!Ts0-KN&ceTBBtLoS!8s2(GoL>MVb;n5TkW|bZ3^>x{d9r?XGoL zblj;uN>!2@2B(jvx^<q6R8C|w^%_}QO_ee5<C5-l*L1zH4c13}pJ08%V{9Ia&+1|W z**sSL>G=aoLuEB2-mvq^q*~c?yv7!L@yUNpY(Dsgf{CD<d$*EE<jxx^@N?BG?BEsf z^Cx<N2O@tGvR=f2;hRK$vlgDnov{nGP4xnA+TdrVF<)fpk7vh^#?s{bVI7^9mT`|_ z$1fKo&I7(w_^?cR>Y>}^U=%p@-LP4?_=Gl=&Wlk>msj1+R4<gnu?G4YE*1p}4bH~7 z)1!$+wfU#^CUcXCh}TO}K3%%@yMpTx@+yyd9g49hJwwWs8r6A#B+A#VH2pm(9FT)b zDOD>S0xRkWs*cHd*N;9AOGhzeg_fB29(7EHfy{Gr)lS8ZF<Oe+u_InW)l@}abj-6@ z5KlRpQ{8l4txA<lFH+8xqQGI^p5aPG#<kL0u91|v5{{CQDoYhSFlo<HW%E>XzVsod zD6G$8C97hKcMnE?$CVAaOE;fp<lB@SX<gMqH9-_hYSl}LWuDz-O*`rW8*mzBVJpAH z!xD!v$5GRrphvWH8+6Tzb&Anjjd#?V{f4Qqa0s~Czd#TlW?XBBa7|3)!r5aUK$IZ# z*CXMKR7-L|z&~2+gC7%KA`sAJcEzIb?s<R(S@t=lT`Eph;NNKu>&u&<A>`QEZug%9 ziV_WC=7qKZ&=Qpk(8NJKzrlflMzhy(qG|~(0#Z&iED$s8Mgtzo{n2b<Kt=YdTRf-- z?J=Ke1~(Skq7kw$hZVWDXVww49zABX^@|!8DU4$-31>`j=TdX}-1wMvU=a^tu<j&% z=VRtB9C`d_nGjAba|aD&5PSQO>Gm+L7n9)oi-tku$DLRu&yj~__9ZV;%DKh2CzGTY z_y_%Q56|KE2YJZDIlSKtbG*bR@%FE}TCwwFP0>;i4iztc`tk}}c}YrA*T?P=7Zu== z{&`UJ9mOvc<0eJj;xkgAdF8-6y~QEQ?;L``JY#nl=#vC4eeBAG0+VCkE_Utfg*M$Y z4%|Ah-=ph>uU${h!un-%=a?;=o2TT(DekZ#-5@p|qrEl(l6KmlC(c{cn)6(&NeuSH z8(SS8_F1`SlbZ~qwmk$nuD6P9p(S()NNEvm+EojbUL(_N`=M}8zcL+luGbfXy_VYk za~o4KBS&;=bV+L)swAMk?>bZFQP-p^u(Z`-<uLjnap(?Yl@|{^ncJi;c@`bx5`8`@ zwd|eA$Rn6dy$)SH+%?-`buK)2@m_VKOYCwr+%fn{m-NK7K+l+_mN}t!uKsLEb3Jdp zcGcZaCYPd-c}nKl!mOX+p;7Lk10Qz!bA%1JPzdCllUG3NLl^{(Na?enM8s~Y@|}4o znaN&zVCHVxRb%M=e5OWwZMoTh`+>SUPZQrSk>o8w{6mU+Rgdve$I7JF11FcrCa}wz zs;ctT!rZ~V$vHi(jV$EaaF%0pdWU6poqa9)+~|#SoBj^|aS9%abz5lqf(G@GI@n0C z{GNkbEA@m-u2kz0P}XWjcSzEB!dR1-^;E0!8)F;nqi-4CvzcG<b@u3j{^&w>qkEX6 zM|O)_#5Z)+BXPygbn_KE{&U9TGf?7_WJmkx-1cC1AM!RXnwyIT{(Nd(W?d6(KhNwI zaYhL*7O6>b<&!gpR)lk+ra<k!%V_=d&J!s9#2t~@VW;mDP)pe*-OL3{R@^}W&XZA0 zA)K?N9y3vy1}Q7ELOrU8M6B9u9GnIZ!MM;YDZPh=r%^2@+XF?|x0s<CSS#gzhNp5) zIb{7DlW{b=&`6#(a8I^BnM|Jx7xW4JS7Pwb<NtpWgTG$C7Vu%0-hW-zv%iu9?*Et= z{EN9N>TGQ2@HcXaMA+Hw@1Org(#TfTR>xLF`G9MeVS-^$l1^@6D=8z4E73qiEn2Xo zQf_Y|$rsbQW8jn(3r*)pC-5uo?L*hMS_QJweeU+_+dT->y<vt-6`G^dpD~?nwcp)& zor+BDegD2Eyrh~noD?9B1W*x$=erzcF-wp*a7Jxxt2uz4qGUMoRgQp$vMZlsAWfw| zW+MLipfs!Eh^=3)(N_>a3OWh%L(I|j-OR9GhebLV70gT`{ge&(2CQ<+G8|%<aV9RQ zuk-j=Nf2rQcUqxNk0$<PZ{Woz@)Y-G<$k!Yb$f#)kWO%TU@L;L*KTUI8U@p9WlYp( z#O>N3g)jkA*E9@EPn7|NX01lU%GM5|cZeN_Fxm^vU9H`I(pww@_QEYukTpX)xMUc6 zz<f?-6}4yomznZhYdPp_?XhQ|wrhNA*R<>e1<bV;c}t5CXI=KmSUzq92PR<4mWzi# z{4kxE6VvqueK?kOU(0C2#;>mXjdvGL!g0wYY~8L9m7&WuLk*%l!nPoN4^ckg=`ba1 z-Keh`AI-Bcu~uuXMTEGH5**YW1Bp3hF<+k6i*^^O)g~O9D}DpjQd=16mPv;TX2JzW z@er;Za_FaRNWCzT(sakFQw62E&HOO>kTF$R<kH3$oi8nb#Y??EB7{f^Yv=32YYJQ0 zR=Q^mi~9QxJ7oOx3oF}OvJXVZl*PTH%C6O-oSgRRk+-j1WetGS=??*eRs|Ir6kftu zDD6mLh16x5%7KC!a*N|X3s%3-xRBtz=wyCfW=@S|@MLp#!Z68&ceRJ1vfOJngt0dh z>y%v>^J7?-lxXB(-)q^_xz}m%zFUIRV-_ptd#`1~XFZd@?~D8KJ}@s}CX=q4#f~*l z&2-dJ>?gEDNpf5QDA;!xAH1f^s3ks^(%eF{qb&=KjcV7g048fgCEK!}UvwUA-0u6O zW%tWIDZPZH5dTHw&VD@9>32R&*E}goMluQSp#aJt#sKFWwqPq>m+Z?v@ymltVNK~n z9S-Hjv9a`_bQnwaeG~JB@w#r^X#Rw$)?xlH`lz{z=I<Wxm>Za4@uW#AABjbZ8<*&K z`L~!}RDtojBDt}=qEY+mLoaze0Xf#Y?r{LjL{8prVAfXn^B-W<4Uv3Y*Ll6&HwFgq zT>YDC^$<UI4b}$t=nVl(JuFBlQYeaO!u-;68szb&-E9+R!v;UvX2Ay58m|Fd^^=Pj zBZEE{WBX9Ygz}y`q@BoyDe)f<$d9Q>Q%pL<?D)72uDmQ@IxCCb91kGf6SwtJBKY*` z1zsIG;pab&rF7IM<q`aFm`I6Lg};<HKh-4z2J-_0KS=*<*B{#hKm2d<-#-Q9-=zgd zHJ(%LtKuX4zY(7Q#yS5V(xPf-`Y)~dZ*fuERsKs{>>3OQ8;asvnh0!(MKcjBuHc7( zl+M|bRVZjB%MhvQGB-^&P1(1%3HW~J(Qjb7ijCICFau5^>21yZwZwPdGjT?pQ-2jA zG!esl&vL$GIrrXfIokmqZuR}Z9nfL|<X|Q-!i`h}A?#ZWVbD#ZBA*ff7EpA=m3vS- zXcr>XT5-w_sJCNjDhPvhbuy6W82}3-d#!%gtvE(v;@P>HWAjsbb8=_pb|JTrpOynB zYdN)>A60hCo@sqB3{6m@*u&>SY8YPF@jngu^z+7I#<~9_<kY)#CXBz<SgMO*91KwA z;^xkioivBvVRA9Dh>JHxWwe~fG6p4<Yl2BSPh{=)6<I!5KMjN4pgn>{Mi#~7Yd3aS zLv<S_y;YnumSwc6G_{+bvEC$PG}_)+rQCRCxzWpT*^w5mx)e?@hcvcHWC1yxVx2Vz z8qBlP*4mqs32k3=c3f+A$cMs`xc^$H=*T>Mx!7U@NZ1(<x-hZpE|&JG#1I;7G<VE8 zxb&9w6;Gv>FCF2z1v&e;lLa``-T<}^@Dwd)UppM#rD{RnOi?hBt{VESdnAiYP%sM$ zLzc_R65KCp`fJk)RI<I>a?r%fJtTGZ!)>EDCl64!3le>Lk~0k*%uSK>mdmw|gQim@ z966KO_SHR&Zl<b5`Xr08lO2_ZJ1NFJVhzvy^a3I{yJ`>6_~ICA4}{}W6zKaD6v5OT zfgmwkRaF#BIT|`2=$2(GX&P__9Z|_{%G#hKsY;CyMJnC(H4bWkIADxlxqkbs&)PhV zF~4YAXy9Iq0qitjz}e}!*t-iSLKD5s#iK;cAMgt97$tB^XW|puQKFSUA5zl;XzkSB ztQfqP0u*=GMcgUUt=NX@%{vph0K|kg4eJA?*!^}>d4@eVX)U#!u9*UOn|?t~K!Ta- z`fDdEi6oaFi;FM#D%d2OFr&||i_at1v7fO0St$i<w)57kcB$pNncG8n%7xt!(O35w z#n5Z&nIe3##g@azq<8mnyJ*$<takzdJ5O?6p`<Q{5HSJykxdAe+a8XgJHlMk-^RC% zOe|1q*<txTvq&g~sS8;bdcmF<AkGWzBN-axe=&_;gaGRaMyOq|7L7*+tW$FF3AH5W zfLr)QD3lX-ft|;?03eA7hrIoS%(>n{n3^ry4YdSU3DOH-DlKF~+1*z2-x5+<csB<i zbV7>h&JmYfoA?Es>ZH9QG%R7k@d$e&(Ajz_&j<{0!6~<AE$nl+4QMT%gbCO51&m%0 zjrEP<egqRfv$8zXN?ma$t-k=W-u>;@V!uB<U_W9l1+)0~=iyLu$TmZRE>v;||CWBF z_DP|l-PciQlDGow_r@hV_Mp~+vJd~_D!|yNco%I5?@hehamDe9YJ1ZzLWzM#kyh$z z)rc6{j4V!RQ}Tg%GF0#s6nrE8_Dos-7FEO^fZgeDQYZW)s?`DNztE-sl&OCguz6K6 z6vnTX3wO-_1xNY+5U~HMnW#g0sC?B->`$h<GRH||fP#XGtBSu<6JC*`FvD0v29cN{ znMjb}hKMt<q(e4>)Tzy-pjB(@DpaDrz-n!dBqX7fsphS8sL^PpZmhJZY3o#|F0DB4 zZh1Z+(Q$-5{5ak6{&4^Fp5b-R7T4$YLFwaBI}(F<y?4arI~f7-(OKdnT*4Llp;RUh z=~}9gi)PiUkc)WHDD*?FY!><nG{1*pDK+R%Lrm=%pdzN$5oeEM%n^Nb+b(Kk)phG| zq`OTX<K4~&_yv0RoeRzp#sS8Or_XUMni2!)8V}_HVpI`#lmqVoKsGvvvwHww8+D99 z#v$j#+Xujn7UJw4dqf?2<LsUSzK_Cl`VQS0$Bc6N4md^}mg2}eWSsyoM`t;6jsT#e z^qjuOBei!)F}rQ`Sg#y8Cmv#LzG`K=7alXwWLJxKUD(qFKK;>XSIGE&<V%r4?|P&7 zE?q}r2<AcW;`tv%hqHDzC|SK{9>M*G@{i48(IOm6)<fe}kz&zpz1&F>7?5D>KdPsF zsLNmhKV+M6D}P-2z_32mdzhP+v7_8DQ4QAT<Y=%cuH#0y&D6?ZaVI2?dr)MY!I4Hw z`KeRjF|-s%S*%&aThQoDE6{LPJ=H#ezD>Kz(z22N909whuYR(=9M`aX9EoOdZBNhd z;zX4d^NMnf7co(8-H#MA9#>!z5@bkPv4?#Mo-&|n#Bn+scT;C|Z_`X>Rd24U&gI|I ziGv-+*BDh;+hCx<ETrA!L(`^qW)V%H)rA2c3m*lVLNu3MthCl7!IGpicTkxkQhpd^ z!-grmAXY3STy7i>YYn16g&}>acPR7LrNBdM0ckc-4{~xo{#{BN7bRYheSU5yE7pOW z#OUs2T2<o1G*wkc%C_C%wbG6d$c%I?ODakb5xe7(+Pt5mK!6kbNY<!_R8IlRh1$$b zJD%ny)DkU8DS=&?z`G3{qM39!Afx=-HBEN+VR7Y8j$NdrYdwz*T6IhS%&ZNiW)rWC zzDy)NwELu`6Sz^i$66a1(Y?NxoY!gCkw+b}{X<_L8vI8@ujd@4m9EfmuoOfxN`-n^ zn!*pE;-CnKWnvYTvTGq*WGnC%2AXl#(3Mf6)l#oU??g10Os5MmBN!VjVLfij6*{VG zBc56&n%<^C!O>k_0Qij8FZnm=(OzB;*ji?l(~Zj7MrJz~rD;Agx8SfiluDFjDX3&M zB;%uy<9!-K_-nJYJN@TSPFI+`FVNJz1P%#Sc;b*~L83zf5E8s3;y48oy(FU~<hVrw zBZ;x3l;lW!QhZWk6nVM;Q@jb%xG71Z<!Uac+tSjg%gL`e@q2gM8cfS*u>lvICNXc} z__lh^xQJ0>BEe}f`6~IWo0;^*%8H7`<1Q<B=kTU8B3fu?enzvk+ep#&krfQNkPh2a zg_+A0tfV3@40Od)=wr0}(=M3vH<p8V2ik4Q@$41_EBfj{%xGC!*Ml?nVrrvtRF5=q z5Df|-9UsT`W>Ge7_mjHl%{I$Q#1dkb-H2>D(AR#u-S~^cA4;Oyo1Ty^jI?8{mghFV z5ANpV9Bm^zn+A6mbawakkFDWcif;M-C@@yadg57b5|7h`WKwO=Juxy}F6c8$J6{WK zSvwtTd6V*|NRbg`MvHN^SW{hGIK`fB?NFp7e}+cQiFm02fLwj8@t}NUqt`VxpZRTJ zt%v@Q5w~wMoIUF~Djupnk=2xR2plGmLf2lDP0(RKD6+N|y8V#09h}%mUI}f8ho*g) zDnQrt8q&-o*|bN~aYj7v-s?9oYqv4U(i9Ii8)0TES;$RCc-Ooy(CNY`Q={8~Hd`l^ z_Cg|n*CzB`O>8?WxnS#k979vo95Gp^p0sU<nq(rJETU0vxJo>B)4XArM7kH2$6R2K zW7Xe^RpBy+_urOI=IP3A%9N_>%&YHoBwo*PA?^b1oT_m<%x(zuTvGBmd?B=dCgixO z|APPw#BF)#+y%{^{+6lgBRlLTHojYUz^(eWn*64%;*%PXd#ZSEuX^W->X(qvt3G^6 z^?^hBxlQHU6R}%%)GI#hUJ1CC`mm+){TYF;e!p9J;H~nuE%oslc8f7iuX1;*@N0J4 z<+n#KRRNJ|Y$z)4$ssV+2L<Y9lamO(%3U|r$E4K9HI;9D!0n#YN2tmh5~^QC!0g@r zRD6NFc)Ucd^)!MQc(ynL*%<*Z+ZhEVEJ$;L<M#z53S<FK0tWxP4MZ6TE)Y`$<Z(Eh zfg+ZZ?1OFAut|utt=KL?8OV;RmX7Y%@`6^&mK$2X8N`nOI!GDxJ{ab273*E#*_f@s zZC&^q4y`p=Vy5lW%aO_+jvGjfi!*IP7-pS9^D~zn27`IZ7(3(764W9%jkfVUguo_5 z-AuqHNRJ~hdC~@QV0%bqQ{Q%A%xi*8BvjE745u68e8Q(%5n4siG$ekCplOAP6GhS# zDG)`{7D*6E)0iZQ)HEQ}ilk^s)QeQm7Kso|(wH=f)U?DgB5B$Y8k63WK~pA6L<dJD zhRq61kTeVkO^_b6#@!)lS`s3YC|MIClR8BQ%Os37qdBFEs7Vg#u+iPt7;W){ab?^a zZ7D^)n`Ofrx;lKbUVyF})A8pC1s$Vr`<UXaZLQ{ao><*j$wjTMfl+(7cPZN;x;=8q zTL*O0ZGP+eQ->JUv8QHT*OK847*TJQhIc`TMx*qDkUhGXey2cl(Ot-dgihN+t7z65 zay_rla?VMP%uiWgV3qq;+~Okp<wLLCF=4aLDC{`jSc2bC{(G#xYnU(PDZL&fFot-I z!N0`?9`6-lW)?}z+l+v?gQ6|(ur+72-W>v)QXco60uf%>Oiz$pLDY*7tq^On9>v;$ z6{{Ymx@_>>Vq_3vkI|(L^2`MF%;;fm)T%D9x|shFyDn7Jf%<Y#FXGVukOYn^X9ze3 zo$<&672ZnQLFaN9@)|5_>G=ThS}tn=ZV%EHp|ttXL(Lm!)>3}o^P03PFMF6;E?U-Y z#$++udyVMScIvb%dzt&C5$sfO<&0;1BfE4>>~yhe&@)8$)Tt3q9W%0>&b+$@%Z*sK z44<)fIhIJ~*u!hersxwU^Nh&0z==5-8)0aY_4xDqU!|&lCSCuYjup)q)J`FN`vyt= zzd(1CJ)K=lzh1EY-(2wIG)Nzn<>kKHcKejf@xUPP???hb4ME?&-c~h?#mS5bFd>_f z5$+*{9>v4RFd3Q+94u5Uul%T$s<KwqsgtV1NL8v=t7xuXDQ<37)86d3<)+)^bia`? zOX$bX<@fw_p4pz^ec3X-UuuQNHHex%=Dw<1ge!&OnEqZmhzSSw3-~+#lp)TH%ibwX z!c56*tORc;-|5EwD5u6Nxf{o9|NWlNcXR}L6bHmRBXAv{RH!zYzGF@YP@VI>+2N&8 zRX6~pj_d*}TpOBO{D!oy-l>0X{}YfM!DKXC8>F3EU26HMb{XJw=}7H+E22GmU8YB< zKX<r0WLsvNcpop2ui!y9&<*ho>YVr%`JV3qJ?IrVA3<I&fZzvS!R#Oq9^r>n-}i%B zP#!5Biao{ydk`MEw`za#u_s|5U-3VQKsiJodVPyS{15=*J9(fSLO$xf*`ZSq9(f<Z zzR00o2mtjR>32Wk58b}WAwLL@V1WGhS|oksU-aKU(SC7Rej@(T|NcpQ2m7Z>GPf0^ zOV&rcuXE@Hq)Yxypf41qD^}vSMj!c*JgAS@n@%745Iv}mC=bn^^#MCj52-IXhp-bu z7BcG}4Ukr&*e$ULT?fG_#4W)oR2_0SWS_P@Pm&X8z5ojdz61`bUqDv;8A*%*v7~5F zdLlUF0FMKZ{#Zgel&&-m$zS6`#-O=ESyTX)1DAg3FlG>X(is#VG{=@b(;=t+Qv_;| zT<IzlA3VpNJ?JoKP<;^{ncPDVeIXqx0Mmg}e=K<o!j_~Cr3Y%gmIHdd*e}%~t^Vzy z<$zkk6-Yh#M~E9zHi({-GvqCK7>FGS8zdjx`t_MrVC?IsR*$TwniN+%`DXX*-s1k# z3P*Ne<_k9PR?x}8{+eeeKOU?LD}5jv4b>uQG<dh+%z%A7<R`J-$yKGx;b&`|wM@Dv zt5*7atjcWJ8MM|`Qia_(Cb-0rpKR?ju0K=!SG8M5aQhap+_Ni(kIV1XI(aMoVN*MH zm-ikyf%Whi#GBV~S+xTl8(}r_YfGu|E?6>!>gPu4&aW;ah63*pxWbvGGy4RvvxXeb zzeQ^uK7qXTi50_C`pkrAxhL-)TLQ5Wnbx>+R$l7(R&g<zTK{V2{hn&y>`q$8V_99{ z{D;wZM!?qT1X4P2^3>g%cRXF)^Ag)ZuE&HFePsL8T~&GQZCtA6#DBqAX<y1KC&GMT znCnF<cd=CuHoNXO7VmfVkhB#x&cPzu<2ek=XZE&=E!G<<^Ka1=f`%yxWapH11y!aM zljGuaHjaNB8={~3N|r?nu8;d~46H*ncd*W{hCmacRW*CCR;$LNMjT)r%VUzeS;4kk zndp(%&+iSr+TLhcXQ-wiCI~dC&-L^&Ru;}G2dh-jjti77wYPGx>@zabJQbCu(NgZ# zp%aDWIh5+LJUtqG;%c8PRWG)3qI_Bp!Ce1TSRpG7z=pEZR)#D#l(tIP3{cV6u!)M3 zypWtIS#^@N+GQ^`R?N3gB-2Pg=28^utnWSL<y=0uO2|`dQTg|Wz)WtzR5J-@rshx2 z&Y_uDKr=UqVs02c(v?%D2MCp_*a_9xT3Fi1B~N8CgBvHsZTB=;VQe;8J<U*MSxJc* zXbOhxD5+jLfo3)3Ghf3-Kgn&WrH?GjMHSmi;KRzv=cPQqj>&lUbx*K1xn)mAQfo$s zr&+#ucU^)(fwwD@GaKrZ)aNkuoj;c?Fa}CxrwQIvuzCzd&CqDxK7H9@f7f}bPY12( zNTD(h<lZZ)l15nu=+vYne_SN>Z|>cbz)&^dsT1T^mU+KBE1UY-XD^<L!MhZ*dm)rJ zTR+Zily_YCO3Cti>Q842SMn}tq))d|MAienkI%Bu<?t^xS%ihVO%NoKGYl<l#c2VG z%Ezza4W5rowb0?}VQ?Fa<fvk>DHPhT&9daCHYCV*Mt+krBf0BQDCr?XWqSB)RS?-~ zB&efbF!AzcV^3QUgrSpasYtt%%&qI<Mi}8yMRNVP40PnlzQd!X!2E-hR{s+ZB7Vi7 zjS>S^F}7mUa1*H-yWpf`4o*koYUxt`iIrDcf8BePm{GoNQRX=jJ)G6_IV*RES#>xQ zUiKrqzHNOSA=)K#9w66c)!><XZ8<1=<s#%2zP^DBJM7-!)|9b*H}r#~Lm3zTVKlH> z`yz1L=>*USvWPZnAC<0%Iipidl42%8Ay)5d7rUC#-%^J;XkbCgGOrkp#L8{nH3Ktp z&}Wu}vyCgMdn7tt&6{7gUJ}*DhM7G<u>W39tC@uyQ9k!w+gU~0scF(IvaESbk`^N* zB80dRiz)X}W|tu7bL-4Q?1KfQ&=F>747q_eEvHH<`O5!rEhVHw=<b-Q0pQy>#4S{R z`@@DLp_ma5YSh9pwI#$9+%1OL5kSm4ua@|X=#{0`80FKyzvzxtM=8z>5fZGG>}nvl z_8XFmA2GvaZ9;zFP#G<V$n<XJrbR);T)$r3#Ui+wi$h|fI2JO~C2C2F=c1Qf-qn}M zzW>43VM^^eXu#GC1sr5*R#de==Q+m1vCcyRd{}Wx(MAF1mLbx3;r+nm09}6dHzm$# zufrcC%^bGwpHiD=r-FCS3LH9HW_D1|L5IV45{~Nf96BWr(Ot_kn=W<>U83+e@eOQW zmQ6}BLuQFHo1URFJBGD;R%bjz?3Y&zuNyP1XFM>1+3rH!aG8eH*@r>IUD)ow!q<MQ z;Wa;`%^Y@tzZf`pchTU52ek$raIqNGtzTZD%8bdjnVFiYTL+btH-5%Bwy}&%-59W7 z#O^`8scRi~DDY<z>E5Ny>=0d+B{lP6UEM%5k4)9ra(QP?h!st6DQW*OnOKRYMr1F{ zB*u1qrc<3w6s_Jjpix`FjXKQQC2ov2Qwy(Yd?|hiPmnNY{}XBF%b>7*Wfdu6Y=%9I zto!be*U?T~6NPU`R3Cf(Fz(;FKR05*(4oxv>s&yP<?gkj3fjGPh7UW<yMf?%^Hhb* zxrS!Nwk3ouSnHUcarqINif&4&OO~s;k-l6=aRn+I5x~}i>!&}4#hYe_A?2)G6(tA7 z9ARxaVii!`=D_Xx4EvN!ZB5qs=|->usjMl_Qq_1nRz>Y>gkxaYGSi^2S`r2qXPBrA z#J9(|(IA7xQo+dQ4SS5CQ8p7qysSv439f`lO`5r}aI(ayuueyPsF;#7O)zE^J2Vk6 zzXFHrlwg(0Q-d3?l3}PV75LcFk=4DGQ;nztpxE(iSBlQKcA7GD;ejoc&ynHMlrWc< zufqk7mmeAWkP|T*5}=hTR3_H7U>Pe@P5MH~i+6gHL?!&u!G%iFC?B*Somn)DLOQ)< zPz#54p-?#x!i`93lL&Pr88E^f8Kl4^8v}ZS%op|#;R<oFwjI0@Ymy-uK6y$#gonh9 zkZf!#%*W-DNm%~HxZD^h!B6gzM)O($-*VwV6Am<NRNIRYSu)mw>O4`G3&u5BN(Rd@ zYAK0%%Fau92qK-pG~*zqG(wp|W}0<4RTPz&m7L_5(wN93*CfLwZM=VWObIHUBOK99 zW|aY8TK#fZ-mz<xu5dnn<TcZ=N^TH`0rTRNS9=s60GxfbhU-6{-=5$9an%qo)TN-V zf;RNE8-<FLSWecGp?AeagKyc7iY4A0E1I?!V?-^7Aa5e^Rs{8GOp3r6FBrziH%&*g z>ERhvij{Qp2^mJ7GZYOeZWjb6*9;-0mCe`SDI1hxIw6V1c&UH^hEvO)M-<&A4Rp8S z1T70WdiyE8-s#x5jy20bdUGz5*rkU&JN{GMc7>gj&y$5&ivIUftv^_YZQT}(+X3(> z+SLfF9WdK#8Q$<kw*Y;i2g&(HSwdCqX}qS`kW5^wZkzNrSvVW@9UohuMI(q$GyvJk zWIK-O9yPbA|JPnFet6n=>PbAljwQXm3t^g%BDVwTU2z*7$}M2$G$Sj)t7cu8QQe$f z)JLZSTNSsz3?H{hTb#={+BH=8?yA?`%;ZNm9DdzCG6wGgm+)Cl^U!t9&szi7RO~fJ z&DHZVU-UZ3sK!)G<Laug_rUG}|95288MwR;s|-G{r`3hW`La)H+1C7zTNYj8;Kwkb z_P8C{1c1^&!YAXOTi7@A!43O~gjSX4R@7ZZAN4!l;TKeXg*Sye;^A0Se#JMHJLch8 z)Lw-*r90|zA}=nfcWl#7wYyG`^O;l-(V8+!EtKjAHqp)kg(*cBiW8~}@d$+Ntb{?- z2b2d?aSE&m4@xOCiWoJVLJqZhg?b6cEFwKW@n0qZ6^>B{BEv?*k`alhv8q`G9IB2P z2QI@%!<Z4p5zMIOlrw5H$~5X(g&O%B>h(&FIR`$&pb^lh=#+G7JaUfV2TH@H5tFE~ z>N@#nDmvvF#TwOTN>%Yw=A3m<R+#?S&E;+OXT65-%o_F<?^E~R8h1j${Fki|)1E+W z8crZ&ZPqipW^f+Wlw?m1CJK_n`ON6A&5hu%*P1r){lQIn6~Vih3UMA86tC48pr8G} zvT-?l=cJh{^Y*}34w_et>@sk^b#O^vPce=&PS&MNoJTSIrNrrs{b+g5z}^LwS7pX; zEE6m?Htn@Fv9Nw=$JKuR$JoTr%!MeQn8bIDxzQW5P<wpqvB8?_3?<`=FiUB+FpV1{ zOqtbTvh~sOzwL~N>)<j>GcD_KMnYgAXLZ~-zM~%u5z`EveeIXbU|BgXp+v^@OqzZ& za$)HTNO_iXW8;^`0Y0^++~`f_vT-UKCn%6mFb|#(<AJ?z_G1vg#5_Tu{$vJN^`dP~ zn$qwNRc+)fq`$5+E{PNQ3|hjqOivkY2JBx>X*{<qH7FzfgvlQHrGoOv4z>J_se!5P zkDAKYf5nU}JT<_xHhgb3b7PL|&e&<n-e?gR$`c5=37<CTR)W*OG7sKVNf?<gY=$Mt z=UI^;vR*35el<m8a0KPkG^a21fzR9xV(vvb^LQVX-co9Ifz7ixU48?fKOUhIldjbj zDVAm_voTAynkwbd1eyXgSq0n(|JZ13Zy4MNMdNIK$gi`fSK$)_>gM;7VcM5(Ndu1C z5x;KBUXQa`O|$EUjcweSE!%i)_F&^)2TDQTyiJRn9ZHN|KVAnqz@#*3>XVj)<js_u zEJ*G$-s#IFq97$=1=4urGkJeK7yUWdR$E7$*9%)NscNJQ)!6*_oz2vqsu>3bV>9r} zm2hEU5{fZw^6^5_&45<Iq^V^*ZDY3N+ITS<X&h6m{7A+)<;bQ`reQ0MSkpvBVuqE9 z^c3@f6dePa6df~?G?qC<g0A=hr9BEx^2q7XV;nU^*{N8ORMWPN#5zhfp*ci*A*R%n zU%NXtnteq=I9rkaoUtnbc0@}ucRv*dBRWBLglpW)xcdm~5M&%VI*~-4O^ZaHF(3gu zT5X(dFlmaBO_D3hZTyQP!ZYL)Jw3K9Bk==&Qz#UUNroJ<Veu>>3S&D#JG#tdD(s~( z=Z8&Zy{=Pez4E=vA<Ot;G&6~x!JERp%puKqV>G^Gj&T<CZ{y)yjMJyahnITjC}>i8 zCc2cap*EF!rb8za`aj;FOzqh(_0-XoCcovQD@kh^YuIY8%{!m#^^$557iJYY^rYDH zTndxygwD+<w*wYti(ROtS|!ijlH8=v;gW8W7IZ1LX^VL&wuy`N^IU3^ZkV4Z?p~vQ zB)nkvCT-dC5UkttQ2dU&t2-k8aTTD~(iW?`G)eWkX4-AzhTqwcDtl|Z`q&`(<0@Z| zttOWD>;L(qp-(?~Y5elCAlvR|aMQ~KH`e28%R}Wk=OJ^?K604Q%bF9%WAY|<FL_8g zzKbm{{m~C7Jj#tSC&^{~p!uD3*L4Iv5}Dw~_(AnM;f{U0x73XyYg$gQJsol-*!$Dx z%Y1G$Vx6}th<D_q?sT2Vr?$2))rq!84%-08I>gBhibE4T2YuV10k<wN8xp<YVb9AA zb8E6DIPi+hBWfFxzOHls3w60;06(C9MX<V_=tJb4qF$Hkf$AO2-oWn3{Tg>`qJIzl z9q<%4cpHrPMu2jEYJlViZ1$@*Kfw=Jjuw7vgG8fpI`B#BtKew{VR>Drx(UVIytqem zt;3<;i9)yP)=ziM)~2}$?QRu2pm%NQq2P@QXLZ|`xPktwY8Z%K^L}4=(gU!dG|<l! zd#a`O3rHF_*TV9InZ~wjVPQH|Q|`2q=Jc*Pr4j&{lG$dtK1iJ6+p~Dj!9RHq!@qma z)Vp;Lwrl!3XxGN{O|Eigw;AnTzFPS=`wG;wm2L@aV@ETPbs<|n)>4TUck}v6_J+@8 z`v%h`YR05jpqhQRv~|<Xs$2tJ!m0Il<WNJ$X51EBGj~hsJ%(49UJnktRO#l!zuhMO zSqc018X3Go_hs={8`obfqyO0F?PBWTLN8|TWNYXmW@zkU@AO}O?XEG5Py+%8qMt)) z7}R$t5qkkC=gJa&MC2N&rm|}$rrBY7(*wXB6!RE@*nW&Yc+6jz9>?zQ8ie79qZo)t zg`CbkDKcwQ_fk1Ubq$OK2KsDd@8Vi?)nnNSYNZc&^?Z$IjY<P;4%O;h)YW7%-dU2v zGx{mpT!#Byi1!4`deFxg8?2)*g-`Yir$G$A(bjLMsyT=dfLsdV7zEZhVf2{=9zp)9 z6aMo_|9uT$+=TC7zrbW7(BHnX{HK<-f2@Ivp^?o$odlD=W>o(gC6a4gmtC-h3T_h7 zg4_^VFalmeJ4>Za7RoD@kdhXp-8?GVZrBc*2D=lY$1v}UMHH{avB&A^lg@UuTAKgz z-S7+T9Z<aE&AcvY3OC+JZ#18Mz3V#l<Y(*seE6ap$qgtuuz~QGpmbsNae^)qW{rN0 z;YqL>)6;=DPzGU6g*ae3L)8T39k7C`151Q5#9Bk41??1Y^wOn78fhXyXK(k(hOD?) zJx@%vKfc{RZY{5mdxo^6yI$9%u&_9@rnk^;>);w%q)%juYBOJhPE$C7d8)9xdS~^c z%hNDODF3F(ZkahF>($xN*k9>tF>=_a$(@e^on9F3^rl$1_KM#J$n0pzT7l9wjwGhP zjerSq)B#Io?lvYadRhxN+8R1fuS63CBi216$6@?ANam0x*{I=4C`0vguBqssQyfjY zDMp3bnqta|wRdK2F445~EghPM!C$wXtd3WqN-m=$2#I)u8~o{YgAve9Ya1egOa76S zUyWo=Bl_C<Sk*1&1{!JpSdhbxNymb7qtfk>9FT&F2VoOo*lsxb^mw@s+GcnbTu>IK z9lcwi*tF+_8grhMovai?*imUVlj1^rslkHHW3EqwYRmh=w!W2TCb6k?@?53naFPBe z=8sJOB}~3ckBKRui7tYsq0#ph6l~C$)!JU`NPSq)h3S!f1sz6~x9O@}&(O{^+uR1! zzRUx8k}AePVVD*HAkZPe`n3{lEyKcB7PH|u2lE)csrx+IQJ$)(lcz?!<eiaFYAPmi zs(q?Q0^O^Mp|ptnsAlfl0O}39C5607jZxc>=M7DjJ0KWTYzEaMMS_^&;Iho;Wr-VR z7#ms0_62Pi^MlUOf$8+@q-8w3hW=^Qc}JG3vd?EVRi%<?b<id!^{HV_s^Vu4t4?I~ zz%HDcNvLTR-pX~Os*7Py>8Vwbw~^1t)R5c$4qf7+r$j}^eX>H*NoTF`I_36B(m?|b z++En`U6*!onAbyAO%)nFh9($YI!r$^sWz<6=n7tnOS5?Gq>-97_BJc37`CJn+{N#q z=aUzu^7O2fa0C}TKglHGEakf;t<ke#<`OT^KXz{CAFB)Rd8!G$fC7v7f`prtsinf= zjR_=%-wH1GShArs+hh}bL;S{9GwFmsMjlAG7shS%2F}D{504>YI`mS?14Y_syMJWs zB3jBvCFftcI4wKgJBcDXl6*5?jpP&G2{85;hwK7<Z+hVDB>6I~x@v<iK~B>FjRaW# zG{vdAi!cf_Fmey@eFEUFeMfiO4u-YgX1u8Vsl5?`{p>J^XSX&8>)mDu&o1*wqO;Wx zMfV!x6D*<j<!5E+C-MiVTJbkHh((RGzF>Tgz<o35yWD+&lb2+KglWd7Da$8_YxqTh zsRp82DUnjG@iWF~fs?j1rnm3#&b~lW(Y!zLxEjikHufOdGp(D{t(1NTfpAer_`7hw zMBODL*EroTPN4X_IMKJvFq$586ZxEvdGe)=A1HHVTxhQ#!hE6mga@b|0y;cJo%{qb zyQ2_%eWX5NqCOzl_=kLW^Pl7>N5nqS@|0n-IAYKiWZ880@dEx=aQi5ZXeeDCG^xBP zlX#P+vBwRgPV3V(Ymhyr5eK*zLCi_}uR#nlx8I|<wh^sfWb1kzbo(_d0^VgG8UE;U zKdZ2$2RMS(GW>CNGmh%<JGdhso?zHl89D0xOK$%us{bRme+_n`u)nFhe6f6rzFPf+ z{#UvEYLyXk{lWtL%arE7zpB_<o7(-4C10_M>|Y=s-dg-eV=xNPd@76Oifa`NP<}K7 zG&Vv@rR}6T!zYT`Yl(D1X8Wi=*h|qP$yk0sWEA1htz;i$#$E0k8bl;<X(bOgKW@96 zXWLsBb9;M#fY*hAV-`6QN5a^dDTt9u!$&Ss@!L6a<qilzwe*GEa0#Bb_%Hu@i=lln zsjR$8Y3;oHYLrj3Gap~MNN>s9@WbHhwmqg_tVSJmeXQv7`F*uYg$)#*(OL~Mf*n(d z7uu;kp`WVFyD`q*m2zb(vAge6mu}z)lqj6wYA@bC1APpg=DMotTTLD)fN1eFB_u^Y z7hl?hM*_5XJgwEOXUP*UUyN&2YR;Y|fK0Z2A(b03%x1j=Qo9Y8gofbCcPEs3Fkg~V zoh|NUZ$P-{!d0`BFJJFUbS=eiUQV;%$URx9Lba*bani2Ec&XCvghPq|-!xmz?Un>2 z%d+_>)LXoQv%<*7(%t8PtcgJ;vn6RbKZFEDc5{#u?wrQvh$)KvqKKmLJGUm`Sh*Je z`{~D%Al&3zC1tKE2&^f!O)IAa$UH@O9^Q1zY#32D7N(c92;C@d9)+Afav=gnp#?1C zpKqF#e?SMgM6Q@k8KV}Rqv}VbNut%qFlyrqyU+Qskkfz)!Zgcy*b`>b9ym=QwIY}C z)9R~$!+?hlyL?3t5XOI0a&eDZ7ny0C!y=7nqeQtYl2*>%wJISpQz($e%p3|86^2Ek z3^QUgh69}t-K9c^5#wqkH8FW4Y(=w3B+jQMY}CS`9<^uO<#hQH)Z#N5`fwe%JLM5c z2B|wFL$n)V9iWpbwTY!EsQ|bL+sRqJ|5+Rd{=1d+pOO6UF}_bQi|F<h<5pk1s{iOY z`LC4X|24+do&I7b{@oasooFw=sDLt(+i4f&s?Mf}0E&W8?9xEAhaW%~LP{cywrkKA zq+X0tM)@^G_T&tZl|ez)2Yi217;(0vX10sWwDj`wzTxeC&2pZ7zkAqp|7N{LV~7$G zgOuW$R#xvhWEL!&9j!WKg%}GemcUG}r-RC%ZRldPj^5&Yq9y0yiw9PJyxD)=k=%xl zWKAFLwvpp^C8mw?GyvUYqHQpY!DHj8Pp}IStNT-G5_(Jh`hl3;%NGCl5vF}`%=PVN z{OD&o^Xvgg1@4&O5vd&sL8joI80>D0ajKdPY?aZSJ({Vq!y7}%HA^5Vn%tY4kJ#=D zk33NnS!b}Yed5-Lp|I%zPP06SQz-0DqTd--$!Ixo$`9KD1_Kt|&AaPT;MBhYlvROg z<%s0ktd;iEV&hP%ZiBDK9Nl?qq>B?pvR9?gD5NE1(CW$RV_@0j*LX}HqNbgHPJh-U z^ra!41h3eKGEzis4EMA-1RC3=j@&c+P&+k(N3P4r8Db#Z?2fU-=$qULW#a&HcF~u1 zaTRTzAeSsu^dhbKc_CM*dvx~QrSTbb;4NZ{{Lf^*kQ)pZEv~3wib4Wc#Zjh=`XQGc zkkydNg}%(3&P3In@0*(f@l~8^aNM~`NZ!nw`<}^cALZ5z5Vj_o=>zl7<EXR+IBw94 zvJ+NE)^FnAdsQgYt^Ot{LnvlUhtmogkSblG-QmpA1e!<6ahe;mE^o|R*!xF?w1ep> zy@EMWoq|X+ih}f-ZlZ~(u|m#;4CO*kEK94@V7?0Rj%N+R<tM(1TVqD$_q^H*BXq}X z75hiUY$WgUnf?3&n*9(WNGoaN!@hqZ+5Q>G{~qGcwn^*dU-EtV^`Za&BI7dl_SUWr z{|(`bj#7mC&WIv<YfK@WMhb`v!-q{FAVE49gsR9$&)*nt8rtyD@D~jyy1U-)dT~lj zeDK)0`9@~J$PhwCxU=C*xlFVgF}ME5$@Kb8CkpO>2x7ZEexqZn$oiPM(>x4PSi3|A zMaV2d+M7%BunmnY+o`rD=M(3hF~6HdESZ@$OF1U4s~JDd-VL0T*YH;<?fFlIe)kGO z2wEZ9H;5+(Y{SF8Icy26f33nlpY`8Y0R?qgitlTqkAEFzT>n2-LDtaWYuEq1B>%O? zm8I>GzG!rG3Sc2Wjj91D70Gb$+&u?E5SduW$Xe(uSM-OlxEN+*3>dHAOU>b8(fkEu zd<B1>U_9<2NS-tj=*)kS=z1RhFUrm-JhN@v+Ns#KZQHhO+qNpUZQHh;RBSsH+p7Fo zd!O^1wf>8PyUd&1jCZ!#$JcvrEqin4=g$vdd$3lOAqSdp6m2;JBsOK_x?+AcdE>CB zS3iU1xucmjhC7;#)uTX4p#}>V?5kMre)+VRWx<8tvZLm2IY-VF@70#s5&JCPhBcgn z8N5L1)(k_go27zJ4cPT;XRX1lGaIZP%a}Fem#ELw7O~k3UwxR2=E^cMm^B+%2nv_= z2jF(2zX$X4PCi4<U7&e)fBVx*x9+%Q8}MJ$>_r~;FqCh8;Dx09F44k;joDC@3sT2| zl3z?sl$=0l9c4m!c&*y+igaB<3RSEYA!yyohUKwv3qDmM-+E|YBVz0if|P`Yv#JKW zFMl)<<I7RC=^&axj-{s1HbvY{8N*a0w~~*Om!Gpo+E~;G^w)xZmL+5uTuv~7URzre z$JepU$ytZ>;2Ox)=u?l{C!|2?!J?e5tD#dzU_FT+KAoGRJUnqG9gpBIhARpaHOsKI z;Vc%T@d2Vr?!~_guOerBn3;v>;)kXye?w6np9o$X+h>N~6nuCrUrm>g&UT)jyQH3; z(|huf!41!$^ASBnQ(cYkO6n!T?6)PcSMDKn6{e{7n+(>^Vgr6n0oYL(d<K5<|G)z> z#3I-XQpY`}APq0JM@TKpE-H&Bn@m8aTSyfqeg)G2Q3J;}&LE@r&?UKqm&R}A4j$tB ztK|ASi~po_SYC(%?3+@FZ%W1f50w6UFh<_d&fdh)*}}x>|3kL;I~{F-9+^jWz2vf? zI%$TX2SclKU|<)*MOqL=JdrU-xyg;LQE`E}91*SgX9!siy!ZxG9?uQXi$a(cU4<V^ zc^LPm)y}4qx3~4rFNY79J|gb2f}l(lcFxU#OUkR=nm`n=XY4A*q!wf9CDy<#^D72q z&T)Tz^#>Db-5Ah!LZ7K;qKd^&;@vr1x#FDT;efO8D1&mY@g(#v$;5o|WMmDsV&8-Z zF(FVlvKW!|aQ74l%gYxDOi%Bzz?_=^V|wxZ$w+r>-lrsVD!T~nS1PkiVKI((%fX+6 zJC1{S^^C9^Qwt>PI(pI%q|+}fJ1X2K*LV4AN%f}D289fb^HVLZ)0lk5=AS@e`SZyJ zlS||zRJqd;o1ERDHv1K>i3*ruXo|VN2AaHt*gDAz_w)7&!d<{<(4G~{)c*vF0~ab+ zjNd!phe(n#3^so8l7}>7aG+-}y^qMhF97%u2xC{|v=4Ljx}m#3JLSu_k3e(>BJzNL zuGKYh-~(CwRxnM9JlE65nd=+C9!{X>36+}TvFPKrOv0GX&k2Mh-$+8!$~EW}Dt<%> z9@KFaHwiV@23!lNi2)pjQ~nfRk`s0@E~A@s1fD5>JmIE=e<O^>QSTALc_@vddX11H z*J{^xZP`Sc-cM=_Bhh9NOqKa!(Pn!Etu9H{7)b{y=&jnYI?DZvy}uLoPxf|iLmsof z+1vUqg=qfw?EPC5lU1zj=H=0Sr`u3MGWSi;YLzx2l_)oyO?RU-)EmY?HR6rKO)1<5 zIHjc44L5rouL8rRK7RZmKk&+fM^8)gJvsH5dFMX%*mgSouIPP%)CbSWiMf$#j}eRw z!TG}pBG3?wjlhj)0v^Fx3EjuxcbH^suhBCO>_ZI%c$~DisW((3H)^JFmYO3|9*egM z7JaH&X0v(8agbvoi|60rOhT0B8n7ak=g-Kr%eAITOgJO*)1zI6k9M?+;U*b`Rk{r< zZ8v^H+kNcc4J%z%E@L1HY*`<+gj?zIC{hJ~9^4s}YqM8fpe*(jrCFqRmAb0r2pias zzDe(!Ms|$DtxsXLQfW@*iI4Ef@X|bNIn*FGk)2!uOCMB=WolNAwvf0vt=HI+H_5h3 zY?4N(>M&JgR6`}^ECAF;LP9Sj<nJ9es>0QAXK{);7q8FR99C)p1s1PU)ONPptl@3{ zT<SU<@Yq`1vT-CXt!Qex3YW#=VPc5hOZL>jRY}2wVGw`q*ps1&ZRN%+(5ck4>6~_R zQCLXtiHZ`BHUe#QAg2FSx2N>e@n&)47QJ@p9Ac2G7x=3i5qOStFhY(n<Xr7@zI#ti zB<1OJjI=fa>C}xRQ3DV-^+Yvlo`xe>L_sF5LiQT;5lQHi{%C86=B-C2-iw(q=i4{( zdU0MN&#et<>w(@WC=D+(ts`Rf5gsZ?eMkpRAum%iN|X+PUGhs<z7G(n4l*9_))w*V z;72oDC}C{br6L^xIckPz$6{3?65;x+M=q;qc%PW$Co?~eU;-tBI1QoPIHb+bDtWzt z%~D-5+S^Hpr6^@RKOI79ULv$K&TFk}*^~ihM&Q#5X@V^aH3~>d5x<5YkZ^1%=Jpp4 zi8jzvyuYyjJKX=o{#xJYXW_T8RpB@K|Et14#=zOg{QH(GWNzU2AAkQxVW99!c0(SX z=YTzp8$X{W_U@t}l33hDg^*R*&lqJ~ae$N@OO<T|UdT|aCGaKds^b*296THZuTLyL z=RBxIYBBhl$I0~f<ZX88ai|!8-c3F@k`>5dovp#(KuO=t8=wO)lU^Xb_%n#<RJof6 z$6PvHSyR9)A1<7iuXlkb5Tl)Dd?~073K(Zjg6TROqQLlRWm~mk?e%Ct16GLd1+;R) zi}Y1X!OMUu(QwtJ$e;l-=@Wl28kg(YPLV5_kHzOp>|{<KWCAt(<gzTzipx3e=hMjX zv1f#X<a4{i5QJb4^Bz}ugpz;(q7T#zu+w2zWecVZ4;t4T`_o4uKUi|_0-sKWl}bqP zchqPa0`u2sYu?j3>w4`{=gVYw+9p!2`V0x<i$)rW5<aJ4Rl4B;?!0<uphM;ovd45I zS_7OCtbCkM(in|Qg@P!^Se)t+RenTp`R_O%kL{%qI`ob6sq4B)JbEX-@gqi)tsfR< z5mOSEc*B(0Jxd-1Zt9c2RXE%fItesM8S4eJLK%LJ>FoKKdL)N56O8+Mz*6=8YYz4A z2mVhK#_R8wz`rqI|6ZHs`QIqu-%(I9asDR_ivRLD<3Zwb*l&~BNNV9<zax(mD@RZk z1P|gz6;DxA2Tm4IGjdyRV|QiF!GELi2Ebw!=cYsrW5Ek<V+!ZLfQO2m;bD5t^17ak z&DHDu(H4z^refW;Iz$3y3j<5r*%nagx#nm;)$bDG$bHzLPmTi&oeU<CQWiSY0v9mN z8;Ell8jwFH$9QYa7!l;%Uzn6u?2CKvocl|7lxbddFsSG^Py#l1^Qa0pazZ~;qx2a5 zkqCkLmo8uGC@-GV`s0B&^F-r-oQJFTsM>z?9hl^_V(TB(j+tHJU<mXIWkd9k?6`>- zQZcdhG0fwlnXn4Ea{qlrhQ*S(#EUqCn6{TCT)deGSFl&%k$sDTz!ALbY@|OKUS$WM zFf&3}IB+a&upPLbH{8|-q=Q>u*1`FowdsqhT00^fviDJz+O}?Q9js34KXJ3e)aQ&* zq1hB9&iGOia_8|c2v@ee6cQXfIN`O=`c=&B1;~bIJmFP5$(_?X7z9b)&Thiei5?OR zr>b0g{an0q72aUakuI*pR?WzN(nH)g(e{%jqguDbfNu0bZU_gyBwKKz&H_WvvpVys zkF=+cqoYnd*jX;=T0KK2x7uI0)m1+WYmMXyhW58apIkk>*v*lynJYxA)|*mivdfJz zo&XYHp+Tf7XnG67;m|0(axTFnR*cq#HS7JQK7R-6pUAcUwt!UqRv*5<u=~FtCu{c) z+LGme$qsyL&jKnWh{$bljgB9bm0$LVOrZplF_6LFnIhz3QcBbC3)~yfpFk`%QrZsy zz6thj8~aKb+vCYB4yNPn+Ur<30Gljyd55CH{DU<4t~)@wcG9w`<*+=By+x8mPu<<8 zm0#glFvCN~lHF*W19;(MQukeDBv5puN$-2v;#t912o<jIZShBu?5^o&PXp$*5y|?? z&I3n`(1r_W{ar?+S4M`g3FN6cwjtVx&U7gd`HR?EEjF#zEu0!Nrl+tb*7Z9oWB1|b z$yL1K!bx@M)SVC|z((*jM5Eo0ijB=XI>*oZ0?PUM{N`Uf`1!AD2()=OPNlg6p=<$k z17(Bp?5NY*0(J?@uXaT?55Unm3j19dEcugR5Y`4<c=U(r;x1?BqB_!@ry`V{7@1T` z%7ZakCHiPC7GnLlL@EV7qL`yV={N<1TX9WxdAI+vMEv^+{qyW*-?hBQzRzv<yIAM` zzntB7b#7s6_K)++R@##N4u1bLedXGkG^|?W2M8Fkj%tojho2{k6&)=?M^79Am7W5E z`pdR)>n+iJ+$#+o$*yfyIC3rs>}Epkh6P$-#u`f*e<W>c+S|#u*J*n4_!`gcN7R8P zFexGealEAfRR~O!aGu0C`8=Y@AtP$PNR(6(E4_h!0z73kRIQ|ZiX*Vkw5#<OB|#3k zb=WAO66&<3Y5%jenGI{Z_^jhqgh&{w^=OCI2DRq4j{<dLQTJ|&u!n+s3pZPEMz5{Y zNsFkT$6o3(O|1TJoY6Z+6NPHcsvO$3ZB0>SU@NBY3TVNlLSR2U%8uvJ<gMg<7SG=l z!gA@^_)16{B18w~0(@^skv4aR>>jw`^;m~)Syhb$rFow*aCyX`A1z1D+#<`Cld6hN zOIF^GoF@Y<*;L11$L5g0nK(hrB$m33rPg?>q1fX=4aCC2iZDV7w1KpQ-lhO%6kG=^ zaI<Xf2;~=({n`-xbb4BUmG*CF?RZ37#iy?~QSpyTA~t-2QCzOE7_Z-*96cN>JaXIz z5@ZQ?e?CmzYTFEw+cG=Kl&RMy<_c>T2^1QwZ4K-QpV?f9RHj;grTYQJ)+d7b3^CJ> zzzrO#4X}x@X2wtaL}p0AHcJW}z?)53|4|%rF2610^9wK-rw`Uz7A}8|Q5uoGzhOEA zh;tSMxD1Po1A7nIGsB>_F1P<(`V41r%essWS2M<{7GAM+sS0-m=vL}sjHgBp_F1+k zu7f7K1=;iSz>2#GM?M*Q8h;WS8~u<_6s0LK)VIPg$h!zbZZ6Sp#bz4a>|FOjAhrD& zV|tfaP4LH=Sv6wb4^c}$Pz;L;p8jng@I7n!_LkA|r#$&*HdFpPQr61OK?LKbez{rP z3;dz(g>!mCAeSH$5xm)fQBFd;C#-TQFi%`~7OZI*PsnMoa}Zl<c!TULb?hy^e|=#8 z{$Bj^jX_Pz+4J~TJL~^zt)=W}Ve`-T<-6AUOYelBj!5u(ZtCs#0GaDW!?2<m2r`&| zu)(ud(KefdXgX>|eH{p**=nOBq51mZnPll^oXoEtx=v@Mb2!;v9k0BD`3YH@=I0yg zZ}ou^xa@n{x=VgrJKze~y{W<GuR8J^JF;T1H&B5ZnNHB`pdRGJ*(Qw^;cmD6AXrJh zDxwj5ABhj@I`W9IjuC-p*XFi-y<10C>Q`BKB177NnykO6IX6Ao3^gT7x;>euOE(JG z1EnM=s{AZ5(O`+Zgf$&BXd;=jYd9{S!3ulb%(@N|3<;X#=6bFHhnid~Y)Ko*X~g+S zYI8ggov=Ui^r_`Qb~hVO%>2hFUH<bN9X4)PEUX6@ZyTZqvyfA4KW)<osJpD8|I2z& zG<NnB!eaXVp41rK;Rh7?5FpW&v?KL}4U6Ok9KCbSd`|jYk|JeBky`P5n%f8^0%bu_ z5|p~Ih6a^>cznq$BM}ajr4!-L5j#H>69*U$lZ3_UhBEJeN#fs+@t+4gLL3wF@GXa- z-yM3||AQp{$0bsA>n|&aFB{%f<3?}hVi1aIWD5yE8{|5b(@=t98*4#G;G}|mQtCQp zV}iBCeK9?p9q($n>6hI|P7%{GBBH{BD7fj9m$I*@0}eK;28jb`=aS=1r+cp69iHbL zuhgACuX_M};JB}Ik<ghOtoPR2#`mb1Ags@;)D0e5BV3TkT~tOA{t?f}=3|s&2I<k$ zrXnL10r<<vSt0rI%N=mfCWk1_{Wk_eq5=YN&=@6AG7$dKbF1POs<tw8lJZEw0lHDg z&59Cq5;t<`OSzh6)ddRb)g%5d8LCyHHrP{VsxY{6rHb{%%G5}`JRC#>3Cxj|3N}iG zx!>~@MuXHz1s>IPoS4lIp{hx%mzxf{%GL!b>zrO}sJT^<iQ&>Ts!UAb$}|^QGSXX; zva~WY#Y{0((^#kN;bx^;ScWc?JV($T<(kbEd-5;jF7Erk8))-+ERY|{??hGUOq;B8 zOp&F2EwgqDTX!%`Vl_uYt4{+#rkp_Ey*aNnSz`2?G-lakDYu>t@b^=*7i8Vv&<5>` zQBtKbJ8AmrQekRG>m+<9xd}ulQ5|Ax?irfjnt$k;<~=#ljEL-5w7*l>EG)O9O4eAx zF~?(9KODXwsC`NEmM5KcZphRJrBI3X*VQPXL(VKXXj*~NNU=%+lJ$!vlOTrM2jp=h z2U>fWh{#)K0H>HwxRIo`h9_w>YEPcB!O#|Wx70*-k)i;xm+o_C3a}Ee8n7a;3R#D& zY4>qJ7=_Y!_Bp7iY>uP^{Sup~&L%BIGf7fbC;#Q1x9`KPTptam>>U<Mtj)>nu;n$- zh1V!i))q+o$e*icp%SZTye0G-^CFer@kD!+3ysq{At*+ZsJQXmbGiUEzfw4R|0sow z@21x{`RtgQNbj_4JX*#|Yk<PcO|8YZvI@=d&HY6;Tc0F%ou(E|wVGwFVAIFj#n6x- z+&)VWE>Xj9xS(Y!(V$0>EJG*XV@BgmGpl4KA-4x^F^u_aPZ!yD_K9F4)CRBqGww3f z=BL1m(U1#*g1CEpf$rVM%soyK*&#`naEr*~Hp!tlQ&A;CJO9|6skj>vqtsZvskj^w zquf|(CP8=f7$X54i%<(QAs)h=BU904*hf%YEwj)YW_&Kf-IA&JPog^p0=>bu=<ig~ z$+zcx>IZHSzdc&84=HVeN>%>02&+TBVV5pjq{BUgUKml|U^>Se4&&u0Z1*01EGN-T zqsb097lJ$FYUyj#2eLhqcbItJNLB8Bhl^ckR~*N{FoOW^tUq3RPn}%g-Z*U5M>1L- z>~}otxEmc_=43}P5qG$p73*H?%ff%e#@P7*_~JiiP6p{<Ukws+n~r$wK{zEoO;vbo z?6gaTeDDNl@7!gIqq%Rm%0C1se{!yJIaE%_O8-d6BdhVGOaSl*uXZZ+B!u+Xr3?6T zseiW*)1!zRo-5|C>K4}!ZhJrCU}{{p!sA>Qiln!aO9#QEqz9s6fLQo#R4VZu9s;6s zW6;sjRSS$s?~%zBViD^`5MHkrrDM2BHe$Q|xjR1bbUn}*TN7M*vK_4E2MSUq67@c; zjtVjJnYz0n21k;$9{jU(ef;>8oL}llPM@ut9OywXYW}iQGCMmDHM?+_Zo#0Po@gR_ z`2LWn2}8%3ZCYLy?v?jW;LdFPerNFWQ00y;@BLrbgTJfhKlPNw1x|4j4FI57_<zVy z`p@>Hl8d2}vxT$E_uSXNHFa3?dqeW5neW&)QJT>yahz3x6dwHDH~}6$9MM&<Z?!H7 zz(B!SoRpqEJ$+ib%&&}meOYsbR<ODn%X}D;93rgXdol8vR`XJKW2I;1`Rz?t=d4nE zo8x)A-HFMGEIt3Swioa9sx{~S>(9<>ic<*M46g$w!1N%VhC>z%{HPP7e_}W*_yIAM zY>NP`Y<)hK)#XV)r|envY9EWz<!abM+p{wk@_|QIror(2{V7*sB56&#-v;gBCbeva z#tpJ<_S7&(*5r{fF4=v%!H;89$A+*(R9RG~dCOrE*0eAw8~xG9wvy<`ME3TyL^*pQ zuHzJkhRqPFwjE*Z@$iKAA{@1HBd)f#j6{~Ksv~1avh2-{n9-WnJ<#TRQQNkl$W%uM zB(hWoM-DPwSyrd{WVz1{o0CCY-1^`jHb+A<E*tEvTM<97nhub;o($u_g4rRQzT_Nq zf)dHe>bWlt&Tu?lPPw}R8o8?5et}}80S#?UUM5ej;mX!D>@Rt^N5jyTnku%k!POpJ zyKJ`6!PU+TVzIwtVELl*jkaTPyn5qqCxz;b4Q5umLkaHfFOxv6G}ZQ0H5Z!fO{fA} z3y_;bfD|&=(YGvPo!mn-WQ2$0P^mT3T4;stTEL04FnbPe*Hrh6)X3Y>!B|4O2Wpuz zk9eyMVR9M9n{1=Ah?-)Fx>acuMAd|;Rq3qulsq;JS6|xvT32nY5v+SH(Alo5HK}A1 zlpjFQi~WL>fln^<;TdUg0u$1{fO_%zWY80?rCZ;Ne(BBx>QU)2C$9^vv=kfJz=gEA zhC<r>fc;9z`yQscC0I1$w2d*tg{gi5(XbQS`E5RlcOLmF)ZenJ2_usPzU{Z0ry=4K zkJF=SQlV@W{W9>w4y`=%)OP3h)}9J8bIoek)Cx*w^>SPl{{f?&yK8kmn8h<#Yn-l> zR9R*S*ZQZx&Rx&;RL_{@a+v%)?%5saK6ul_rg<6Nd~s8WxzL!BI*AIkU72mrUH+YG z$N?i6+$AR&%F$VKV|u}q(=uymMK;_1(1HZ>k<sTEcL}UiHA8ZCrRI_R6Jm8mG~wnA zT+T7aK{iv@L~^|RDq8rfkHY<)hrwCh=7yA2){MrHI{t!u6){7a%%E}^YZQrmDWp*8 zvc6s|-Tsk`V7F<ExR52xhEj67unQlm^H7)0hD4TOv1->+L@NTgO|Q#E)QETY2!}N5 z-oz&O@0Y+otK7hQH9Au7bS+DAgQYRvnkQmHVR9pgZg*Ft2KS-OSqRTS66TVqnen%? zeKoyOE+v|@>}c*Z+>C17xbPicr~D{BHpfAW-pk+Zcd8(quMdtiqH;GgZ!E{>k*Lo5 zk^_X?No|1<sd`Q-WQ@qmH!vX<v#w)2xNYsZZR(Q5TPWK59LVDLhRh2-sFA@hLrTW$ z3G?2^S~420KB1b4y=^>0Cp|e)*uetcpLv-@iPxdKtOz^HroL#Qo}L9g=-o9NW$-s3 ztwSyIPD9=G!%dw{@m*PxmNG;&yejvEo(s24Qypq0=Q1<?O$m$&Q@rw_*GfJ;`l)ut zOG2Jx<+$@HqK{qB7j!-RC4i{L1o$u^-j_PdsKV&Uz9?g%6}T}PmUuSHHU6chYU`>& z45y(L4Ok5ZmO`d0$MP^O<{$CmblI;OFl=2o>z@jqUGph*^PtLjHz#V@Mzqbk2r+dA zH@~)qVr`%22oDwYSQeU-krRMB4Vd{x1GcDyF8VE(BJ|)jF3xYCKnycV`TrOb=R}Wm z#iub2$O<7vKnC)9Mz|&Fts$O4jjS#m=Y+uSh4CRXxX+7>Gm)$h@Px1WWq;ClD`%zU z>#~trUKO`e(t5MuXxGEP_Nm(WvF|lh;nL7xqHyR?dbJDNS;f7FdKe-l`lWa6{GLN# zn~rGJx`n0UHX8;Fis>~=mQne>%E#5!T+(oL0{)>jk_I$L7{ARh<Z_;v!EDcMcf~vp zE89zDZv?NLEc)y&4Z)6mDg#X`wTM=~^=>Gn=~1sFC=$NH9BnHQvZAp)8r~HL&h65f zK<Z8i8QrVJ#*C_PGlN%>9O|Piv>>q=)4zPoWYdCcWEY_uaL%x8aYRkmeb#_vm|tUH zPBA+qD=%j+rl1{Xek+w^w4s!>5F}^OmmGpRXVlQ)F=S`C-?r2)V74rAuKM;Unje81 z_dfM4Gq}g;DID(hr|DS5(@Dp+q0XP9NcM0#iIOM6Y=I@=Y#W;4YH>cnlr_P^-<UDo zGHHW@9j}ACI@%Os^hM|u9zzTr6WKmdb#!ij^riCE7^&UOR_&4*`8-Lu1@KLleK+1n zyrpF~8P+oSz}%i1s7<{+KQYD-LntwBLuY*GhsEHX8uy{cKVZATo#q)CcfhC#v@)sk zD`Z@+=N}=IrA{LnL}3P$nk6-&SW-AnWc=+k=g;cdY3f-tCr+%IGyHDsj<mhI|H;Vv zy&c0H1m}1~AlqXx9Qx{&mMB*BLX&eNrR|=SNR)+rbeINRJ8-@j5vy_QK>HC^8S5m& zSNReir8=2dABO}H95tL(X<PvILfIiSf+U{k0Vv0iL1y9&Dd)7c0DX$V7&g>F6D8cm z^$MC-DLrC$(8%}!!<(>Y#QqDim*~KWnc;($m+k=Sh1#Z~MIR0;y_OUnGT7>)Kcf!Q zYeT|gJ!(&$KYVK`$kP)2`T3-NTU$tCkQ<{nmTn$aVpTv3e|KXa=39ptJfodo2e=hS z7#RV*A;3Rn@qOL;VS{cd3Q<K{9v<HU7<}*rZM>fs%Wk(abRQSXPA?<Bw+Qpqr%d%^ z>geFn$qs(KKn}De{V2!L8(uM9okB<4UjlIOycHe4?V(86lUy|zUNQOZ=gEig*e64K z?P(TR?%R6)zBJg!46(*y=@3@iiQ7dCSYY;)gsaI<^(Gaq#%uJbkL!>^nAj|Fb4}MM zQ-AFjYX+myyoiWp4M*c@@hto$h@fZHH%c`wH-Z0SE@C|6QIG9H>*YbI`6jVCwnI0K zRWOGZwknb;mUK97DKOYOUDu91$4)l<&eWlmeTsIwc|v7&<k&kC5$!Q#kk>bmR{Vg~ z>|>1ZaH3OPr^nGPLu^HPxN}<YjCpEr+EBc`Ju<Y;9UYDb>QySlWo8DZY;H+*K5jqQ zEZ@LJb=w0qV8!IL*^FTQqO_(8SlVTjCwtFG+Ow;eF!~^-&RM;b7fU`GBQPRX|4W`h ztCFt*JKmX}GBf|%>Ui@K>cuc(rk;MJKlox-eaS{d%#R0EG3cgv@>q~2wB4~ieTjYR z_q)1#XJ_Jc+KZyi?!u6Fg9bp8@Mq@>*>PAcThm}FAn|RblNvet{afH1@gN6Uw#k{r z>S?Ua<xTK-dZC&*^Z2`U;WMaSeMxVDX+9NO9?qRBEZB*fzK|%b>HrV5yqvbr2Zv)E zJUfGpp2|9AM`S^SOv_WqD<yU^?^D~4kspHS02jLfasok;3X~G?g^WD;6xaJ|O?Tab zuaX~s6ni?G?rbl;il2(bpvK!Z$MuAMKKLr!tx)Vh5#;JUD);zH;^32m$=gHP`)mP- z=lH^ll?nElkx!8b0FdoACZ$y3>^a#J`6aw_Zwg=P<#km(9Asp=EVYtH*e)Tz5`a-Z zxR6JjVS)A;mYlsuP{yvSs2$BJJ6y50>HOID<02=6KEn}O{HdVuMMBy5_FQg8>yx_J z4d7A4emq7oro#uYY~u16*V?s5d`NT=8lFVJcYsmHrgf&B;v1Lgbf$x<HZ4I8KkH$B zV<YzoL2kT=3epT_ozx>x%qFp;B@b<fq`((kf5T+?&XEPy>(_oGr4G=mXv!KZ@1BR; zBfUzqXc<~7Pa7J4+NcBQhKPK3s9(Zp7fvi22y~-j)6xZRxuN5^u~K$vYXTwsXB1y+ z?_Bjolt!Qf>}rWTO+<&j2av3f0YKyyB@UYEMhwI(O92I`0jxYcUCz9{dNpu{|CWKA z1GHEK2`ulTjCQPqdbU#@_!=V!We~_-9?4a_F(R5+S}|xT8^A1q-T>Y;B?ty{lAboo zY1~wudk7X+8JV|;VzVaQz`vlb$3Holj6#TOj2sKPo?lHh56jTsHVlL!gxwj>Tj|G5 z9cW%Gz#%#SI}Is71$ZAhNZ+gFaTI|46@4~LN|QXULY}u&U_+{E)^m_h=>7zTUxYEe zi+tE)$8CecP(O4l4M%Cf-ezG$eCbAo7_zz;i~2cpCi%l+F&j8H9;AIqKR%?3a`5_( zwAm4sm6P=tignzDrg{VV;pUtlWe;HoyLYqU@<-*@p$geKA-?Earw;Q1@|PT-MsEhz zW`JYvV?_8+77=g@r}bgxmi~;|&?>8tEN#G>ZHsjw&76IjF!;y&O-pA@OC?nXm+&vK zR5!6!H?ec6Xu~{&-fFUZi$!^Qh533?CtMJpoPxbMvvz(IZF6-ewm98dV%N)aoh}cy zK66_Xkyp5kvA!m_KyNK$(RNU*!uy^8BP6x$xh=yj%o~KT75wd}OE&#zMjbW=L5_m{ zj*iBXqf|+<^okjl@LVjCZV1Jl;qz4C^E|?*D#E8rM2eVy{d+8mBPw2=VmWzRyl=yu zGau%VQMo)SI<V88%rUf&B9k0Xf&28$@17^W>=r^s3YP<v8Uu3|0`-f>*f5<RkX^`} zJ5*Hv2J#6@g*eU|a0h`cSuiYlAlV)TV1KJTuXwvz-T-7Nim;qj7%skWm+b;#SOr*K zi><Q@pL+%kZmNhfRo!97Twx{Mb!Z2XH&|(3XXx&h)Xi0>qc_0Fp1{p+AZTY=$zWzl z|G_5HjZN^H#SQfla5k0-q;ceryCC+%Yx6iaOX3)|IQI;OXQA$aLkqx7j-)|HQ2$W~ zV?KXw0aAO!idzVvp9d~}2N1hXMU_#o<-k9k6^<$Cdn)_eRE%sBAe>+zesd<CD8_dQ zi|djS*COiF_N#ku@h=hMj1$8^9Pca3%$GZ&m(9=d)aGv##xt++EAmOJSXdfogymVB zhP{FGzmxR8v-H2iRR87zEg(I=Aw}v!6W8P50hSJX(*+fl!3!^QgBbS;Is_8DQzJYZ zY!dE{!%^5-nXN7az0$2HxL*wKNVLbD*I*~|FOD;#onsOyIM<k9+H@%93{f1oA%wsw zI4Xu_Xa5NdTSPg}74e`d)Xoe#B5AbXcw^{_-Njv1FRc`9@*8}Fa0#gkG+;&irlg<U z!c)`8gR;B6E8&NN3=u+eSX>i)f~sIcP?%;$N?B<G(b@Kc*bIO+Kd}xwqC_RcI%dE! z1j%>iVajqTkEboM4v8soH)O2^{jw#i)+GIqL5s%v#wY!`eZufl+%iqkQtt2cnyU-~ zPTdt}>}6ELkP4!$8lJxBiKV<MaXw}@O+@k$zhwCfLgY?}VO-6W$}#?$5Qur*G+G@i z^&AY&3XC`1oP4?&XdjOXrK`}nv(FpK4}Er5)91k~W7o0eq7CpB9E-JA14b^s3BT<2 z!8#_oWSkEF;=rJN0mEYg!{f}MX#>OK_@;}G8|~HCTl<T;HPS|>1bZHVwjAkS(@NtP zUHPZ0f}Af7%IGWoO-1DH>BwDzkh)B5E~2RfJyKAQ;i#5KOUVt9cxvm_?eW7^uweRs zw)C5^0VBmvRJtrqaRPY{f^rrgP|n{XVBW@lI8yUh_#*ih^hi39CH5&0(@XQd2mHpC zL}NWx>?j+Tw2)!~V?kv*>ZGPK7tgRR7^lrR>=?~&ZuhGyD7SY`96Ys0-KL6mJZgi? zikX`p@Kv8zKBVRZczwrq2L~&^^KJ9PqS-p;s^0PAoH^KCuVsbfRU3W$tZPzA?vTT6 zVqSYjfyEuT=ERX1Chk7DBMmjDM35<tp!6O}@5LLzdaSmiT!RyNmyG93lD`%Tv}<>S zv6svu!OZF}%`OJBU!bU~EqyXfkP(XL%of=KvR80QCroz>tc==jo|29IMWHQwseKrg z`BugWp0%K|tQ|9jQqy(3$Ec>k*TkY0L7Hk_;i%e9DYpZK#&r+J4?<AwT%iJN%6Etx za9YD%a~>MG!iIoSsACc!<uY|t!+3U95PC+IK?RHOn{wcTovwdXX;!xMvB5O*SHS?D zjMh^@Vx4w?Y;5JGi0&6;>aa@9%HrGy_}#>BNi`Ch{K^2PnL$Q1lJ2EUZAqqMzBP#` zueK9If_n^J0ejByG+RpcEEVn@!9U2HCV$LH`Om1y3{V1!--(^$mW8??18-H>JI`iE zd!5#wgz^`9_-v<S(_u6rT;iqLQZBCPn!>k1G(2OkQl9e_-vCC$@dCu&_{`(}fG!lp z=1Fh@H5SJj<T#^h77LufgP#WhX9~jx1*7oN-07!|h4Ku*vVmjRB7)dQk_T-B16?7L z*r$>QzYAkvBg?vrCk-Mf{3sP6>B1N7k2GZd;8z}u6@lp@8X3eJ0)9zMgZ_!2G)u~T z0`H<ua^?_W-dA3LU>0G)E|nGPGz_hcZ)#X+KH%!`qXr&rA9OBiW5^mhk^>#({zj7l z&khmlMz$WlSMu^Xtk_*%J191S)mxQ%6m1ytqh39@7oqa@*%0QBg7bdvu;&NAb)39) z67@b}xw>`2NZ7Api2<sm$f<egIg%+vt>X3pIvwg3iC@C}niQVJFoc9Ulm+vq2#KD< zu)M@Kf}Rel@kBSMI54u>AXK|HobVNOILm!<rxv>5RQf0%QD@o@f;RrSPO_AwcsFR0 zd{`}gbmJQogBt3fy#<_P)5C->EKA7;fYg3F@-+e5t3TXB9h2?Razb_#dkxvcVh69u z)d1o46kgaSk`uz!_nwoe_LazdofTxcI><|Lbdr=}X{SGb{K>u`QCkQ7%73Y7ScLgm zq)of_i*z`#Ibo?P@T;hUyCGZUM(^9L5)ao?_%qy*wV@F8#cpD4JOi~aSE50hbqV@Q z2pc)hWGd*ZxI?g^_I{Tx$%**GK;)})J^KMy8F~P@PGgU!BNe{-rU!*L@8{T004RI- zEP3PYDD7LdB3m<ajS=PSV8V(!<s5$y)ffA?k8OoPIAtchyWBgucon82p|NrfAf>W1 zB6VJI>eOgzQ2n?PHbVJwzZz&7#G9WF&ulN^k>=cTR)c7>^PY}us#5j<)MBrj)S`KA zLw6wwET45PjrqFd#{*3IY7r#amNw%ZzUn(3kgQd9c|<M%th_jUh>L!qZJ^eMbgRQI z^0ZF^&26}6!!Yzh-k_$DGniMs#c!Xj$_$dqj@I<p!#OqRDGX5^${Nz28kQ@+T|<I= zpv{^yUubDGl|-L+NTxVyu#f65Ch|i^io@xBAb{ZY0<|63etdEwhj~GN|H^=)j-gNu z7#YgM{;ajsA+V)lyd^KLQ^P21xR_y87SjLwM~*)r6%FLw7sz}Z>wGH7@oaR*DLr&} z$3iCo0{Kih*u-nEutngpf*ok$Ife^1D@pMBFhI9=6yN;e8PY^?DAZR)(8o@qw4Zhg z@*lLBOu%umOjh^Ar@;8c94(O2-MdGU?H{WjO{G`t+P@{(2`TsNW^wLFkt163l)G&D zju&q^lKoQuG*J=jxF)gaI5kTgdx>WI)%c?4LO;QQroVPfdbi1BHh#~1t1OaWUO?iw zwnDxGzcBZQ92dCf`u*hZ<6|Z-n?+G3_n#rigOXXhlmN7@&uBPD580w|aP>-9YfcIr zR{Rl+ik75VF<;lomA+NbbRjDadM-P7g@f5CGFaES)OQs`>`Eg8`~e8aO9j*EM%<`n zJyFAlaYH7(Ml-jTT|2cp;r+%FzBfVJpbg29A_FR}ij$xM(RG(4wJ^`diXmf%`G&i6 zLbY^yZ&^SYUTgE-e<ct@<rQQ85iO(pQhDm(3WKcv6fo$REg)4~Q>+NlbB@g^u7knZ zeBL*<_hh`tmT6y>)u}EkNco^=p?U^}=+MqXp=kFCso+ui>YsFXE^T{P%k<GpDwDz$ z=WMEZ#iVmZiEZL)3Ysu2{YxRhof<~?&u~_%c@qV^8e<%pjK6XwkOK*jN4j5E0_d0v zWE?kk;nxSJ)EwY0<tfR5JG7)^z(i{kagq0Eox8L(Yg<lD;mjP-m1zL8s>WEx7ua8; zMSt%Q{Ihq!D>&l5{N0NM_%^!c{U3X=&W;AQPSys_CUpPabx{6~=l|>@WUKCc?@fQ( z^t&}?h7>mi<5!n!Do88h&l{4{0M`WoD?t`D-3b|V>Ldg^vstq?53&!k2QqQL?niP* zOx_GcGND#Y)AQc$>Jc-Ue_WL$%{MW{z_oLHcV}mKcHE}B-M&7KTT1~z6=Ds*V$RtS zgs@^-4`9424veAWOA=NbB-^*lnOXOkkc(#8l4M8e{h8*^tCVLXRtm65i!ZyHWF(F) zaB@fOf1tT&&pT-3b?<wyoh>;uQr0!wZ)LGDJ@%Cw%Vsn)Mi)MibCRq;pY_n#*DW2$ zFDNr?DVCtW#AspKG#?sgRoLk{p+>mQb|6JRh_`C0iQ!RY_E><l;DtmkPvqdOvWOyi z{OI0qFP2|`<)}eA1b$0MrLES`ZL(XoS!obcQUW|nW0R8Bf{d}st(lox{ZquDlwaJr zt6^#~@qklKhqYnZ3Y?VTqm*YhSO<-nl%3Hh-hVHJ(P*h@!e!*)<dmZY^%=_O-wkgJ zxZ`Yv!c@l;9QQSDvUQIkWVI}u=Vk<Oct1e}TA-%7Yex%O;u07PaS!{eOHC}}50w|> zg{&<y+fJ5!*JRVRc#RUVTIG^i1mbH<^unBXr)n*5LU+ntqcH4vCKDPkVT@Ka*xpx_ zjLvP*a=WXR|LQHsuNqL;^o3iH#{#uyn)e{0N(4Qr4c+$bK3Q*y*`@g+P|w*7#{NHy zv!SiJvOyHbTYa=^Juy_EH30->`WR^-<z1$EK@C5^R$w;yhx@or*ludDe-}*!o8>_w zF14os;q>@pg1fwYxrXpx_0sC-WG?+^=`rTus~@11ic1<bcz-K4aRSjr3hZk!w(LHm zG!O|@V_O=UblHFu)uJg^MamrAj~PW5lKHJ<M0fA~xp*HnlbPJX;}GqWhAma?#YB(h z<eKtXFH2h<d1t<6OF<r*wzjJ9%L!<~!NZV^#mgJRi7<VpcFRDek&474@>0_-@p0Fs zYkSlBPi;{h>68hllG4fXaCcy>e}wH?8@zj>CKlr2S}oPv#^PE)Ql|-8NQ<32=yu`g zyI-0?kgMi(aV~$+PqB?)GI`W|#VGkj)O@#AJXJ@anO)eZGM=*qYvFNA2O8Y=*k3%B z+F00g3%&f8bIJWAL++2KmP+nXG7DLAM^O#Hg)qH__eRdrY&xyr#)Y@$`@Bu=5BA*a z&-{?>Tp8}GFBIA8!e$+I2s(UB93Y+SIfTIaa7f#cG-L1&p+Oz7@L&+;;GuPRN-trf zw2>azeJkiAHc`7;QTw#Vy@Lqev4!7$?KeM&j`HSeu_WdZkIn!U#f4Ih^#MBl<<|$d zUgYUDLwplvwKiLGIW7-AWXoVUPdGtcpdk=o`*zq1je6Z<PV~IBKoTb$%MZQK7GfRu zx{OWnZzEE!yz0!)Cn_Lb-CXdEPkykn1rJ%PMpv$ha}TUd<2mT#$A^j4&>B<*Aka|z zwM@RX@WJB|oX_ZAoX+7Hd2!#J$QIq!-Aa2j3I4{1j`6T2s_yoFQwri6f(t5S4|K>n z>Q)VkmPqi(aa#rk^hFS#pJsS>82An-VDWU>#iv*<$0MEk6yAu8ByP-Q4|fb6^O%N9 zgrGPQBrJ9gdS?m0@Oul`?DivUn87$wU)=!2yJtgny(Ier{7XUqu9N?zpnpXuC9JsK zWPi^BhkkEF{Lce^|D~XEM$QJ-|9{Mh@?ZLi&cn85yiiADLBMY<ublKjPThnq8QC0% z8eO6+O+z#&)SAgPZrOpwhE+w^^Kz0HdlD5$#KcKNH_cvs0zKIHGhXhjy)&QY+XZdX z`1<*N^O|d?`}vvgrw_P3;>rSg|KShmy{?#*`7kj_l4t{M`Lm`3T1pGjXbo-21D8pP z<XgLwG&FHtM{Tk+q%gFIN<hseD@p%Am(k>vH>__%@cL!0rl=*Jjk7Avp27!z1*mmd zIsJ~SSDJ-0O;@dqme%^ccAiF~_G${IxJ-YHmz0fjb${m6%f7R&>xmp2mtsCD`lbV< zH1b8hCR;6o5)B(IUm@Sk)EXKytN6j&Nvs|u`g-+)-?a50z{5d^WMJpWYNMA=r(7*~ z`snjXnbsRh{^>t$`zE~G4dSs{N%Cr+vt^au0NZ)OqWempB@Ycp?1}0wVpFPY$7IEC zOmNiLG5jC)OK3X%g-o55L7+>~9P4+Ru&-)SDuy!w89JvzPH<g4*@~~L-KlK!5;B|z z&)-|R&d8VHc*gfJRO0;u$L#rlpwyAsJLHl<YxZS;Or+7>p;&-Q61GRUIL|;+?4uts z)kiu3lfT%M{M*gGgTmsI{g;UP;(y|0^o=D75hBIHG#}ykdK7WZ+kjl&h~L{2+XQIC zO4Oi?+svQ27H=SrB|dzin^E2nCid+OEck!h5;ZSv^0z2Ul-C?R6RSKaxO0}5P)d3i zoW(+F4o7ws5Xtkw2u8>6C|HuJ^|L6fhrEOfLK}UM3LQXT@2`Xb+M{dKY$AwZ3>)8) z^oN*xDf{}NYuQ*%MLc2c<5>%3erJEf#f1?#ozq^KHrw5}lxM9h3vRF`xZQv>OETuF zSDw5cYLX;NB{h!Ec7uG1sxDmZbt`gIUYjbbg!PaSJHVNqIxMp)y4eR<TCy1_n-sY+ z${r(Xp-&X~3V1?+F&AT4Js&);32|R|krJOGd(qZy5K@xgiclHhBB>K=z+?$!+U?u$ z`swX)`}Q&W)9n)!BCEBIjZ%LnRUVG*aq|v3B{~20{oX8~7+&_1AUSg2HhxCPDP=>I zq>FoIr+P^j`W3%N?K>ppo{q#W@#Qe|XTL>=Q+MvRV%8zzD*#^jm57=n!#-TU%P){Z zue79ZbcD&QclgHr_ki1M^L75E1rO${;Oa;`xo7DtL)Hk!n_LJOLCRhtu2QQf-%I)D zZfXvS?yj{v`phTHUo!Cbm;IkIFtE87Q1U&sxb!`>DD!_Pq*QDzjO>g}RBY`HEF4XY zm0TPh?aaO_EJYI=JJ<i*7_V0RC5y#?%#)gKEa?{);syjRAD<VgX_<=88de~FDg*;p zj%5r=<sdOaG%D~RyF`PfDo*_Z(398s2jXEJ7}a`RL@eW-`+3vLW@lSx2f#ga7%?JE z>V^`~*MIo>9k?0zK4`yWx@m(@*y<cC$bBP=e864E>`bZGtLh?$`^vs(oxc16TfDNH z4}7Gi+AGL&a5W{aU3x>ZsAPjhL(bWF*^@4d(``T_{gHE?qCWRD3G3S$Zc#Ox`F%M9 zm8_?thC|6Ukp2UhRJvvfYv(8(c|A<15(j9xmtjchP}D4j-z8`BVXcBY6mcX&wxkr# zgcrTF$tkB|(*l>SAMjmfp|$)i&*$z@&(!PuR4jfM#DK8r4lClarHS##H)!k288RsP zr^#LG<8bcKHoo!2fwMRK<BS}X5eA4a&>t+oR~mKLMlyAz^MOpNSrhS8byOjHSR!gM zJb<cEb)*S&vm`oR!>L+`WKEVg|9DN7KjDJj2s-xEklaUcdi(1rEowkJ^FmX8Gg>HJ z&^(l7h5;O8LOjU~!=jVr7JtkJ>>K}WBJg(%{tJ-5j51bEK>&Qe;o$!ECi-uO_?6AS zGtG_v9eplqU}GZxjfI8LHxmCb|EQ!T_ty}(sTW2^lOh#Jzm~|NZW84#2qZ9xq&U0` ze^if5szhho7L6CfAC#Z|bUkV0#2F`<q<_dCFPh>N&4W_YIgTfveVl0T&!1E607&ce zghts%mw2@o^7lLeAr4)T<rftOU~t$J4#}N1_uHlzhT)q<gcyxgTZgd}T7q<_YQNK} zRw$uwITlzyK|-wm*tgY5?2?#8_5oFv(5wWAs&rr#SW<9~!Y`NDPtDqL75Z*HpetGx zy-X%+l@NG4lBrp1bx5V$a7*l+s*F}AizuPHXs~994%YLKaI0*Wbt+o(Jj?vT;^P;z zlc|0maQ_r$PEMP+l_jU($u(%Y|D;JVS%Jt%9-s>G{khXmzj<J)hM-9h9NT&WX0;l_ zbaF1ci+NX%p^Cp1-!JUW5&mP-1bqXnMm?np;@n>g3UmGmubahqfek0qz_^gs$)MFS zy6@hp<>0vD5S*IISb{8mfFj0AVsjLlBzK6K659#;9y*b%mZIDBOGU17V?Iw%7B8~Y z<w_ru{V<*5N4zCJnCp$XTZfl02H~r{WTTjClK)CkZ%N5ddOdc>KS#3o)U}n5)tY6? zrJd;*Be99-v<tn^eCB)!dHoPtVtDL=W@p6JrQ_=aT7{q14scZuNaeM&x~7C)VZL-J zyhKk51dL6v1fX>o!fVuT>L3`bu?8)EOq3<;^kD}4*@85pT;h?R1c1>-K}Jc~(8u;Y zG+zOJkeYA)))r{D`(#6|{X70*J4BeTH*&nP;B}!qhqSwfTC|`x=J6EqQar+Me~213 zg^0yac<>7hqM%{aP8i8s!BM;cH8kHXa-+z~ZjjPq$o~AR7WzBM|70BD@F2$OoAK-K z8|8n?xU+?g37zma)Bna?#?IKn)I-_B{y!McR<ilaA;XvUe7VNi&#0j5C8oh&QFqul zh<{|3#EICNh`_faiBYm6#Tf?z?_(eBD<(=fN_5cdXVUHFuK@V4xh>M;hf|Jc?wNL; z=i}O1K7h$x6>LaG&Jl)uL;hhX9G*1fk;U0crCDSQCCs<r+~qh#U(sReK-IOf6i2FL z?!Z6GI}Wa~lwx44feJU=Tx0EBb9GqIP9l6|=^uVtUM&`{j~&-6(y3m}8cfb-E$tIR zotT`qMh|lF)I!ci-I|&v@=mXU_41xFc7>T#!<Idh^j|fN8TCR}tidJ0&LxA0lG8i+ zxL%PlW~mvEHe6*lHmN;j4Nq^hgPG0_xp<BmlhmR92TKj<)2j(0JNs9paM%L#ri$FU zts)ngP%dpJ?y_w|^!9;af~JYCp<b}r{9PA|+_<bj7042iel6zhms3`$PrtiOed>`O zrHIAo-lzH+R<QFsj|puQli2LFqBi~fIVLOJ$La6Cs6j*O^>+zyF-}D0`FrUph{LZe z;g}Ut&b^9=lBc!L?0md-S_J1gpJFeVeN$&tr#+rZ_<WQ3I=MyIN<(Y18@S1v01w|c zcuBl>;@A=6{n@W}Y0*I;cu46|wgKOxYM6w15e(4@u@dWvCh$hYxqiax+*Rf%kM!bu zf{Glv>5TV^Ewj%I_;ANLa0)jR3@{Tu0Gz!HjZqkm{#>g`;7*7kV>Cm?%t_!uGgKln zto9CUNLD5)ot1@8<yRv<N$Crdj0^K2L$;W+wxytPPHioqA)X-9A4U5lH5q>v-v!!> zMJHm2XMJT794K{=dJ<`jIX=<Cef!r}{qNZR6KGVAFTBTZm?a<q00jQqulip=iyAmN z{{^+YfuqyE9ge;q%sl@6_;2+tR+W;+Rzc>mGtJAl7%+Yz!3aZVfJPdFm-x7q&_{Gm zf+vIkx120IW?+7Lh~nX4sHcSbRgBd#4m$ijqMX7nS>b#=A(yOLUaaDa+EMqRHR9b> zYeveC52Zg>d);}x^_`)9y}j}|SN+Tfa06c=sSrtv!Zk}%Jm|<y7>bM19X7F77GZRv zB=H=Coudq&m{F>nv}XbGN!gOG1v`oYowOSiafzOEp9q<wpb#wpQi_~qDnGyJ5M;vu z{8swHfy>aI90twNVnD)){^7u2piV5-PEp0)ic#VC-VkFT3aPnXex|X3nt~LWYo^Z- zVrVu$#@xbiaV@tN4ld{9qbU5K%$VN5Xq)yFW<)Gf6l<1MxQP(BISqbV(UvI4xdly> zADvz^rO#6}H3;2fPDzVS`355eZJc;8z&kuDL!cpkx{3X}h2YquSgvHCE;>uGZYWrr z9hAmYV<0AjI}xF2yP2RVy0Tkg8wFwyI_zH7!2g6Uj7QabD2yu+nkWDFR4_$b9=~)c z*@Qgrq5Ws^0eALH<0f(gIw%y$99D!akNRAjIQn7LNwPLzghia2En||y7Q=LS;#!hW z{~CHA8Pjx~(-gy#DGbw<qB3iIL*nKsQxHZeXK4eLq=}8r0|w&HBTMG@Vmz4Ve1XAF z^yNCFPG(?*(tO-blqhre@2r-Qo2-CimM%Xg%yoPIL4l@O2U`j!7&=4k5t16K>-e}3 zcJQa1qoXv72w*m^3t?7?Dd&qW+WDCHgiDWg!u5m@5rusiI;rWRX9ySw_{vZ=VAc#t zJ$s8-x)n`*9+Od2%8Us&j(Vg6B|$gzE`l}RKb;WyC8bx=V{hN{9#6Am?OQ^iJ@QrQ zlFcSW{AJW_HIdLdd^R@oB26CF---9tGXDMY4Ozd3VRV`2Ry)vs{q_u==rA(6O_ec9 zm@>?fMFI@rT&sPy%{iN0hf-WmWiKC~P!3+^#Q!CfDHsa+#(J4&mjU-<&5Ibs_<e4J zhztJa-Ndbfi+{Ka3>q%ZIb^xGgtE&Hm%0mFuFV8@+y0!}`?_s8x`wX(*eGcq>8-&h zLee_~Okx3`wrN<G8K{QX$V*#7G_}&8>CmWKmderQ=L-+=+<^}NtroeVS~0Z?lssqP zio7F4@!l?>WGy1@Bc+DB4sxfw^uck^F4W5{$?I3dhp$Y1ufyEp|KsePgDYLvZ_#vY zJ007$ZQHhOCo{Hf+wQPq+jcreN1fcPwf8-H?YdRJbMC2{v))<XfAgy`p7-H+4!ck0 z7Lm@?G8siIO8X9a194rh$E?W_PIa9qP@=|mb@vppea%OXuLH6~AE7P!Gd6ankIY<e zuSk<)5=Vm`Szc=etMo-)wlsQ$k$#ZBKnOh$-`=3C-!?_DX2bY|b!gyOBgM}9kJ$yS z$-Oiu9n$Xh3aVU|ga(5NtpVAl+0}Y*r`6lKAfb(@D{x1Rp`CUGrzz@PCu;MA1$y}} zWN|dJ9bu`|GTgCG^~nPw?cw?CPc|>x?$J$Vm3o0bM>j9ec1e@z4c{yX>chtow9yq< z3C1*q9xX12thB~1sI0usZUXcvlJpDq*{L>mBtIcaUdT&6Fnn=7N~50eW%l$r+GEvk z@#*%-^ag3W`!P#1MoMl7On1T!(>OFO)bC8Z7@~wd(m9kIvEp_W=Vg=y`NSX+h?~Gk z*$bG!;&ud3V5r5@e{%sJHP;QcT#JNndxvjmy)Ic3$zt{V7W|mT9YpMzna_G#{QP^~ z>z|hNKQ{KS1WF}Fnc3c#(_r%D7>oX&+t{z^$S*}L5(PsO6H^m8S6d@fCoxM?8<T(A zSrzHOMC3l~%-0JRECYke70{4cl1FZC0?|o9NiCH^AqgElxqFiP&zdtbkPqhb_SfMe z0_H@1e_+HYx|5xEER-VR!R#0Im`@+P{cxV%e7QRrBnMhZUnw9iGgJ`=?cmtQO!7bA zA~QHQkv&fzXa-=xwXtlPg{!97>?LDq1QKfLw&+7SO|RAB@{owPDqw1wD_~fg-npaO zs`J>YNDpWqkcRP`8BOg^bN#k?*>tMxFTG@Tsk?E~OwM|tMK9Xz9ME=YzlM?0q*(5b z9J|<DM=e#YQnRkL=i029Ob^sWJ4XH;EY5>SoqGvBfWrq!Cy&9AwOB%EAy)^n>+u-4 zD8M{VCM5L{B2F)KpzbFNPQ)#+<M!yG+q~0?G33$S+~43SX2TF_tDa`>iRp8j6upwD zOG~>CPr=5)88ANO?uhNHQR5T7mZX4vJxEI}hhS@|-lG%#q{JQo6KU&M$iI46(i&_U zN~HZ-MQOr=(zq=^ZiWSbuZNB$rrOlJp^B+=2xhDK1|kVUNy56x?11kHlIAEpm>md_ ze>wAc;)K}=uR@d78iK|!nG4qp^}CwzZ3%(@A!OEViiW0*8=75uK?)zABa|xWbje2W z%I{r<Dm+s=_2$oB#h4@@aDh#<YJgyi2^SWsGtiRLuru9~(}YX))wM9HaLc5p6gG5P z#txqb#XERNTqO5e_$3=>H8gYL7g49MW9WIH-_YngwCW3>{SJ3)9N~eIpE3Vk2;nD0 zmd5E%Pl9GTL~@v#C=*f0Z^glXNS#Cnfsz=-=A>zP$#Ui~rh0@QXt5IFImmLxuj7X- z$eJZEd+5|Dq|xgXoRtKq*tx_W&+&}BXWiB*?t(?u6I7Ojos?}mDDQOO=9Do9SjX|; zA%-1tZq8b4Zc!`b)Xs~rDDQc>Vx343)nkOedu0jRJD;{=#U2I_2ib%(2mNp`MAAAy zomMmpn&xKw^S55bKbiC2oI+k+_|f&nDfcf<{m&9X|K+#*n^P+8rgko#V)m|15?|kc zvMNdUuh<i?W0^*`MTajWDjHvzU*b~@Ocj|JZ)KbWEC#tEmsUVy=bm+me!H!|XMZz1 z6t^3yc>N$3vwcR-ILzE6%NU7akhwOU?R&yIlg<3LcT%+iRO+xKfV@Vs&X^e#m>tUq zf<1g>EF?zesx#}TID#sy{b)Cc20N@&q=hcn%n+4J9@IT?;i_ofu67q3`O|uH8#VP( zz3PX0o6ePLY0Yc}bXDKQo-AG@ci=%N5$1MNrm=*MI}drbd3yqH_tYtNaO&@sh?=TH z4<fIY@rlINvcru{-Ge~lm8pDmJFbxJu2%t%y}_UzNV^3JjsacsQT%uld=#z>^l~HD zNG@9<S4oc)ha|#WTw12)do5Xyiz>cBk=Ev)Z5`tVwB_|7*-?ctvyL@9?xrjX<g&>) zI5<QGryKtG85^>^!e0Cs=ND}5I3gpECB~$OPk%)9te1z|Ta2T$PG>7zWtbm6gX<^^ zqtUn;X`y2`Gd_x#lAQ7)=qA%83KoVOv-1J(vL^e;bXo00_<u0x7$@p)c4Q4sw?Xvj z?4h_#(s_T;7Ht%6e&3;@Ym+K|m2?eP2hFfvE3~N<j1v8Epn{`nbsdOIB#du{d?;8X zt`@_m6(fexN$C_~1~zmGf!UE}(9v)b&Re1yy-47ieQ2L=X`isTU65wvn}BVZDL56I z5bH(1G53(IXnpnq+n_symD|jNau@TY=b4dEc_!)(LM};)i>GKdmVtFG*CVj;zH6Lr zl{tGgCB4$nuY2k!vD|)lDU9>t7gFmhB=r{E`~)VvuAV}U;n|YTjM<kzp3_eWt0<SV z%FH3FXHGPXFTtFxx@3f@W<xC7N~-jev}YgF!cpXe*~GWme&|N`Xj)`l&8{hBLj}vY z*EC`;`;IdX{`I;b;~R|GKt7!o2lN5PU)j5Vvf{t_Lc`gz@t3yCU&7J<H+-=du{5`I z`TyQR$~%9>u^)CTw$;gj#=@q`W%;qTv$w(`jASP5CS#~XA-}t>m?Cw%nsHx$KkrA; zlSK|ed;)z^9GqP;g%5x*%5Hq^_dR)=ewps+_4|B=G60)ljoveamgJeg!6c1QgTWpz z56QDaj*_GyHDn<1f|Fjw1z#pP2tCs1mj-WH)Zxh2-@1eZjHMohvj^*Gd%ShqCXp{V z$=cyN%s^ijD8t3l<QaN>_H^00))0(i4qV8NAn9!#|DdNR-*)P$?SI?kK?a;XdDR}^ zu(@|ui5WbG%<cNsPk}UCXvz_EzeqE%W9^3_d1yT+i|*0xxdamfG%N$xu@3(HaNv5Q z8#JnLos@4cW@s(urtxCFg9n~qJKu!w**07CEac_jLB$)KJn{s!gFnD(Oe<ipsN+j7 z#MfBVLY{zaQePw}iOqBH79f)Q1-9w)JM(u~p_TVlAG7Enbj&aPMw(C$E|==lS%%!9 z%2-yOIY*eEB+ITmqKYHnxr{b{+O}bpPmZpe<3h0*Y;+LVg1ouob97lsNt=(br*aak zoT5o&kM&(GtEhucv*+_M>QuoLoflAl@atDCO~)L~j_R`#V<ShpL=E@F7qX*3%el*z zsE>ep&No{L6hO?5@AQwq*em>qFEL2`VL3$MgI<{_E=6k)>BFqZVn+Zosv4_s#xy@Y zMQEnF9)kSIGawa$=PGA(I(LN_Jon2!3C-+E$+aQAL#HCOSBO*e7wWmEsMct$8bg5^ zsS;x(o@&xC%^fmt4Dgl0gYFvRAa7&=GuvSU1^whCS}7MkqaI~8;RjTO6rmqLL;@qp zB}0M66%EQ2&e9cE)Aaz@)=ne~XYSY`?@-}JV4mviITRRma!l-)k+uO1TTU~URP<9z z=<V-O?SG>Gzj=Z2ba`L-<&*vIWg-8%N0eRc9n}94KKhR=q%8CR17hfo1#3&>6C@p| zqp?C90W{r^C`PR@?4JTzDHPsp7=+z|q4M2z&q-JWz8@p^ZV>e%d4Y@%kcvihF)AC~ zDj|mZGQOyCX7@rmV1~_ejVx>{XL=oz*;qsalPr`NE%6!q^C~HGscAxG)K_;>w|T~m z1h8&eRc5--)+wYz_LmUHVaf%?#4?}FKaCN!p5-<met?}m<L6)4pR(V<_5^bH{OzLt z^UwbGYmoh&W6kna<FkPP0%HE(x~Tto4azS6D{Y&jYOA~;faq6iFDV?Lg{1#YGz5L| z=GYpkyxE|oH3c=hQeP+nu}qfB_WZdYzvMF7)x_obSDe$PG!twzZdl^vW>Z_++pq1b zqr116IDMdF#bm@GsdRuUlq3(DgRp?q0BP|{J&}R#kSbK6bu-~^MmQ2wBlirX2c40M z&`?e<Vmulnnc-+oFKWCoWM!+_1+3FB%j2t-s5Q$2xUdIx8G2IIPnSr+F|9{l(JIR$ zUtLP=rAkw_<VdqCT8dW1CA6hht2)-MZvH(7Qp}L48XdZ%4FXBpV;Hb$WVN<MA+EIj zMuvu*NxKqNz*-w`QW&3A3fYV!ANutccfHx=yc<LlpyDKR3AaaY(T%DY>HGS-H=sr1 zDfmgz*(1EbF5NrAV<xarv#MIPwWYKFrH9~~a@D!dWgbv-9qAy;FH^uC-7WL2?Op3{ zxNV%JRc6*MO>#2-X!?*C@X(r#*V-b_1Iucy80%LFJ2tD%j;d?uQD%}ZFpfv?6J(y^ z>jfJ8V@wSI%snhKuL483^igEn-eH5wyjfG{qH#l7gq%{1Sx<ExPWL2;IJ!G$Q#96Q zs$-5nKf4L)jZ`1mU`}q~XgVmaMhSUY1SgidV~u&6Cl;}}gLXWl7kHZ}mhq<Tt_cq2 zewiJGF3C}(snTVb(XH|2<h9T21lyzed9n)Z@7O%K6Co*=H$3^{ObOjG>PzIUtp25m z?n9ux@USAhSjT9cJ@P;r(GbSiEQ9p?H4Z}mVsxLKU4D^Wm?=!VIZUTzXcPVj${9Z- zK5=T%;DsF|E|K_+H@Vdji)3BuA;!z<1;ye7=E;6}dIFgloeP2I*Drk+caQV-i&ctm z2C17!yS-2t7#v~(55K!X??v!93eC69%5+iUa;1Muo&bCT!VddO#64t8h>#U{?q*`~ z6?g(PA_0GJC2SvX1?WWIKyYE389f3dD81-b1)F2;Auy>#=|i|M?G6fWQ2G;lL-|@z zEesWC!L&K*QiW)BR5osWc`M%-9#L0C`1KB;w-qm0E4>4q9AO$l$l>W0sOUw*f2}xh z{`_=&sE+I=f*;3=#G`YH4)_0?l>emOf0OdhJ2__A*PX5VRd{FmA4%!zU}H)zX>05H z_nrrZuR`0ug2Wu<zuj5h1-A{`npAX=etOhUTR}AeSrs9pX9)&4OuowJ*5m@+`768D zE)m~bdP^e01QC3n`>Ec&IECxU)X-G2R<ooG@9Ry@uiBcM-}}cMS|2PPsRKV4paNCp zRI(8-+>|RY19g8ECEfJY+F^yoiu8(2W@BAT)5L%tla6jxZIGF!&ScT2md3B{N8RV^ zeG;MCfj6FTZM*$<Os}bWs@L^tK6>vN%tRcspG-VEN3e5KM53rG)hfJuHAxr^zcJZb z?$u|+??g9hP65WrRXX$=k6d#JP)(gD+^n^Aix)r4e=R;s54u2cw;Eh4t;x(aKUeDS z>|K>|pvhb^J(??|9kK@p*Yvwjj|sZgK0okeJ;FD5#&8w4dKq(J=wy-)f7N-IdOQKQ zS7b_sWIdH@1cKhU(+8hN={%N+k>pgH)Ka$)%|7HWXteaA>XeSWv$`Q6cUHj={>XzG zVRqbuxS$v+vWW2vb)D)b`nYYZnd|kwZIfxTFB8qt#!>;yGEYncEVX-`8hE9SP#G*v zqw%w4EN#_*YmU~7+b!0xE`WHP{h4hB_kaQBWe{%<6|MdN3$JC$wm0gagi!Zym_yNc zF|}l}UinweS10p#KZ<1jfC&=>r9(I)lW!Hq^_K%fNJRLg=V)37E-)TJRn73=n#efw z&<bH%(~WzY{u++yG}zKj+YswT&F0YJ;pk-WNYpZTLNBQ3Q%Hmcfy<&qog(=YiG30d zaO@7s=wmD!sHyqL2`X|;c7H9bs>*8wRw732is6=3ni)gkl-gr9y8Kf&es@Mtpy^jm zN+bnVUxeDVfuv>`M*9fl9cN^WX+Q9zR2No<SIp-PGQ!?=w96b+dC;?BcKz$1jA&Bs zzuQZOPLF>({CoQUpJ4wF4M@tr`cH<1X1}9+-Amd)K<r;MkQG%Cq?MEtqqjA5Gqt0) zcQU6lbTIr9BcwC7x3#smbEg0INo!+hXU<ITU~fz3VQVwRv*EPC(Rlp<U2R=yMuwBn znv{_=HJ+*H6LG20IH5#$pByA15hRMN1Jq0-e{}S|@lv+{7mrLi-zaOAR9rfYjBW9N zyVYL)XT%mW9)}DKWA5Xrwy8;0;}9xOJn7Hn@4<uRs!M(@?Mwe=E$zc>ZyKdZaxFw& z(_$QDgb&yujhPCQLk*Gyc~%3WUKfawUgYO-5+o#Ip+p6VR#6@#%Q5i?Kx*GUu?rCv zjAn6)@Mr*IaJN4r4=)FiF&@LdvnfRXrgLqX_G~aU6NZ!6a6tGg--xB9fCngC0jW?U zRLUsSBsM)so(wC}J!E>$-Rc^V@S&kY_FMst8Z)uObDD$_xKnp2k%t_gMnVFwxp~xk z5O1sU>Qmh(84M=QJXk~sS%eYi(643V25_dpQU-XA7@pQc%Lx3#8}&$`XqM3J#T$Vk zj-42Vo)*!`-iqa0>y@0D6L{8QE+M(iXy)JFP1f+gx5RJK-tj@FD-q;<lIR4<h{FgO z6ATv-6ENmGFQ&~!&aukyrxEO0++~-mtZ9RlR39cQg1;Yg2NYX~w040wajlZscLp!? z-_zdRx_CI<`bqG))zx<X**lvH(9uZ<j{4X;yLl)?*ol>F`^4~cU+4Fc!<2wBGi+-R zIS&+xMK<9pXKKo{@oI*CuQfWpW&9mbVUaisMU3)o8LvQbNCu!&fR2WEVjqYbqJy)b zXd0VcqXzSxFm*rE6T28b7Nz3PrOFLqkD;R8LmCF}?~*1E_>@Oq->T<Eek!YvfrrhF zwKZ4%$7u)#mSS2w${01nVagA!jAQ3LtZ_U>!j8HyON*`U_wIYokq*@lH;7V;k^CtM z_h{S}awU@6ik-l#HHrEKM3Q+o=JZR+l4Ij@OA86_W}4F0EReMymOf|Qo3>qR=Gp7I zQ(N$%GeHQN;)g|-=<BU`@_J~F7C`jNmfA{B11~iaS|Y;Bk~trJg#;%7g_qcnow`}# zrxOhO^kSwEORH{CwyP87<4K#%d%vNxXZpJeTmi>W@P1<U6p}0m?Rtpx`Ow13R<i*F z)^p00U)p01GuD{<1Y!KtOh+<GXR;VGF&M%S;T@5|oZ9wyf$ETb!D`3CJ|rrJ_pXHk zOfU}g4%z@k%D5HAbE^6v+6Y*#ik1?m=?$D`=;!pTm4FR5$7r-XC8&!z$W?fC^m23t z-_?%e#MZ5csL(?)W?>j-Lw|RYpE``cyEpu^rh`?|j{DV)Of3YtkUUuKKx692b$aE@ z1LJBq<Fq9W$;ONdbSj6zhQFU~x;eMgIOT2C1C=-^@J3a#%Aze7M&kwkj`Qe^=0w9b zn0J{M6!i1E#nJ)k#WKY1usz~bzNmJaCmnm8C5+*K8AXE&nsirU_|5G{AjtpG2nCFb zQ2#i?7`H2(Z%Y-Vx9vvDase|5bk2=}#tlIPd0Ia6;OvC$DYro@&_t-z*O}%k-RmCR zg=;p{rn`_H<KQgp<g_z+C(z_EPIPk{5F<iFtahy9$!Q=7%z2u(GEi3D5%Z297p6Op z3qRWNbZw}2AHO9?w;b5l`Tib5>O4R+Hl~m0p^?HFeF_Y$6#BItd?p3U9vR%RH+aBa zVMk?(`b9|(oYHz7R(5YEv%g!l*-x82O1#ORR7}R|jw}H=ogj=T^R}D@?5r#x5m9Lr zp=zg1g>JM!cw0!6@UU=l-6T;^s@pUlZqjzPzwO`_a~@>O{E!$V=}VT}tBEPkc%x#{ zOpbg<UDf=CA1oL0yGr_QOB%40l@wtdOMh$*5Rp%DVxOAWj{nw~vxdnSDa;(MDA*g4 zTR6<7Kk>Ymif}*xS7jtk{tEC9US0E`F{r@tC?^VEYFM#)%b}`YU=UnXxX&jf-L5{Z zc1-&8T%XQuZZ1C{IZ)XSLu4IVUBQ1Ywx(e=2aJf+Fxl?N`KPf!&DN&R@ai7Z;n50` zf~VEP@%Rzb(SR_^*0wLJYGIF|DojVy9KPK<qzj;<Brr1ot0tW4Z#+5G+5^QgHeIK; z=E7Vhv_XxuYaP?3o5Ul#W1TA6J>0!9LSlW#ievzgR10}-tKevW1!J9#jM_Qr%Z9nx zwQ=GkSW}Jf_652M^f4{P7=Y26A(S@K!*2vwP<0S(4I!)+vLP!A&xa?l6HEj&b*-m+ zeMhGRD9&d!tZNX6=q|*IW7@D5^F97_Mp6(UB5y%@r~n@WiWOy4;Zyx#EJEbNcJgS+ z34%5SG(mDZ%WqX>0Un8dpARJryOv<2r_a0<u%*;=?JI$CXdpFWthQs+`7Iw&^72;0 zW)B@YbU)roQNKM|%GS+TLnSYZc@s~RB!b=cS7g{jsi4Iv43>~fF<kpu1`}93s0)!L zOGVrnv=#oh@KFMjPQFwT%4C>BCIwG6$8#Jp_}l2ZA07=V8BUd>NET6GQ>ou*jd+^4 zpqJH`v8l%yVcsc23H0;@)OY0)<YNmw`kR{9J?Jvb4r$FRzr`{`v*LTgyjZUqG_bB4 zIXelRcu|?4<Vob*hmgXx2bEWhLJ5d2fbN?(u80V0VCKy2lTD+LQu9ijlwGjCE$}!= zC53kv2`1@Sj5bT5qt1%J4%q*3ZH*i0A>2)1j7m1^<}()O^Ca(!7;0yWL_rb=mED%i zJbkquN5fqJiYH+dNeAbY0Gz~5W#tE!#JnA5|75JQ_Y(g`e!_F7ngojNemH~DE9vG= zK$#a$9rn--0-5cyPN1M`xO?g8I~?>XlT$xxGaqD6hh0sc?jMhL(3J1j{_7r#h73la z$S|Y3BIX2FRiQS4&pgoR@h3NE?~mt~m_s;+J`0IR@PM)z4+a0D>!3sf$)KS5s~%Q~ z0&#&^(u1UMb^(wzycKs)4BIu4;V?o7pbprOSb?`k*X@xDy+fsWO<x?o#7*L~v0}f& z$yiJJBr&W}1))*p!$`*7h)PCdjd<#9lY(~vkn-sQnGR&Vq=)INU|1Pi4SnG!3NwKd zxWY*^xc!Q?Jo`R)5n1QG3uJeXQbGt(L9O{A6qyFN_94uH)Exp`c8IcYidndjp+uzB z+khPwh64n|+x*BZ+U8O?^-sJ}P6NN-N~VdQT>(%*a=!Td!n{xs7|-WX$F>3UODxf% z$fw+TJETe@18=?yW~I*HEek-!#<d761dwo8?tDoE7AAbUtU1EFSR{!RujgEb@yJPp z$|zQJL5rkfLUVIPhLB!3a-tF!Fy-QCOTZGH(q^*n13E$2Qf%0)V+zx&9x{9i6<4dp zezA5J6LA94N&E3IcM0P0N-P_pG5tV0g3roucM;8rTu28E^D69+C1HKju(-g#u;{DV z9jcL3v0dP#y@F+D?GOWse)m;*EavB*zp{Ydt}Y~tsolfZrLv8QE{ysWcx(zB3{sY% z2r?{``UUIiZfdcGK{b!HYQ@czdO($mUn5tTJ)*Q5a}6LLcF(0&Bi(-fp}&%Uh9lZx zgz=b^SixYb?0wsQlvR8@{&t3ro!n#i8mBfP5mZiD-NkpS3427(M;ef6B?w&0YC_{d zowwUh2CR8_d$hLOXxTtQ*+uM^BjT~q;!u=>S{qZwyIl8GPd9Zlcdv6W-xNrJkXxRU zvFxUf%2NicRIG{M>DlMa&nAISfm1cf(K>gzfi!eYM`bqiN!YkWq({XRA9vXjxY%D3 zeW;V5mW-Ecg#f#Yvd4FxHwVsQOi!$@&-k(*TfuU8(}FyYr|oypWsjDXT{^P~N$lxt zd+FXL^aor#cFB6o;m{XWWm$M4;qs-~N8Ve|RAfyT-^lgmrQ@8e^|%~#2%MK*e5gTU zVf20QP7=))&QbH1Iyp_>e)N^yJhg50ATAkc)A0Bv9z-MKJ;x$PJgh3d0&1MO+AVs# z9yfZmx@_HzM~LVSb@zMt#7Vg19vZVek=uk^?fIjo`TG0Q^b}SmT%;U^cQ));%bn7} z{W5C5rw09ExR;puz}XLGevSi|Li7nT%k`7d7$RAUem24b3wq77x3|CSVqt+d=hQ;< zAtmj|<I~ML;FILSrndCKNZBJ`EWdVrf{zJdKeoil?7OIzhUto5HhdBT9m7DfQ+<B3 zAk(I9#3~?8&!QL>x~BtMX3~J2V8)JwN{{z65ibHm@+eL*)Y44wrD)RPK~#<fnrPM) zofJ|dYDnV4tpuh8lZU@~axNZ&IZ2g37l0KcBSBUW${olVxF~uHSQ5Ualsmz2Ry=k$ zKgsJ&9m&F@ex)Pr3Y1Yv=pjdJKdIioyFQ|P!Xt2^C%qr%V^MjsT&QgdqfY{65YZI; zz0GxmkwIy8e4)K%pT8c`=|f=k=iztHkbgxXVOo`mfRE8(!1U#P;p1}T4@Q>jtDe;@ z&lf9qTcDuUNMQypF2>@b;cc})>X+7kdTyAodS-Z^UtVvy#eX`rQc=N|PG$*$@_^EM z$M@56acEQj?2awj><VZ04%n1@zznvn@U0r)=njz1=rNJo>Bu;#entZM;fnxmVu;89 zc&;3{M3SC9b#B5CG{c&pS2eq2LNS$=jF<6f?wqjhHP@FsG8V(xT1Y7QUXot2x{?ho zHOM&HU<#pHLc<Wf#WX|H+EL~9a_mzz#jqcMo@Z4|pm3Hhk1RPc819LLMZ%|i5r9^H z|10Co1`;YU*dAueTXLa0cB}_MRhw)s^daMy1oq1_jm?@u@nTQfVypI8dqY{a%&!I9 zXR;2xW}&3g(Nx(hAYkkqq3Y9JywM@KL||KP3XQ(ItPj~Fq5Fi@UdVNV=@bThR6RYN z4xh7Go}Eb!2PODXFK-&)E7~XjS8q_0HyuC6ln0$+459ET>11obYOeLmiZ3vIxaXOr z^__l4nD#?lV^^{aeqKMI$e>~E;kqs87wg5HodsBNaN#JKlQ@r)-JroEqFOc1mM`(% zL}|jyQ(=@)kUL%B7~`P@@3+ca5vU)-G;GHt+GAIP1AnL*PBX{rumROc)o-8kSq?uI zi<V&<SnB5wE;9C3BG&a*Ba;;SmYQoH?<7e`x<a}I;C>Pw(t2&-tMjJf&PMs}?TNlK z)f3dkoZ_3Bt+h4(a9wCY;-{}F9idAh{pOV}M9~9@r}3;t{bJ{-Z&>6*OY*iBDo4jv zd)!Lbv)p8`hEz(RF4?z803{4vF^wsMf)AZSh!EjU+5T-o^g@rVPBXx^PD4o6+x(}* zhHTdI_X=RaWsP*&6^~x(y}Qn8P}GIe#P^J?eS!H4KaO+%AMM}apW2#)@|yX4y|#+l z(qsT2ej`urzx6^l4o^0X8rS#<by>)J<S1$<x|Bt`u<u9lNl}&>!CU7l<CA_X@R_b1 zYedGc?lclG`V?EvMS!)(@mB+p!aVXA`bU%fdHkLfWQN%Yy@jW<w^T9^l!0|s896pO zg~lk~VCQB%52hiQ4>{;cV!tb`Slpv!yfCHZ?P+qqRCc)Sc*;Lrx8mP+AUJ#p7|Y-X z0Z{)|`jLLbdU@}Pv0Rp3REna3`(Rw{h;}f}oro|BJkL==zdxU76A1B?CMLB<45DiC z!l$mlN%ML}i?5#$Cp0|?*lFzHfksp#XbPxwYZ5K(ITMi95dmO?VYD;1TCFjdwTEkl zZ7KPnv|E*DZuXczi7UDKyjHkB93(uREtJ`dC0o*M#Chj^<6UnIF)MAoR^((>PyVQS zTI$982#EZpuk!@&FVYB(@#ks@!OFPGtu=LN69cx_^Kj%l@7-b%a)OSRHeYn5@;Fcu zLcBS5YrgT;IO!C@GHVhWh8z5r`AjO-i0@Xx<S=1J543qD;f9ga5@r_<)|b0+xJR2s zejwqVpq<c%yHZtjUv#xw9;#?E>vepp{RcDK`i<TU<;~wsuf+qE{8f)+Vz^App;k+~ z<bF+$8ZT;(Qqhel%}>{e>CJ>I!d8<kabMY@9@ei(Z!8)ngBTpdC+pii8hdQh@^|LY zj4h_Sce3h|Rt??b_2u6<xq9o`;L_a62>=nlBLCvo+I0lVASxm}yP2S%{Oxj7k6hU% z6sR2Sr|eZf`rlQXmYPCbeKJd8QD+L<Hj>|P+#_WXWS6R)mXrOBLIbG(e6)5(v{t=g z!^ueW5uc_)fu56pjipO@U<#=U_vegOdTHgF`B1W^!ju27sq_13mg7!R-}LCpDPe>k zXQ55&P>~$AScWfHm34WuNP<0+A>hdFL5sytjec#Pboq<JwV@Xdt*|o>E`&*Tcjn{C zm?X<q``Vs=L%=b%vd)GMZQ$6T73t$)U*4aX9igfh+9}S`o+DYquzDT3X0=jAwCP8A z*F~14-G{=sF5t?WxP$E)3omvzLlX6raio-{(-EM)g-{l}UxKo5004&ymPCdWe{#-! zV$J^SdHzrkGkclV*B_{Q&2JMgHcg$GPn|;kS;~vU?ADa9iqBEoNC$J4?wk4GJT^cj zZqGwQJ#lAv%k*FcMFSGd0*Tk;Lifg}IzXST``)k$t;psOw~4XYr?>rlX7h*t@5zsU zq}l$HfcvX|={wmquRR>l*Mc7)AnN}q4=rSGZ)0j`_jk+lzY@?j8lEaDD_EafZ`;+; z2S7yQ$Vlv%h^UL51a{woiLl#LCieqCqG6dim@zF|q^;I}MOdmOQMA;wLP<tTM$avi z=ssk#*)~10Y<-@d`SaR3WiDj0#QeGPb;m>SKuH5Qw_pG0djGN0wsrmEWsSUS8mPQq zzB@foyXTqf$6moP+uSCd-t~<U*A?oNuHI&hw@&*?%v<-3L9a*eV9XouGZ`M@RInY- z;m<)25tg_}Kq*3aPh7`sJC1z#l^{EO2jlK=+a?DM_>aqB_s!>83~>jQZvUCk>#p14 zQ$Es6L5y6tJuGl@T@rN3C1wlLqb#fkwA)KVK*LmmMtezJ8Ey6|rd8Cugq(9XFY4BJ zDUqQr>_uhW1d_q%V~@fnu0<THYiRYh5pS>k1`}5n)QjpGJ-j&a!GhIN6_QLHk$I!N zX@y9))D+fh$V=!k)icqkaob@D2^?1}CtLCn8;Q{Mu9XlkQeuo;Qmll-VG;Z>Ond60 zlztS+)*<C#B6X5A%t*3|la!+KpGlEbxFN<*b@1*XuZ0z*v8g{O6vx|8W~oR_E}=!= z2F_fg#U2{T8292)SQbUZ*c?|{FCp8?Ko7{gabTI%m1)qfV9A-%saMQMu}Z2dB$025 zB`&AHq3pvH)Or@zBHEh?1GyC;NBg!>h?yxE3#c)i$H)jyD!>M=YK{OkOSADc+7q^j zx*Tp$bC#?&)D>GKum(+KW9e1Y);&JH0F#hk`TQtZaAWC)DGh`v;X_=^8tT^9nWEpi zg`UhNTE$vh8gqngnNkqRhbaUwa*f;j#pY9DR`2g4A=%Xwh{h4+dp$)7O7-u4v6M>a zIfT9sZU0i)^gs!V;*v7cp-Er#<C>iBS{Yt;bJ5st3pukeawyvo$DAW0shy1^OX=QQ zGmNFjL?25Fs|YpPI0L2Gpo)`F=fJ*#8lgbJEf67Eoat+8?G!jF?zXug#ek5vCz?l* z6m?4|@bq98jxf#O@Ll;yjCv3O*t*=?Rw1E#if#&aFUXT32^^wyY1t}tB^!|Bx{RP& zYTi~Lq8V))KL|-65limD+4qfjaxfNA8MLu(s6r<4p%CUoBgKzB@Wj^>h(Vx_JO<Uf zGo(9yVZgsX9lhNn(KDlHF)?G2Dq-rRnOh^THn}rTZ)u>`DMW5F@iy_6q{*c^gDP3? zk{U=*!GI(49=uG5mGJP6sAdcLNeRfv_#JBWhnT&?VLc2#zdsDWP*CMH1k-yujM-x? zO#OyRxCDr$+uM-`KlOkMa31abt0QU56#Q*Aru+sTOCT!haQ1Z&m6`_~LzzX3AU-WZ zg6ix{x|GC8yPbrLx_&1;oJ4wnw}<lX!J6+KlK+V?Ru53c$7_;YTClhJmB^q%jgZt0 zjYmeCk;H$>UkU30_FN~`jm88PhMj+;^j3+6$6<!iF)%4*d|r=+t2~^alH26LPGhx4 z%-wAF`>Lq#<@gd3daW{AK&FXjWJNQ8&L;157gHO1is6nm=q?S@DxGC4EjBh7nhw5Z zEw>^<=)cyq82-^JM1>pSQr2CxyoM%CEs2&!S<0ZqB9&+>ZBV{-6%OkMeG@jZrY2i> zbO#^O=S-JSunK-qla?2g7r!B`KPewn6s$?hHL8${qN+GyMmHp@JUtU+HKPo;Ko#)2 z`TqTv#trCm(arZTH`M8a*|@o6GQvL(ps9$5N*t8*0E2tRtRFa_7=3V4XWCZ--;ssH zLy?t)U52FC2@^p_@+B83N7%JzH=(D3XENT>s1uEY$oF`F()>_6*({Wp1v+U6jA@d; z?`le)&7zepTkvJ#=FzX-X&Ow7q(sc<VjMKh4q2;sto1kD;Lz2N@L2Ru;>B{R8PN&l z4Csi<BY|oTG=v5NyFyMm95)?K8i)Ak6vncrQmf2qM|%NRq;#b#GkvY&Orsdy4w6xs z(JJ?%G)sk3bd|20Xb=iyrC{*y|F$v947Ae%^hz5*=TH~fe$>uotkHGZ04M#PLvxFe zc>hsfuO~Gr7WOD~Mn_nj_7u5=0u2qZI|~65d0GIM3ow_C{Y`4pV<d$oZxzfL9*IJC z42bjGHRq$O8R}EOj@XtuXI$$7c<C_B_Ui&*GLs)hQXZ(39BqDb3g+K^C$kFfk3_lQ zrP>Zo5t~U>j^6}k!{VY2&5{jFlO>j0Kr%2*?;BU_3!*SZOCPVK;i*bi6|paQ$UfB- z<_#`G>0H^nl`yYXlDRI(;o>cW<n9Q02`wov!lkCbL;Og17=|r!N8?2QWtC|g5LQEC zwL%b9BgCg26HzUy1dUx^dRCfVnpG%6?p0M$R<XLkV^?;#T;1MN(9W8OMxKa9+B5D9 z-j#8}5F9j8UzV+ip3>Bx0dTcFqc0u>-jG{{OLFBNJ<v5-gB)(KYqU$Q#v#5KX3Tjk zjJy<qlQtlfE{wfwEMK<J>Y8hID{5>#ttrhdC0aal=4@;XIa<j-Qd&sfVxy5YS00X& zSZKK;!OAUd6nZwLios1N{gq&7$pu<I|DXlc@j<j?j@l}t{6vy*Psy>ifKkD>B1LSY zAT*>bjZ+XGt-vx5X-@Mkmo4bDq-e}qQe=U_x?T|~d_mcRTHQjCryTwUDG?TKn*?r~ z2yVN9gL8$)$yqj{!|eT7Ykx)Z)iXt%jdCxmdR;Ysay$X=#aiqVTjp~9>;iecq^DUk zV%2iVzVvQhLKEP3BH4=|+52g-Sl9p8$DSfQ)DQ4{#Ka-d?S@n147~y73@omKT{=km zCJ8ku7bWHekuLRV``{k}*nIHURp1WH?i>*KBs@d|Z~Z>7Iv{Y4$P*eEbIwBrJ9MZM zm3<NK90OvLCF9(|U9Q~K&VZQaYz+~wP4eUs2~4X7n`w<@U@GdQi&SGQO3WApZ*@V6 zqt#;yloSbU*wGoN5CtN6jsd}zUS2xX7D>`XWCUpX*{DzRTK0<+G-q*ofwuCB9-4%t z@AccJ*7wsSpe*p&yfPSYJuk#iJIh@e2f;KC4nTB>sAyokh%Q^e`M!WkAsd1LbU!Ja ziV_+9jNzyQB-Y)#iE#ftV(A=Q^>;Zr)d=;08FQk(D#kqJ_B(8wW9QlN6T<!zV+{Rh z-fq0M8&ZzGv^@g-K$PxpWzSUI<LU=A_QMxGaN7qLH{bMU$Zlk-!`m8_ex#(_UTC8A z22LHZH_B}fcY2a<jCHL}@eDlO;o9I|o4Manym9V~`Tcw|MZ^~iP%`7=i=#y~@-DZ3 zuq$X#J9q4kyjWV*9LF;L<;um@rX*i<zHTz9q^oN<sU)gfZT6G&#q0b`1;kF}!mhNe z!HzyBdAQRznQXX|`z+BJ<nj9*M+Xvn#UOnMa-H$;2!)x}hxqJ=bV{PBrKTpn&|3)j znP|6ZPMBMu($L-j8+K9l*f_Scpw5j2P`kjDLnWp0G!tbLlZ$64^NJFOGi@ldd$~g_ zjxNWG@9c|T`^%r3TL=nNydjPc2C^G*g+7G*WPZTeyQ9i2xxyfV5g~sFm!F5m9t$k7 zm+c}mv^n=<^gu_BR}svKP{@>)xep=eDIib$J#IBk{zF-s6j~!&P<5b=?gbb6F2A#G z3R>+uBb~YU&{TBo`^&h(`EV+?i!l!W>+rBY2!uZd-G?^Q)HQ{&U)=W(2&M^q#i7rT ziuW0l%wCPycg<2tvy9U85}5)!8@dzB0zYzJVJw}KcqCKHd}4O;yqqD>gsN0|l8-v1 z-{1!*lty6;jAeb`g3fD1zv_i4CMg?*(+#3#V@^$1XlsIew4ut>QVQ%!;L@yz6|U+r zna-ElEQj#!H*}J`dB6t3$rX7LKb2to<ESPF0Bk@e!Z-o0tw7wrfJQ^ufHrKtbs}{w zPK35H4;~TOGSrdIFCH1;*kSM+QX+|4R+X<ujY%4t%<7W{@p&8vc;%4jXHienET2b3 z!4uaNw!7u#mf<66Hp&}|)4$8&OHG^&;jdpFPIK?BTnW{>u}8LeE0%19Y1#50EBPlp z1-$&!7Oi$ew%)t>DM3(y%mEa(^BKVbqZ|!3jUp=8DWBjMQyf81{^>GLt~jsbh@5nk zqn75bb*a&$!yszLCd?SBK`Vvk{fbQdBtI5BT*oW?E06SPM6r@r{+E8=_e;@*?UK=9 zy8Q_X<?eQ@u9BV$$uPeX;ey#cW0NHK{f$RpxH-WOusNTE#kKp-H-TJD077#D-!quy zt@Qjp-2A@m{J!m7KX>uZx-kg*B!ulABK%(+LijR0GWgx%zjnx<K1rVN5#Rii5T;Sy z5XK<zeckw0tzUOp`sZjdr1@2GYv|fb?__$&qV;_+52)@Rv^rysIPEGn%3#=0V;zEX z;dEyL_3^`WcoBZSipb2vC{$q>@$p_fR>_!Jjr9${5h15ivC9mY_>8?{QQ&v(_y-!` z4v@~%_IchFC>)NzGhN=j7tWBmT1n(^7EkLane$0Kf)!5-P0nHXs`=gSPCQ2{iR&DP zaIM{m<JmI&A?3YWVev&f8nDXLHhy8H#nD$KH)7kuSTHM|;YhQtc)t6S$rJbc55iw@ z+&`nW|HN^B4QPYjj$@epdk%%=e~RObTrF)(Or7XOEX~Y>{`H%L`CkEDipsx+vjKK> zbPD-DsWDnCx)$xg>>&voXi3tcBMf%RE}L;1w@ACRkv~(&3Wp*51Ng^1%(@tLUT3cc zzxEAHyI+}qzW;f|=>y*;OAru55>9wTO{6Hjfh|F8C?z`L$Q^0ukADiG?pQ*sCC7bR z5R3`zF;B1MYCUn@uy?Q~D8%%OCiI)G$zHmbs6lqB-8b@+_v&C0uDEK~P0G7flTW8D z+aVV&{dsv+y7o2FPpi{J#+@^M^FwwN*HYR)&5)iStJ!aS#*=_O&R2bX>r$#@)?l_$ zPMcwJxr7!T;!mlAyvIUe+Dqp`p$aFdjL&m<MIY7!$OgLI(ta*^IITRYlwH!Dgj;d_ zdRRBUM<)^vS{3zs=jk)aGzJ}|%9m8*5EQb1@)q70v-+X<l=9qNN|^ClO9#Kh*x<6q zw=13BP10^kBh!7h5xy07^7`XN#mN;;-fk04Jdv-#H{NpGv9h@IH%cQs=q{5)HO6uY zuzEjlwMKAk&NO~T#+p{oLdvLd16mq@V1G)&E|}alF&nmFS-m7QF`X5giKi=qusgR5 z54K>26GwUw>UYdpRjLHBA<sG>P;LUt;yWs*%ay4*e&aeBNTQNsY6-wHk#tV5BQLJf zLyvicVK6=eRu)t15*VWR2zX+xcg?bhe&}b}EO?_Lf)4Cz$FIIKGROdHgU}!XRi1+3 zwVACjfjYn`^&@&c%A7JWP{uzGVav!2Kzbg9e4mu{dBxqs2Y4_KiN{=r>q1zk_04_m z9wqEPV;Y<f771K1I`ww|$onsp4=aT8@#fs%KLb92{=)G;(fZ#w{<*j=68MGV#IIiV z|KB)f`)?eVVrZQsL!*PL2vDxmrHLwZ3ox{Y_p8W&zRs7Oxvj&mT_tYOM$~mb@5jxF zEI#id+=ye%*szxdCeHeDd~KI|`N4d`^mcMxw*#bhYlLWtnlhWBF=~Jqg+*h?DO_4G zBn2I(q+vSxI*_zU2Q!ma>)hNn*tg9Dn^AiJu?aQ4X%|Jpg>Nj8<HT*x?hDZP87(89 z0V1gU`ho^HO1xl&^&6-uWuR$WA|e|+mNT9zZ!OV9$!#FMcvQ#r4UW&6Pv}P<%o6gS zooD1f+Usyc^q9A_QJIX?q+uqJX(Ph~NY5j^U8<>igmqgjOk0e#P-x3>CgIwWEiPd- z^Nt|pS~~AwnAASFX1sHmGHIj@)L!1JVV=!jmg~SFC5!MHq*I_$>*ARud2d1wcomPG z1>3NUQL9t9arV^V!B8tW!kY~432qc|(AT+7O>NJ$hSNIlw(?5<l2VPbQJ0&57F6}Q z)M&j>2EP`Wb+M+bw)BW5#};!`9%N|57E2yA<P9yu&fV((Xii$B55vNV_`8~<_o4?F zHsBj&GW$6ZWn&N8?M05AxjT(`Ay(XGbtRf_+&_;L39Pdiob_G0BpX%=%z3+qLuZu! zh9O}Hg|!O+PpQTPG-|4P2P`L8lmKQkylOe46HYiR!w#$5h95(n8GO&aGx{<)#<u@> z28pO6T%k<_IYe;#QjIl7Qiqh;cYD4W5jI1&a(75WlzC)}te2|dlD^nMe2X|tgUQYl zlB+pDab#j8;JvxUd!9+VU9%n7iMkOBkw4#IbU^Z129x`MkpB%@R{O1#Zxf;CI38ie zlLyirzfb@d_%U2-<3<1D@3!=R0{OoouDUGcZ~6ssi~k#lbN(-g+arJJXaJntv+T5` zdRkQl4Wo36x4k4$LK7DavR236fIwuLekE>|^h%>t{lAuaEnUll;?3bWJL8($`B>-a zcV1pEkV<`)5V9yKEGgT9L_zW}vrWkuO9}<~4No9+@D-H0Qx&C-Jl9iM5jKeT41>O_ z&CE&b&f&7e5W@$i@P3f?m!u9-HJ;YjCKx~cFH=3JHt6V0hJWX#pKfc;Kp_5Qs<&I$ zuqCUAzf5)4mb<ZUT>9I5>c_W1Lqj&JgKYhq-A$fHUCZB3=Z{87gj%j#L52l{wvIg5 z%^}{y+US=wtl4b5DGR}4@a#oY4&axgt)bd2?I%!76U?EB8wKvgok|)x#(a==nc*>s zODKNAF1~;xp<C#DJI>9rdy*Xg<Q~3nOrPK6v`z|Z5G$0|nmYKM&LX$6MBDit=e}`D z<#7?W(Vi=r3iRG3(uS69;;!3H+)`X23|w>PfVQ%B_esM^Yb@6T=?)emV|7dIwgA{y z=jsDp;jA^v$kJ)OVP9~NFr}I}O1Jk13+lOHTLu>GGFsHtOWPG`+Z<@e4#qGel4>hW zeH+)4t4L%?5r66yJHjjmnus#gT~PG^)kN({ah5T&hG11AGD)vv87|2!uXckn-=&3P zR?SIIVwGHn`$75CBu1m;s%(<^f;dM8a<^kdJG0$P0$=jsAx2l+g|e$ysG3V2P!sVZ zzWGd<)7(_VFc!#{dKp0b+d=d5j;-t<e;SUm3;Rtz1D;)(YU7PRN3E5|B5>j>;NyT7 zjSquZ<H-B3lu^rt^0DUvVn2ia)xrEvu>LoUxwL{$@{xgn%)i=~|Bo!SsH3Z)jq|^K zj(@>;N)yIMWhvv+pE+qWV+@f&U;vZ|6Av(E5TAw(3<>phgoH`@FpvmiemC2n6cMnU zTUNF1Qq!hJ#3$fW3at@v4KLh9x&32Rvsl?uwXx;e)#Yp9oB!Z{)zcv(ggmVIdO^l~ zlI{I9f%Nh@^E>C7`(zqMpT85KkE3HKwBKVU#?(W9(4N(27XZ@he4u|@kVT7Mak#U1 zaIJcG%~^lI&+=Y|gXdFS{2{&cE=c-WllZCV`gtKn%clnNITypfH)9puTYiWFmsi=^ z+j)z{w{jC&`L4n1Qy~?mdY9t$t~H3n2dP3t)zF~z%g#|ERl8BtIZ9ba&asP8!bv4& zgw~ftoz$20tjtPINivu04=dJga-dz~l)5llxe20UxOxgSD^Jl~KQ?^1PdFf$ihlkk zXk32zCUHE>%0u*MkfpoyPMM{<;LZq6zQU(nTWnN975gYvxkMyItZJw%Q7PqFl}U`W ztfF|5*7(Rp6}xQAqs0l|nn^Gz0{Embqp8XooxTzcby63%okjs2UL<oIy)F_AB*wW2 zF7U=Au!?LE6^ca5NU&db>vttXr8aVbgQhHlA|pGtH5CjC1hyL31a{$<Y$LIwu9=T! zVF~AV8f{F-pI&Fpg`}u<u*2h(Rnu^_dD(Wo6|ek~q5I7AwooAlz!fNmEMO>6L9zuN zM6G%bN@J(f8kD=`(QJv@I~@fQ4t^7vX#K1EeUS{-cBktv_~OwwG<f~#nPLuhl96oa z)f%`q5;A<PW-eUmoPN2rV<mwa5((_;eRz6k>aruz<E80VP9ee6C_#xX9gvMi1*NK} z9S1`NpWM~$eJGLcH173^4pv?cmJZYDrnbIuEiGocuEYx}QgS}F`5m0A78E?aO_9s& z?&W8%pZsQ>Pxz(ve5?@ygQWMsQ?G^P48%z^wxGtARSuK~g3^cO8g8N#$Wk&TKhw(D z#En$L0sK$Tv#|6mgC0bEehs_h3}uj_#JKQQQd;p!&DvOSS;D8S%jE5~gq!o2*=W!J zoP%+p&P%Er*A0aPCUsdN^hlO7YEQl6@=jbuLRxw2$yei_DGr}@=VvbS*o|^<@mY|= zC{f0N5<IBUB<%{$3rVsSm9P-|x4A%_i_cyNfOO*!%<y(e@!~~w=blX9y|aeWR8~+H zXI<g?wMCV%6dFst@2ui3^DyqH#%c}n3`;*iK{}_k_p-P&lbAh#_BqAt37E&NlJPXk zFdtmJDj>HGQ+E1Xl+;eM>`FVY5FMS--J6Et;QBpyTtiJu`m*NdOcYD)iI(v8+cI(d zOFF8cFTBrkmJs1}{5k}*=L*94Xm58FwHF-X$jr}A2Ae=}n6&Uqf>ByTIKSztveHgL zUpyyv>IvD%=hBeZ7ISB7xb>-g%zs)-Ts!g^1I`*W0u)_^#<DrFV2PZQEnHo}3sI!3 zte7$y#3Izx%!srqM9e2gMO*-1i>}5+nx!J9GgBf?X-KuwB3N_um3F*IMmHT^-I=2e zlqCOTzsksrs_~1b)z;1oMcO<rb-Kv<k`0?w)y<VqUobb2Yx|ba@fPu+BsDJ0%$8K0 zGdECa`=-$GR`H<>em$Bmx%hfStL>ZP=U|*!@*4^ESNqbL7$Y$@90UjzP5XYoNSL(q zEG?a?dkO(HmKJw}hTCDa1!R`_;C<(<&j^_HK=mnjEEk}|x{$U3Joj=DiN6k|X(2fT z;<3Gt_=saDec=q405fH~e=WEw#5_b2uR<UR;#>8N0jV?-SQrnJD(S+ZO|E4uyuTd5 zk4R+&WOZ+oPMN3Kz3j_^K_jJ5c1<G?x?v|-Gp|#0Gj9htJB6_r9wwI<Njy&RN>8cV zSzhPDg&!FJUMD*9A-P|7yKb9%2^~}p82F$0B|u8`SZQ82v_2ce_a;BcV0ao8rj6U5 zMu{rsOd1M%L#Ay*sAwKXnK<>6wBi;ed&KGDUmw2Bu)v?=btupkP9GZe*B|7lf`U=% z5_QLj0PkfqXe0-|C6gxXcABkg);ntao|kHy;9V7P^ML8SlL){buzPGrk*_+`OyMa@ zJW;(Xl+sfhtD^GMC6%{o93Y09FURw%g@US1CVRZ8mrA6vR39s%@{}QcQ@INvtK#92 zsCnAOcqaW47QK$)S_^Kl^{AG2-+=^_Ij$Vic28JVE;PDvO*0y}3}ES6{{XjC^0qQy zAHg{ywNb>QV0Fu=>V<Kv#9$rfhBp^xNrVg`y2T4gv7g6{=A9iKYclR<otxmuLyw%% zS;*eiEPHQ{Y8d4TrjNze9@onKh&X*eeNS~*EoYCDFCpdKB=71mp=3L*e7rsc<E~}9 zQt0MFmIoz*19xyv<x5_eNryYG37=6F<Qoc#!EIY2BrWph*2KWyFiH0ampZFY<<sdc zY6+Sn-GW<FwQIcEPMJQ2SO)Fl@`&=8c`9kr89<A!^8SAqd&lTZ*Jf+9(^1E^ZQC6^ zvF(m++eXJm$F|+EZQHh!lV0onzP;8M=e%eC$o(Ua#;93!6|Sn9CTxWf=k+}7bC8rO zpn5EAy`aqwZl%F4`@&d)ZO*;hZi_igRNRSDB6zqFg0?3G**VJf?_VjAE5$$%v%yLt zo<oFkjwvwJigMJ1;EV?j<%S}U$AwzM-7_pW_RL~%n0t(eD=NYo4&9CxiqKF+4gjXv z*#Wo)rGSZ}Iv(S|T%hd{t>WuGxt6x5%-UJ`bO*`wJXkuY01ZE=Cg7VnrTs<GFa>(_ zdidF{AORFcwGQ~rna^Gp>1u97X_VK;)!&7B_p;vSYth6OGQT_GWc&aHOKvL(```G7 z8MIUFN`D0VKmBUAnSH*;H_xPuuc6=IE5KRea>QT}r*;3z_B-%`2#)U;@g|c2LbsXc zJ%3XGNv6aknr>OP0j}}SDg!p-pLR|F`g^%rJUuDY8?m#={U`C2t#m$82((VCajo-9 zyx;I2$s*DEf>d^I+QHhZ&|_0z!JgnGIGhav<6l?13c0rWQIR)kk#(_18CBTH&}&uM z$x_&H(1X#pg|>q5AnM?afr7Rf6R}lCGJ9_C<l5)e+UGSs+iuS6?l~duD;bn~P%tZY z2fP}dJ%bpQ^P1yw%(4L#sqY8TjcA$6Jcmp_hp)+E%;{BxUY4sYl7vqTOeFDkXQXLY zXm9n&secRR-P6xyNy>GRhcA<dt5=JahaA%vQ3yP7ChEmSPZfNlz?2@;MUDoWvOWZQ z1A^v)Y{c7o#_JLj$Y^pH8951iSL4Om9GsZ)fwj9oXttq)e;Yx4*0f{1yc^F2ZlCgQ zuSkZ)MSYHeY%lW94DIkMAAVh9K7Z#O=s~Y44HxU|v0dNgY%3+YMsL5u@knY87y0eY z*eH(UzH%2M{&t4G80BH;b01H0pTgTspPSUzYsn~=Z*H40)T=+IIf1Ef@A314+c|a6 zc*bN-lvbx$i(S797OIIiV>e&&pr*iHZKj$1@qr>+^z}EkLlj5RfC{J3=}&!Gww)+3 zj0OG3lj{Dv&8#C|3(iHX$i8Y6h550DwT|hR=)J`)t}o@c90p6ykFl4D#t9|NE2Y=n zW8{}c3Fhk-tSAk7b!@Gg=7QB%WtdMEw-$jScNPjer+q)pQwa8?D-(sLjCS2Jc<(t} z)v)?s#M@IBIC@V^24v^BPkn|5R-r226)W<cOt`MSu<GoRJcAcfgsx!i)P3Er6x_6W zY*c2lzN6wxpbEqZA5yU}U#TOD;)LyfjfjQXiVLULPR!L*{w0q|uYp-DtE`t&1}G1x z79domk*gcbZ&KHL%<i=<CAO*bz~W1&clq8Ch*QI_b2QSN!)tYpw@qr5vZQ<jRB<-; zh;TRHSbtl!GTmdP09SIWFTQveJKgNBvCF#J-9l}3m38?+dR&<J(LYF41>ZRRJEMg{ z+Axjb17Q9h`Mj^RV>R2JfoYk`vJ5b1p1ZK)dEYfj^$0|SNqfYwL+?JN2QyzxXYvRN znveQsgLM}0fZJoWi=sEC`{uN#7-Su!pF|n)O9flZeyE@Wuta7GY)bvouvNnVr~BJT zsC@~z-j+FlI{&xAirjP<i5r8p17e4AI@9D-$te*;)Sh);ijl1(RliGyYaxl;eApKC z^k%<XMqN&I5WyXd^I2cha@&<Vz3vA~Y8_6qc2~+`5bvH<`>x}~MjvRX?NvqJk>VJs z1<7kUG^+;9L?be=*cqA4aJdac_Mjy?eq*lexsT3y-j+od^io)#9U5(-<+qWwkfHX+ z3T_|sJzh<^haHjARxz(2u3df$!*`$4*+@f@qzgAMYoj82U2ZsF4ffi&ux7t5E37#N zpOtH?)!g9Tv&1Ef#!(}#$T!k8i-sNE>#CD{*3?)*Itt)n@hiEK55UX-Y~ait%CmXh zR!?%l*1Hn(3|;gMM~#vB;yI&Z+5K$irg6bUv0-FtMb^(_bKykmLTmcBD(k{M-kaIk zYjo$89nGpY%_=g7nx~-jqX?xV{%&NPFr00@m<JR4)W)&gQD*a0`43MwfKG4G$^BAX za<51Wq2nmInXpdFHSsupGV7kvo4ZXx)UfOhJFQQRtdurM$wKHc%x#>`kLcG}uT2{0 zghmDd*lfl1E{tp5f<bT!0@u_)x6}%dDG6~1)`-ogb5zd(C+b?c+9~K>&*-z^`I@^Q zZ4}{OTe)(oE!c9RZ<Uz8t-I6NIp|qFw%m%P*JEhw93ioX<8{W6$Vtz<`$Wc#^$)#1 zMpB1Dvhw!yQyA?ad%Xe@dlgw5s%=x3*dzbE)0P#>`p1q#tt}^?7m<V>7}i2n^|VFV z?try{m}0dp0hV!UB-7IsmKtJhyom9RMXfFCpEqt}v+kEJoBj2D*l&{ti_?TwUj_#T zWB7h`zQ&}T%b-(v7X-cgxn4uCtrgymdiUjDV^qXV*yeipy6;L@6bkc+!8yrx^t;=E z;7#3j)Gd)LBswzVif_P{*BF>3kO-D0owPVS;OV{Z9qm8a&u~}n7swY*cIUSKIHYK- zOEq4yy7w>VV_x~vWbuS<KqVSF6qsm;g4iS2^4GKA4*B<as$i$PP~^bsmQQ5Lp$#tU zmZo8*Q5!{?-Qc|TBr?*NO%6ur*Oek<W^Jg*B$I|ClQyB+F-?TP0#49KQOHz-0uyPn zR9hh?UlY>%5Tl=gMlzfx%S^)dtW%O?sp2`s#|UFYsHq~;{5K{ACaCaZ0-wH`nT023 z$vk^04K{T^l9_)d;^t?LE(otPbEnuS52P@k#tJ3`i72@g1^qP*`cuGF6D&~{JuchW zg5Bv$8AT+hXo{T+*M8(CTj-Nkq2>U^g8eX+Te@8*%br(UGs_-QO2t!s`W@%^Gf%}6 z%;%q-`B+k6?Y>N^$@&2@Wga!Vw!zB5Mq{5_jSLOtUbbnK3?DPhWddsC4O*lEc!v2Y z_mW3^cXqlt_zJ1rCeOGNmYrqejg>Rm+c+xnQiEQRB^F@m98i3Q8&SO$45@)-#FS;+ zx)J7L*mhYA9HQ6$Td&=xENfbg4*#T3a=v*|(c`2?fw0{=M*7|~++rSrKx3bdGFSLs z$O&$!A?`GnxHZYZ6{Y5kXz7jkg?NZpxJD-Kw3gW2#~_Pj$=@{Ev!C!qlFlHDrz@3b zOs7}j>@{<+L%61sa7mE(#XR;6W~f7=<|5|QTI?P;_6=vqOSA?r<}{f2<%M|=w`vgg zF!0o#EcsN(d#aZh^;YN}DfTVifRAWtLhN25mPfKiC*~AEo9xSaAw$2FNZ^|9(&)ib z?F_#AB%ym1TFpe(j~b*`VWe2qMPRj;FDCcCHcL>^=6C^K_X5y0aDW)kZ$Zm4q)XYv zToDH0VovNssBx!*%!3_2Vm!0aYUnb5)a<+o@5HfJlGW^pIei_HCR}0?y{C?)AzK<E z<_a_@j6G$J&5*8P5_RGnQqJeUCka25Xpi=M0^ur}c@r)qt1cp|2^Vb$GDwO(m5=4g zGB6iwh%%tVUxE_5CydpSt^xY<fcX?uAK{BQoq^7$pm0v;wsBeu$ZC>eEg}q%h*tz^ z%*C8=hAPOGs6_9@W8YARtnimgMV)|$yvSf`D%A{hP6AI)ywRAnSCN*|MDLAa-x!A0 z1!@{&PXV!OLN(>Y?pQ<X(lySpr>L>*aRwLS{-;=|OKfh$?hNb9Ly7#i?`n|FNh&_~ zXA~C#wWDG}Z`5XxKbZpOu;RC!sF#+6-(!$n3n?yS`HoVr6~<J)E<LCD<XRi7mCV00 z*PKq|wS5_EFflse^D1iIXjs3Lrr)?Ua&~PskGLZoaH9Z?<WTNBGO#~P&KK1)MWa+* z9+PLkGB<zT;uOL+rc0bV?|N#xI1@O?(x(0Vbcg@O;Zv*kUxnO%*17(t0`{kOGGT1- z%Hnf=U-PpH2Ke9Hxk))%IG9?PT7B-v)_1hCH+3>pv{rEV+*@U=;NWWUpY^f%i3`ri zO4tLPY?g6`@}ha72q=^EAUUeCgd|F=qy$ESh^h2TlHI?J*ha^}2ni{Lseg!sgdwBI z;t7%bB8Qu|M;`INQ~LO-bEn$jY*YghTg5fNW9)4|Qt5GivHp_wbesh@0h}Bh=T)Sd z<gYfFXY!yB;Bk0KgmhAqJz{JO+ft=Hj$YHs9~N1IH4bR>0MsBPOk`SE#L6gysj^Z( zMHuHU{2W`{7Qs7z&@DaX#y4(wy25XGxq`<{ME)sSEf|&|e;TXTi2PH$S|n^B&qXtg z%)@2+vl9%IVU4-YCfuq&!o<M!m-zQt$X#Us5ragyDvdgOg>m;2gfBJGbhZe!8R%l@ zoe2R?f4>%>w+a;^4{gE>VX!E|>G125BS6SH#JTarsCFKAUsP9%x%UUAV9f=rk?IM| zb5T)vs#ZQGPsM_S;MBPlVti1&=mJgtnJv+3c3S@3Rh41DQJolEAH-@Yn}~m+sZfib zvW_Yp61x5|!y05$1Z)-seLg#Vsg?hH=@P62P8#F@Re1nGG^#mT(=()aGrt6sW!Zw8 zg~fTbPtM)#VN4X|+H^$K@9k}bQ7$f19t)4d!J2y*w?WFd&=Ir7J5bW7eKGvPnaLg; z81=@C3Ee1AM)$o;EzYBUc-3uR+quE$lvGnQ&#%HnqfnBpcjNSF+){f^PQ&^4Kf=V@ z11b}yrj_U1n4#E>fPNbB4^SUYm31?eUYaN$B`dixm)eb%aHr0(8?oSyDRUZ8fxdQ` ztU@2L1hrK$#jf@=PsjOb*p&LE+0=G(idBDUgp@?z^SXkyQmTTJdAh9gGq!2;V_YQ> z$yB<;&Q!VldaqC{)D`ZepXLYbq@UpDzgYQe<Gft%GIp(LJ~#=b%}<cGtz?rvs%lmX zSEEY~Tj3Hj>hZD#`X&f&z;F}^l2VpJxEvWqo>_c~ShyCMM!rt0T0U&9P3@!617cL> zSdV#xx)2d!6r-clP=(Ty2>^p}8m{K{V24=CelQ1$S+W3DiZzlpoR-9*g=$>Iu1O%> zu=f>8Q;AzsZe9h|s#UpaJe7KV2cQlyv9lPExt^Pnin6zb!NjgiV;?<%yP<=+0aQU} zsz5Zd51+OguHK;3wRb|`fTq-~9sxn#0<w%td~+*TYi!;$M8&KZSuka(y4t9$a2`)l zOFz0ntzAd$sh}AL*a3)FDNYIyv<KTj$+J`YC%9bJ5nE}Dd|Qv}^rrJ%iE0Yp`K0^! zN<x7v*^0Ww>9tYxx-B|DJPLqt*<6(9(R^2vKfULENg3c!#vEQ*EInx2tQF+}&Nj*f zq#_@k8m8AoS`}i$J@F$6ftke!#&I*}!jCXy<%a1;aoH4>cm9~HPZp!%cxZKlO`#gc zFP&ubIdzT^EH1eqdV_uiMrZnB_@x;lqfO578r(5R@+ND3>kt{$W>OhD%|@BMq&5fn zt9AnMW>c5X4qd@9<|Da^KG^&Zit`@QGJTTyOQ7W|ECE6Jdv`)Z>eX|rQ(ZbiH(TI^ zLb_DWCvr$}NHTimlW_;z*9|`L_3DSG?f!tS3%y;UZZEciUjtD&({WiVb<wSvR&g9x z1`?Sd>&nM;-Fp3+dJ6e(Fr9FF+cFV*)KD!Fj=q`1N-OC=lHB2?F9_u6#4Etbt3Lxv zX4388Z)Q=f!seTeP42Pps0&~>Q|EgXgSi~By&Ro}(wUN-D62EET-totNpq6O+?Zr8 zP;2fP_#TLS%1wG%>-609JPpLlN???V8kkmsFjvQvhUVp$^H)wr1eSG7MsrX$<j;ql zTB#I*eYs2)U~@Z~X5tPJ7JW5O4LY1+T-l7a<<@(61RrNXvQjq{kUS{Q`Ei~YU5Y6c z3{n&0kHi?yNM?8$d4vlJhi)Ut3Vg<T(OknM7f1}<d?jCoZV6LhqmS@Yo_QE(>{Bom zKBsRfW(XMD#S3~2I0XuF4LJ8hkF=ADDTE7-#8RT-jzChRV~?a5+l31nc^E*o3igpx zjED{0f+Y(FZ)sE3iDo`WEY3nrn@47231>$0B=Mq;1Q|1kW<(60lO+#$80uRjEh!k+ zqT`Q{7(K-cCI)XgQabQwk}{K(n<S||f1iP3X2GE4dx7=fElo-X(agi=E6tLn3I>$Y z!?(aGUc@sp2G1#yozX`sGLq(l#E(u1UJLJk(QEzFi~Wy(`_oeb{M%=%=aUtJ_;Y!b z)c?l6{mYvXOIr(C=-S)=VFCEp3x8kzl*dk3eXf-1@3dS6!D^&1r69S*lMSs4Zt~Md zkVp9nf}zrFO57xbWt?EKcS=~PP;3o~T{H^}_gj#_D1$Nw95$h9Hzgy*+Dm)lymCW@ z4~TmpGnf(AO;u<uRfIM$4aGvKYOG36h}3l%DJ4cd!%3T|>H%7Urd)DdX?^ENky`Jb zKImGa*x)@Zdv@`Hft`j28G26klM0gzIL7e_KVOn&7DAV!i=soC^GOvmC{nah-b%8U zET?pbJI)OG08M$zIUZ3>4khn2fD;S!6-uU`Q1sS7pcPWS0zl{2rC1;s1IqTr{euvX zVRZ}y&kGq)cyOCt-|ywpKjF#`B@JdwI3%{)=ax#c9ZCJZ1(svF$Lm4;wAfYgb6}pk zOChN7!!!wcY$e9z8n9ak7<Fad?KgI3JgF5hCRe1r33pzNFgC8o%(&Iqvc-PL-GMvv zT75%qz<{;pI3mKH)}maI@a3dz5?s$W0m5ys($5)XEMG=ux}NiwsPdnNqgGXTRt_mO zFt_>Qj1<)hy0F$?)9Rn_RjzIecOLT0vrLC5ZP#+_3HIP5U7>;FVM(WbyzPNsm#s>C zJvVjD4d(8z$&!ES$iKBmP*xF!=QBEr{hTf#|8LqOXrgN;|GCZOKk-kbvX+H{A-Y$` z`)OIe|1^UQRvaU#15NI0C?7P)@MIU5_`nar=-TtD%&Cm1`&oFpw##uSt2PE30wQ=8 zBeZ08R8?eV0%C1bX1B9?@z+oW0wIr%O5=PB9A=4$hs+E2jRVj1tP7r(`_42Sphf5v zaJs0W0Ur<O=W6HymbRmV5eOJE^Q%NWOli}}wckC#@}{DK!#_EpB}fFt3-|Pe1ebrp zOTy%0j++dcpd)>A&`6AtFu3(tAB3Wo%DYR?tclcQ^KQu)g8;b!jL$N?0cfp_%8Az8 zL3_P?TZHC^S6U1oPE!1~#@3!Lqh8XTWPXpVrAy@p_^ea~fijPvPg(lMq9b3XcrN8- zFqI?t%1#u$H{ebj&WpA+HER7Tn5mO=CkqrMWLR9M+Y~bhhVdogDKNyQj)1{v=Jh1k z7k#k^n{`0kZLK}3j;ywA&XWq7osS!f?7g$)NnqVBK3zmNr3%*AW?bxvhvqDoSav&> ztmLiuo~#d)#H@oRR;LoYDV~qfmco~8c!|rjVF@9G&Y!TKS`!bbCko1--k-!VHAXdW znj%3u${n|$bnP{mFQ`c@PeV;{8+4FGtmx00z1`0fb=k4tpMcLMkXMcp6wCz-D~Fw* zP9E;m+rfs$)X#vW<*}9@%=A&lsIsx0%Eu%LFH<Ef@hGy>OtN2?$aIZDV>O?h>USsS z^J?-!DO8O~dNlAs>`J5(C0e1`Ijqac6@R7)#XXG|dF47X`4Ju+mNWg4Wt+{BKb=@d zGAQFxTnrk7Q%MdAODsgH_2OuHOPVZ=cElX7MxFC&c2h@D?I`rKDAGJ^hu*-7aetcy z0IQPVm8&BCR<DXv&yv<QtH?FNXqOD)NnFanqKLpqTyvx~j96)V`YPpVN>o<XtsmHi z(@^8&GWbm+P!iB>0D4R%g!~;V6G^rDdq)1A%NII*_b<j>3o2Kszvl~?tkc*^iIG>> z+1Z{>*PfP)b(DvhzyT-~Y{je>S@wqM^U6q6(=<t#o*tT!zZ2{tsArG9wkzGKp>SHJ z9pYkfJSTMpf>9UF_I4UY19wu;)?E_)X3fTq<;hicf?jwq$Zn#|M@{oXMd<JxW}{n} zn=*AtRnhLt*|*G0$biYjncAml%AqR6&!JJU@s=iGTYl1n!pnkisY;SZ`??t1S9T(Q zN|p^wJR>;J9wKi})dl?8*R&I3RfUV=6H6?WO)NH>Pb@YU2@{|6otrpML{Rfv@xK0Q z8ut7IlKeSMs;~2};vt^MRC7v?p-KP_j>0>zFpHN(52W6R0DLASd=Cmi!*t!ZD@X!O zl8}9I>T$}DJz<tYdU^G7y$9VDfgcHvZ7)LfzG#;@z^E!0K5WmRnsN3&*6E-|PG$u+ z^TYb}Dz3m$B3;|5&|42My%ndLkhrjSbj?OK)ze5WMpOw^Y(Y~GkX%*~uVRU05?iW6 zUe(mh)FpW4OTtJM`R2N7Es`!T5Qlf92X;JjMAL4nTZ__sS>a1Ef-Vvr9D&^R%+yGR zdXclEcaf-em??C^4A3M{T)pZ~BlaV&9|`@g$?Ht??rl(ShlwUfZv3dU>rdJ^XWI1G zTz0IlGbgGPb#mYuZLk}c^fux_y*rR!T^kgGkvw>gQ7iQiVXSylAI%kA7X#O%aY;=^ zKNzMk!o8p?jT!G*+R(NPp&Pf(5;PZX*nClk5^|Dd>(-FhkZw%aswsavmt8%)e%yh} ze<1L`3O(~tm2BlyBF;&lZgCUvMCG@y+EYveX}>Rnn;d}1TC}nohgrx>YAd&sB*)K6 zgR+QGd6uX)5T+^EYwRY~?3>$aO0e-afpM5EhB|;GMOQq=*lDiWVD7?K13On+gE<0Y zhEE~2N0Fdy{sfiL7P&N$yp9%_HT9Dy`U%Qq^fQ1nOlx480)%+F9<iDH)#H7b`wc+Z zsSkR-rS{q-`8ss|7XEN;ZFGP)KJP7I2z%Y_XfG0ES418EWfktSEC|^A97)Co_CcO2 zXTM6s^u-t+GbGG(b^?R8TO$#-)8AG02pe*K`))eYbsJRYZ4uO4&~NgQK6Y+2f4JWh zCGub_AF^N4hQWvEP~}998~BOGfni8?li--O`{OT{^iRk0Z<l1sWLqiu*?Fb?*?IL} zhaLY4T>fTvVfZ^-Nl^R`sSDLfQ6Ee^MF*5%3+w{SV}l_BK`b@KBT(Qb*@gJpC#g#v zPK<Ycs8J~K`<IUpyjwQ(3ClDe3yB8OGak=zjtP#3bo+~m&JFJ`i@o>Q24&=fKa>Fc z{E+61+T_W7EznW`xuEf1tXd1#&e*sh%D<yI4x|a%*lW>I)eB$Kv0$CK0C|-Rc_$6# z!7xFs%h3%kgZO7IWV@-BOBMAS7xgqBG}c@J)D7HmT*0f2ecoTibr%YfPiQ7C&|f3c zv_|OLwI}TTLtLngywH}VWsBq=BXHDt;drtLDp7WzpYvE!A*5Mj%{?J8D0jr%-(-8) z?ziuxUS=5uuSY+!h)@WI?489cp2wDF?*Qfe2>Y<7Q6oJaGI>};Z1nSYErdgln25~^ zuhr+nz6%dh<_oAVL)r=T)Ta=xXQ@$Wi&n-Hkge;X5wT$~=#*CcN(?_C1zlSRzg1GQ zIOnXRmUMf>=~@!n2d$2oO@_cE`Rh7<<vo^IAO+tz)gD~T(PPmfd>oXrC5#Fp^UQH= z-!4KCaR_sZo$ifMn-1clx_np;7|>hhN88<T=dc4WnpBDfLV=`CLSo`)8-;GaX_7KY z%(Hw(3&~09@I3+^^$4}FyOoNA$<tBAS3_Y$rrw4vcZm5BS_aYsE{Y)dj##Y!Mz#1w z{sgghz|GX>)_6LPkX2Y!tTS8Oo3P*GG=aV(Z(;|RVM8XTZ;(+8?sHR>e7dSzz`)cq zh>U5%CG^A)YM#`TS6^KA3Zs{HY{RSB6W*T=*ng_xzm+t1hQ@H_Q%QY3*R}rFs*=97 z)n^sS?sMBY9lxIaCpV+MgP^IMzN4vwz$XWn`6s==KQ_3Q|3`n%=gYMy=m*m9JA4Ei zvm;<G1EsJnm<ZI8#cYSR3oGX3R@J8+d%b<K-blWNqKEcRyp!)Vuld2F@io;C@jTpe zKX6z#9(<A#Z2;xTMI-zc4@p$QFn1x=6YoXB(B<A62@7$A&}YnpB_|@J(iI4rp2`Yc z{PC@*VjmNFxWN!Zx+A+@9S}~COqVdH=c`+4z;&1B^y|nSAm5lKwPHqsm8zseFgCps zrLSsbS37TqBjtQkklQHbJi<`t9E5b&!~`wyWM~`AAEC@DQ5i-l_<o0P;vcM@JC;k+ zzYR=)e0`5q(q}SM7m?vqYsB8FUe2#0G@<ZBBS@mWya3Dcle4%b%5;wDivKYx-a^Y< zk$GU3w$%$%!W?t;K1pVn*Id0of+qbGVcMxppm2>Rt^`SbtR=tMGC28_!3w<r4)!$h z2y<;8O%GU<zt=u!O}qNG=d%Ib$MYiTDOT^tibtH$;^EH({^8?DD^O=TP_4S<F^iA6 zMSQp#vqqdX7u{>+^+On)?M#$WUF|O758p!M-6{&baDoMEWJsf!LhmM>OcU`g^nUQJ zcxC#o6hMV?I>Cwzmub`y%t{X9&l#n6L9L22tQLuK)emo{p!$)dWvrMKZNW`5KuR|@ z%o4qnnYUG{3LHL1m!V5gV=6U&fDO*fk7NSNOk(d{q(|PK58!UH>BD^&Q7bOOS86M# ztI|tXojp<fE6^^yZ#HcgkngDF;^2WRO*>0R6;s0)@|QDEA)$RsOd$gw?6ljoa5!>s zwfOX_J)W1Z`|uZFilmHNeo=P?5)SxUoE;LfnmB0TF5k%>&j}JkKD+Rsw61Y3u&W$k zi!mXdCh)WL4za~q7^%~Bcad{_t-mS0k)g|%c0&N>6dt4KDA~6SpMiQFMLk6F9Ocyt zC~Z;zy(hlkwcI1jK?4yB$;jl8aWHlmso%i<n9)Ct<=<wc-|I0r`<Zqae<rYe|1JIa zhZza}UyBm6GIcQ3wJ>%2KO}}+ch(EMU|?WGU|vpOxK3c&0I>brSwsLB0*q8vS#OQd zTY7JsgXc$H+3YT&IRK1yA#8WnFLv~`P0tC87XUWCIeOdH8#|q&2mn)t8H<Mhg$a`e zPbJyzq#6k|PDdjy?Km<Dbev>2J|RI%Ln%H+bu~IdJtR3gR3=U{4Q#4!P&G;?z92&_ zDmgAXCo?`V2Fm%xB9S2)d?x?r+!p{CkV6^<#;6z*?72BB01N;|3I_kf04N9r7%F-I za<}?R-xB(wFEuF`EPhZGJ4VxQX12dN@&75Ne+!Vz8hzdP^BiLSJcpG3mjV?2T-xa% zXzlp<_<uQxK1<zyQA!C~Slb)^hw7wUX-po8AO4+m$v|Hf<m)!xqd!9|K1gpksBm_v zA_>YABL(a_X&Qst(rAGZ8*;}_CGFcy&=T%Xe#k&Ny`{KFAHTveT(=hY&ZidR7UTVa zO6v_E?(QAx>87N>P!Cj&)rlM*aCPcb@>Ft$JT|SPAPwlDzHMB8-4~iJdO7?2#WUwL z0T!1TBAJSPuGN*D;ko-s(*PW{AITNL+{kybF&5rcJbdspV5NllvJC_N-{B9X##GK2 zFKi2mhNCvlo*BvAH5(R&Vx@H`2zsu=fnyss$hIg8FM=lGH(vzy=)P5V(eHuz<H7V9 zZU$A*NpTZ5t|5$j2?q(_*j#YHar8{|sX|!vN_=Pv5FJo;7}BRrSqGK7gd3t`>E(>M z^Bh}XFv?@YE)5h1jlWB*zs#6l2pu}Sr}kbl8@+`oA&o#gai_j62l0}I_9z9NHAzA* zwQQ(FE!y7I9DIOlxlX_}1wzxB+KzNX4wEX=lx15?eX@yujeNFYP!titNO&x3=UVp4 z3Hqr5HC#p0J@euJQq^6B5u9iRAoQF=noc+ah=l&yaj&awR=6<rR%oL<pLDbo@CHL{ z+5Ck|V4gq?&~NFDig^@Q|Ej+{za9V@?m#8*13Qj+nj|D;>l8H`2D32nXS61#-xWf^ z6$Id#i6hQ9#0X3%{~I^)^fJmQ>|mh{%0h^w`GT0lHrNpbF=@jQ!*8ik7$RPR=%9RZ z_2Ut~qw&wxXaJu$@?vsGjM;56W@>?is4iOVJJ-~ex^TDUH6Sk_BxYJ!CsVh3T0uU4 zP{|qg%B?tz<%_S05vSIF&We93^uJZTkHRNh?c0|xdkFtO%zytlD-=I>#v3RYTI$-E zSlj)lbdjNAZlh?7;nlGwCGGS;On@Z{kz_D4-9kP69jMr6k(t<151#?6$md(|TF?IP zp{3i?r7!d9*7aeHC3j!V=EC$6md*VJCAo4H(yx*@j}MD>TvDbs-paRcGI^FPoD#pr zE?rz_UU+UCw0q%oK3>RZgWAB+_Dx2lps$C;VM?=bJC(myLKNz|@ZpADpMV><C<eg| zUnU2^nLgS;bMg}Qh!{R5hq!9;dTR!e8N7tD^M*3jyeVR5^&1D=t6}hx9cRYFWhHGv z3B2S$%M9I1FnXx<sOTMbsRVi`2iX&znRh=qE_n&|%t$>NK~s20+;7ZZM)>jWvKOpa zWA){zDSqBxySW&cJWK}oVal7F)3FOr*tB^DX)*TH;Xz7};$q_+t~k0_I5_Ou7#;rh znM@EUbsZi}Z1YQFSi_()r@W2AW;2Rdk2PLuU-FBiX|6bOX-_%LOQBjaviiZ$;}qC$ zI#UnHVTPw15|2Hia9BZS*qzGwaQ&ruJ1}m%jk*RGztk96hJ4i#_=`VD<!;!zN&hfc zkOlJmI`T}^t@L%hE9gYkOATBS^};D#Joa{ElI1rim<ARS<-`6QK?t|i6SmJ3%BV%( zcS@>nC^jjV!J!v6yx~kyH4d}G_f63JVQTYTAZk%VgnD3AA(hjt1*u;yExuQjz<luq zdLh>HdxT3IYHqu0-sZl0q^W;_-0duK?wUE4w3kA8j%I&4V*wddN39+%1<I(lk03!@ zOP|X|ykXe)i)P==P_YGOJN-aEo=QLZ`fU$fR%31=cfCf2v$P5M*-IRl0|;JgH=@1A z00r}4;;$$I#CxS=8TzA?MwHbAp%ew6Kzo$t?E2LBxLE87EQLJbUbB~4SMlyG*6)jU za{Wc%0mr`^uV=Q2&CrG;beH^+2fh`nqE4~tw*c15#&G<W`?&XgDIvo}iSn^CGiMzc zTT5aQxp`zY`mrhp9!UeS^;c|oVn)Lx*JQuv!!NAuPT4*6Ns+O+S*&j+nl7ZXYSwOF z?c)m>ejq3o$lBHJ{~}?T>|n3FKrQD4W1#He7r)UJWx0()PH*eR>5isGbG9o{yp0tZ zGsp}*NU@quV@}@<!iCwGu?5;#xMH=Kv!z?F&}V8mTm<W0vnf>@9qqh>M0o{w;10(- ze9VS^F?8p1bA<lU3X7#M>WzbTl^%uT5*&ng<bq3gXk#lYf)MP`MqaAbJx$jm=<+iv z9okcG-g9wy-}Yp1-U8Wz?kG7Re}`TA&;_INFd4=2qL1MI8MF{?sUd~UBC*0)d01R` zPA^8RG&#N^C4Tx8;mV#98`(vQCIpkmZFQ9K{luCg97Va)w3*yNDcdm_)XH=ji2<dG zXW<TkPLWDvBxJ^}#;Mq3EcqdAU2KMU<$CtgW)jPD3uB@_{ng1-C~fhV3x#{4LXJuq zA=;DOyT%g4x@%vDJ_zGRX+LB`0uN35sSmw1^|*?2pmUNbR$+?Uf??#uhL}4f*%BUV z!ofE~`tpTU$*ya0{j||kCydC|DKZ$_?fKacd#F&3v%c@bS!^a5jP^Snd~o?C+-%x* z*hjxsf~_4ERvm)FI6)^komwUeNJixEa(Y!%nRK)^7eia8M%ZS+&IJ}jP&~fVp0W`T ztofb<+(LO9ja(YDLVrL*#UD67pEzGTXL-{S2Odt8nR}nZ?Q3;$Z{9S<Im5%*ctn4W zVF&>qsH!_w>Yz4*+~s&XiJGMQE+F(NLE9$)dJ8+Ch^|j}%-C2cz3YR~d)~$CL_BbE zeWO0U@8HpAb_B>;P!J9Y?flHnkE=BicLo?CXgQ-uOrIEq5^{$>f|fOZ_2lcSvoJrk zfS$;n!%NEJ!rFu8*gi6Zu{S{~)5SYst+RQhVflzE-Iy8Xo1F3PHG73<+?nWoM|-}j z<bGg#KDiKjfLp$jX~X)swp<b8v*@=(C(4(rQZB<j*g)MFw%u5d?nHDadKW*n{2p{- z_)RM}2Mh)Y^B%xVPY`1evP1=}BKk{MQScdsm{ys4?GS0>GUjj(*!Mkhx&(MXgPUd< zYlg}=rYICC1@mzm6#{2Z0R;-vGs1#r)W_eqOvDv%Yk?nqZ?8H);e|SO#6jI2VF(Eq zGii%L!x%`n(*RF#>;B?5&`MlD2`SY#m7`vzNyFc0Ca6v$TzOnnV<_lDyt9I$y^czN ze1Ff$Yg%~~Dn5TD2DdK4CBS<F;e}w%m8>!Hbh27~jjdn~OQoFIe&7Ff83j?PZ&Wc2 zUMX#=tl^iGWq$F4@>3bnB>smx=ct(+uMtf4U}rWJ_7*^X1wSAc<y8atb;|V{6l**Y zlV~}d;u1pnVoZ4&I+b}wRbvH`onwm193x)Eh=p=88+ZzQ?u_!yLPBZ6rlMGg5;3+Q zZ*<jwGvuV$-P%;);YT8r*FN#Yw>`<NCvo)QuXx3Xi_PR50%JY8u}|nl$*3jC^S7EX zRb<D>1-l4x19VepX31G)J=ifxvN-#yG&f5vqaFqzrX2lwG1gl0vMQ6cS+2HRpZi!l zS(0oEgFuUErn%=_3-)TM^KO);TfZLdIq{8oUEAb`kQHl;=glBKs+CDz6wVmFH8G5U zI<GNQwB(mp<Se(MrUIJrwFTnbFmS>w%ut<6ILefgO6m%M&j?(<fvHOcyjk-gKce18 zP>G(&l(h%knom=EjjxZwS?uFL%`Ff(N4O=lZ?h<`$(U|W6kXm?3iBwL!t)oE2U3P7 zAaWrVNs34Do*g76*FIy^g~gN-ikRr^>OJZS>kG8hK9e9GtElFCMbh4-QCbf5EhE~R z-FPrbs9qR1J4k$N{5>=K&miT0!k0gNC~>_ho_{z9{XTD7WdB>FZuloWr~4~Nmo&9^ zFtjqXQ*gAgv9@y{mbJ5XaTT+2vi{`iHnp}A)wMFP_&>Q%xzfs?7@a51q9&Re9vI9| z1(^jRT9_6RWCv8Py1QIJH-VQXEr!~{Nud=hK;{a{V~*1LaTELz?>)e<m<Ou@v7{^> zF6HRxh}T|PW@3M(l1>LG;zt7tji~Tsm;(p~v=Bo`HhGO~A3b)LRKy^90t2ajI>BiI zOrv+QZrcy8lM>~*TSgVfR{3fg6&4nAPsKfr)$3U`22|*U9aQJAdb2sFHf$hCti-K7 z3{rV1f;<(BJdD;}3{J?PJ~Xogmh&<bbJEXpqQ=6g(ilUp+XMx~Fmx!%!1{VhZ3B5P zlf_A>QG(<-J-I#V)<kmZiCq{KvtVf_1N)H_c43{uT4DX_D8~#{peC>Tv97LvdK!qf zBnoRC&Dekf+5&6S`CgO@_WLw(66ZvFjn;5GJ4QP1k)8>|!(xay+v3mpveXd?ULHb) zt0@dO8NL)N5&QY#;|v&fdJr*ML5-=I+cDSjV-@LsnxMhchVfE?HmV)g@^GiIsV5>q zMb@PvJ2jw6d`Mw_EK&nW%47lQ{yIOdL8KDD)~3QuUfjWCxk>+EXqgWkI{Mys<w2V} z14B&W{<or3<K*M?0i3bgp(WSk7I~*rmAeYaf?i+@OFvc=xf#dv=@Z<7hqtDo12y(t z%KO9T<)7|FkrBWMp|eu~p0@GCNi5F3*6tlS2eYJ!ormHq7NeOnm=U@)T@sItULts& z7#jSJK;eBt2b17TUqY7)Gum+K)N>qt_C<|0fmQdBzFwH12u1YM_xbGE2AvA=K-#8* zdPw|=@u=z3+&C#nslykW`s$e!-OX&wbkW62)C3i(D=seH`i-Ft&{);I3kgFiD2PYE z=YI3T<t~8{JAp6FwD|RTk#O1q!rx-am?<c_vK;MTknj~)TP>Xo@1`88>9BVElU@!f zt~WEv&1i$a;D=|RmmG*!j#mF1Ui|V!+>a&z#KK$6+V>>7xQeWIBTj<1zo=UNWkeFd zAdp|aef#$1&o%h>)eeNy&nxhX&kW(eUW5O`y#B5o|7B?crd9@@9bW&Rwxywhq=NiT z3W0$R)-2B7tKG{AF{OCcN9iXjSLCydUoKl8teYA^%B02woRIVm_p+GOaqC;5MB8Bg zbSUVpsM2YV_?02aaN)QoeW`Y$@!|b`-8k#%C5ul7s0n1{J09=RcRJpL5o1nXHXBeK z^pLHRS<RDPkP58i-uQSc^jRsarcjJ#4~jA4y>pr;SB-(Ts7i;`DR{WRtXe@BPbitb z#6jeMw2@UUZ!?W878t-3?9F<AEctSMh{Yk7l{Dcg%?eCXqlDA1?AC}y=nMf;a|v)9 zHL`;+o0-D5rRB9yH|Myz5E=FgBx$pz)FNX=>l)=s@d}fWF&C@`;@zhEX(QXU`=mZM zev&P<oGL;O5igbaYWj=l_rtQ$y@DO9$+5OpVS_`L^K=_F$cD<UbZ4!VEQ%2P=%sNw z7cW{O@$TUjj1ekS9yVDaT4O~y#^E*K0<4Jo+tIQYtlchk_5fa@E{hZO$9p)?62|Zn z4HlMSpSZ}D73J&pgB56n^O_)qG0&PAlC2x;fCjv_uEygkDlEv8r5tjlW3y4-#?#nQ z=E>?`y2NyT!U*cF1<sYnmeq)!%v0PRb_we>>jl<Jjo3#mFGWpgc?qF2s>}>Naim~Z zQ9<juJ*;GY+;HhpBuLJ-G6ENA=-pLOl~M-PWjns1C?5LT8r;lR47A6pEY(35yVrxg z`rHgxJm`iviLkNlZ+v&!f)i<hyLqz<*}l3T2xc4??tF>nxKe{R8}{*Ubr<254b-%L zpk%)u>_hj#h15jRTRGC%3(~G2W5IVypN>l~3}IT3Mo}fU8p0;DVOUOxv)inO(T2Yh zE*;J`YGh(T4v-wg!Hl;%WLc@dEt`}8VXt0e<1jYeWLYOFD>&?xx3Mr=8dJ<Vb{oyl z3Q#~ClKkQ%PmoAd(lGyWM&__wbBb@{0t>6qo>k=EFkTlS*3j}T*4p#-3fEiE6Q4uq zY2W7BdY<e+p`F8bl}nhz4}tJ^7k2(WbUw}dlAcGF*qNY2<ON}@_yu9=GgNi(0o-K6 z&qvzZjfAsSP4KDyI|NJITwoa+za36Uez5N)rw|wV(6X@xITT`cq2#9D4hH#qf*(UL zhqlnXBu0v7@g{Y0w0b5ElkD8!aOiY}F2Cv*-|}+m{0e^lmPJ04!WE1Mez-j4bV%qH zkvGE3BTunK=%Fd%60xh8u#1d{600C;$Ci_4n|E}=y~ipf1Lv^)wGUkv<Ex9cQc0tD zG&6dP(7la-9ma;>1CX1x;Lo=()!RnO(x$NMI6Vec*3ueux$1iH-oZ<lNFRxk<0RWe zYyY(N<Q{PPchEmYh<_d?|Muc3)=yM%pT$b(&!dLtzj|>OeM6f+PMYqskY;5F&^5I% zG!Xtj|NQ&9DkHX88khk-$ooM3+m^JCjRFu*H6ijhl1Y&0?+BnGMPqs-fL7LJU>6wN zKuSc=KV3EbX*S;k1euuLo%ho=)H^$PI=_(X6NEDtNF_7q&UdE=x(3C3e~fK~*#eg@ z4bSxia~h>rouT~J42iWGDU=HTV{bqrNK%Os<D3Cm`IzlBYK2xs>V^6?-%ME<3%WS9 z0~NZ*vA9=kR}11JU8gxOVy<2=oV`5PUPUsH27~@|wtl1TiN;yI+o|qg>OQ&6FdSTD zHE4INqFFsukXFmq^O8UromvJ2$hsfPi$gE@`TVAB@5H^9qaoGF1$k04+ZbH1cmU-i zz;ME0mup)#)f~m$b&Wok0~+60U_C%A=*)XPUH5rp*fdYzD0JedssQAEr5qY#75T#y zg|8QJF)0)>xY!aA4L^s1y1743ACDk%ZFP%e1PZhQ%hXZ#H^7+2FEi+!UivZ*I^}IL z^ElN#K2^|Z&axrelMoM53XS~wJJwh}T_w!rNZs&^2ASkJ7NZh@wy@0a+*%%g^;-QC z<NrbbkCQ3LQXp6PL|^O^eUASf`u`X5&$6|Hp^L+Rke8Q|`N{yFL0IF5=Rtnlm5bT5 zC`3yNPX{J#&b-tc4z7@BM5CrY?F7>~=Fj&V&oG^kkXl0EG(TfuJdLgL=IQPo=*xo5 zaaT1s8OX2&eUrlUb*QJFZ8ror+be;)KC=;Hj_;fR;0$y(n{PMUlFc)pXt<x+V~<%e zHzwBT`Iqn$@vc5qeBRo|Oql@I35HeDiBgVXFFgB1^yI5AB9-1T)J{{FZwPU1C?GKn zMxL|Oa+Pol0rC*SQoe<Dfr*xpnq{+=_h+@QnSQm?@3q=+=6SWf&q{%}gH~u2Q{Mcb z$%i56Y1s#IT7<qdUdkkfVXcR){CGN(_|N2e5BiT$cPr>{RvQyA1aeTyDT0eo^xEU2 z;wC!`5cLmqa%Mi7_U}I5VOOuOK^pMkd|vJ?=zM}7xLnfw3HwPFGq&BU_y*wUX$1{& zRTwI|2r_L|3q;?r{@Ct6G5R-pZ`zd*U7x72d?HBu-_ZLHiyNKP-)wGwLuMJt1MBzw zlW3Cin(Q6fEjZs6>1<Y2-ISX69%>2S0LXuHi<;XfnDM+MTb3+kv~B2NeHCv3%ZCCC z)eZF-#EH5DIH?{VUCul18p=5KfMF%DIHUyBw^n95UB$6D8urfr``W4f4(5zboHssw zG2xv+Qr9b*+MD~{d3Z}iFJ}zp;>tV<Tz;~NY#*}W=wqmeNLLQwNZ9ME-Gu7>{$em0 zx|c{A2nfxg83u?Yy0~+lUvV91>r~Y7!+y?7>N?UN;rvqs{}zs?!|=BIr(k}3rYLm( zO*k@oW`_C>e}_)ejusYwOD9sEM*^51-qT&%jx-aqv$GRlIA_zB0tJE4&yKuEth2ey zsK-d<oE8=JowOc-`qbi;j#V9UdzB<aRqb?id}l0eDaG^6%?+$7aE{wzbe}%h6&wl{ z6^EJunGiv|;+QZZZ>qlM^Em6J*JR-gYmPe6bQCVgK5J|bUqK5xjhba#H$*2-IDvMW zV+QRhqN`^=cfus(K7bJ(Y_k3uyGJZ-i&wXk7%_<BoS<g|SC6WzbVZIBVD(7acKe6| zr``=ESty9(5_U2Y<~(f@j$hFyFWg7$oTf{T+~!J2m|G#{Qlogk@|s%s%9|nj#54l~ zY>OYa9jHT@2C>u!uL(Xv`*{y2`|j*I{j3q8E=pk9R_pNVy5M1V+gmX%X4V7G9Q_v# zgTdh_5mfLiKFx$c6l|;)1V({IAU9E#nm0(R3<Z(F4aAsRu%+jZc)dmu0U#s_V?+f{ z-?0v#w=XB>WPE8q<_{`0U&x#}>zUAHPA0*BWibb>vi-sJpXmJ$u7A=_GpGsGJ*_Wa zbQivSq5N;S{ypOG7p{LpI_e4Gfh>IgQF@+v)Et+R_o>v9-<*@hx^eKo?|$2Y3|<Wu z7eE~RPHX?m1@ADdu>#HI_jXssc32KP-R#}EBhP~S+?->(ik2e}{NP9XajLX2Bhu8} z!_(_ibmsB-vD<~`NxMpARK@$v*2_Kc?{6e4K-Qwx9Qlp;&e)r=?_1I93G2DDd`HVK zu<XjuXc=DLgW+)C6M1uH2TE>3rJmzsvx=uXEvFA)MdLcE#B}5noewYZI6Z_pItpgl z;-BeoI`U^8jxKRByeh@{7W05%*+rh^5@46}1*dg`XDR%Fuk+~WgGVnjsW}YPln<A= z9DX0%7(n5ak^7c$8l+hij>1x_I>`?UQ?Nl2yB{(~!XCv>NPy#I7|Bw`$z$ff#t-L^ z!6)kPeL;y9T<~*X6Dp?1u{)X!hIMr~EFFH^o#Eo*qVV?Sg#I-GOu;f3l@Fu5=K-#W zKYk6*;Rk+%B`$m<`-@RJCmL4R0bM*;_qHkwZs?P4^GNnPTM&{lk)kWHA-b>%U?w{m zR{xMb5q9TLRv`GwA^Cf7Xn-;WPE<}0F{flf4>G4@z90rpf!w~GxRmoS({74G@?Ny@ z2#U086nE13cy5nJng{b6?XPE-5dyk+w3zSqq1Am3`Vjev@@5z~i8H#OILgyo=t{ha zl=tkMYQkz%N3z0&r4&k1#h6MJ^+V>^HV9@(ZS$lH9J|SFQRkH^dv3$i--7`y(?Z2Y zoY*pjH1THnifK|-g>f(r?7pyM(|eH)?4ht^NF{}`$BLZkfWpF=EojbkvEbT68&(|F zsV!`9O@b_m;tg5XgDG7mUnkytT6~h0XnC}$Exk04P^petQXPPC(#%#P@c>GE%QUHu zVO(Xwjrq4e8iz$Qp5t|zTWc!A=6TK`u-B}+BDncW@Ax;)lf1oWL(bN9(hVN~l}zHq zFRI5yR!)n;o{PgOe^|EZEmFj5qhOElwmA7tl|4TCD(ZAT*JEa|jxa|htdgL46_yH| zma1}+`6efB;D_0Q{`rQI{st1IyR-Ua*X8u5@I<C)%3;gv@<%R5U#X5r{^ikT!<oeL zR4(hOl55xSgG7cOOoq&n(qQ*baU;q~qv=fcG0@TA&}B$^k<|^K{D1G!B+&82QY@-= z>cVB!PFC(c$IFSrN~I^}q1gq;CC?;EGz^?*XbBB1s#N~`C{i@$!OAQuN(*za<yK}U z-&r|Mh(IsGSM=`6$$c=*Gv+5(8)EqBH;6Z9TS^iG>jxSaSd|x|@M^w-7Wd27D(rp7 zM{Q72s?1WDqkgpMRX<>@56!tUu-gIHA`a^;VG%U9piqFy@5^nugGp1iS1ZSdFiLhs zoFKH!HzbBF1BBR6jrmun)ZodsZEXwi@nOEHc}+m##+Hp668nu~jO2l%v5Z+(R*Lv6 zM_U$p311qTo10pfRhS8~gOO2q7)?)G!YGl^M$XmEF$~Jw%U&1eErybN&ZM%G*IO0^ z4(gU+ENyk#!fI_x+OV;T9f^ea_$LX?O=I$P9a~RP+~{C+vX@tbZI$Hbdg(G=#cW6c zZ9Bwj_LOuLMhgL^(@2JfIi_QkC{s$q>Z|VqhG=MPJxEnl7FgxA)b%3A&d9@-HRtA) zSNu4D-T2Q;I0ZG#7UnbA9Xh<i@r#Rvnar)s%F7uTQ^}=Gf6gt;HvH&sJ1*#lsi(1o zGQ%pF9LHKX27wqYF{3U^peEkC*@Z7NfmFInwl)wCe}e$V8vjXzo_8WVrn#~>E6-J5 zQm-8B(e&<*p@>*gLJ|l@2IOvJSAXVe2x{oaoMSZJ>xQ3ZJeaOB$z*TvIjnwTNKctR z*v^TPUwz-py2gWVd8=GruS7HF$Vrv=0}O&mmt|g6!F{`p1%hR|{5FL+XjR>v8{;co zycN^8LN7l)y`3P&&Z8tHBGeyfgz$T_MYqEZg~j=#^QuaGOtb}SKA?eUY#0&mPx&{) z^$RNX4OcZ&$@9$haadKoxAv7j^U#ejIKskZ1VJc!%(x^C9uBN@zA9t!`5F`^I+iAC zp-%Dmyp(}-nKQ3Vnliln05Xf=syf<Fd4@$&ST8!HYT_s?Tn`t60BMNOkhR#cCbU&& z;|-?QA=0Up1j2ReAP*D)dC46jt;z0bQKpD&#V7_2A!pb^c%`nOfZ*8HCZ^&hb%FEU zIacF(gGCk`2*;1C1x_H_W!X96JP<kVwSYBkQ;(UKiDXh^l^pA{@F_6v&UIxWsbU(+ zmqry<18&xIwwa7#Yd5zs?y92Mgym1f$Q7XKYwR?D8>(^RaP8vH%Fjx7ya2_OT7u<z z5*C&?JX7CuhQ|!<OaToP_2#LAJ$h@oC#7cQ0w*`<&SaHc0N>x|nOZ7nIu91leGUrq z4M=9qyp2i(Y_(B?40yWGznEDRh7ymTNo%kw`RnF>alRx?ODyZHu#;F}P=0ps=JWOo zv(}HIxPaEaw2BO1rR^YG`vkNhxgk>FR1P;P(9dYftdpzFB&81+NNvpSs;vPmPhk3+ zh|G2368Dajm8k*&BJzu)yZNS?rxaL8^DJ`<w5QWU{9=_8*2R|PmP@kX*=sokclEo@ z{$fnDmS$=)sod{_E*dfE9M<+SZl*zxw%&V((}4H^#VzzhB}-(?ZS&psVpnt2RK}4~ z^C|ftVt3-eoZZ|CTi-bRtzEY5SU9l)9E#mKX2trLo2|%0Y@SG608?}5qFDXS$qGf- z2(l>F6wwg}=d(dlp)$+t{7IxHBa2j5FjlTUZREGh1Xk%T?KLIL(t?U;il4PD?fIbk z>KPb@S_)+`5rdlVZF47Pr7N-Ss2Y}@mj1Z@#>B2*68{eXa6pg0T)Aiw{@54B);3nP zwUh5Gny{#(XV%hu%9)f%elm8ZCe3Q8A`M`WmA`UU@*L92S^W0QRJUjH+Y3|OUdV4x zNp*V)zdbeiZM;*S>cMh;yDZi1G6s>PFr?^YI(W<~B07rJMAF{agfUoKZ3DNT_BE<> z5c@!cR*HfG1Xb#LQ+m0#u$OyNd%0KE%f0ec_r@hd=Lp-!@kjP-3d(U;!95T{%e`9) z{j{RrX|Jd7qG|QI?&DO3$=G6|4D=bvN~Q=s)<R8bR+8HjBIM})z@Q)*TXZ)$XC+Cc zI6?p?rlNI(&v)~-{CRBtQ!uK-!^4BjWKS8ebh}K<bYartR_~Z}C-5^d=|SrVpSO`O zUK*n&GFiNFq#l}rb{g$en|P*H3Ph_KV{O<l)tCZ?q!pONOQUZ65o5R-^!shK=Drs8 z9cUn?8hZ}ZthCfNG;OFAjf_=4!{*&|x!bUTew~j&Wf*C5j&%L1`BJh_FGZ_Rt%q8I z3?JE2+W0Vog%1uH443PMg=fw6DAqjQd2*RYAi8c+yT?T`vYNT`i0kv?BU0AZruG&p z&aIO&Za73v&X!A@2u4(KioujfnQ8pepgp-CtN5j*tw`Pi#Y~)ve%T_9ITtt{{@G%U z)h)F=Qykc7RTM!bV<$=2lWcr4d4s6;l6fB_%~XZ@70pC@L2YwwRa<Qh^?4m_v4+}3 zO%*Xx-?_h-r4`8`SJ$=>r50`?M6|1(Icox=Kx5M!gp!ArwXNk%Ey!WLXwapV*u%Dy zGK&jw4T?AT*w#0Tw1cwgg{o4xE34><B<&F;w<xFSNg4-ls)?<M(QvBITx6Voduy8! z?yIQ!E%g+m9bv~OIdTe##VxyuepTMHuQ`!=nY?4|D67TZ2My@c81DjfN?4CeVy!WB z!jl^to7$?{VoenG`%R^HJwp_*=w|NMhVkQY;=R4CxxH-!%}UUKvoQjrUyq+2S@$rx zT>kv2DdrmZxWxRb8XE6K=bd88A$fJF%~dseRVkQiP0r%XBeWzctcH6+n<y3wv|^Hv zMN&fV_|td_=hs><fazu0iUx6LY@KYu-rn3?+oC&;)H5IYpa2aV)F$WCTF-A9QI`1u z>Z~=L5GUfOu4<08Rn>D??L4^B(NeKTB~)CbXatKUin{XKT2H8I*2}SCK)r?}aPekP z*ei7g+gIZ;M*5k0pp%b6s<GC|_04rvG%}{A7V7P*N1S3uxV9yR-MEbI7euynyxLkF zi_J$6+Vm*N9&4Q&f5>B`MSi4WZpAs3`id@S^b3o-D#Tq=yQT_5*m!H`=sL&T;$-F; zF<&<;rL-wEA=M28kas2XvHMt(DpP4b=AnKh&)UU~m`Ag=km1wZZ);tQM*Gy&`eY4n zY0)u>P=lw+YU^o)n;eLvYV~To8spD8t0+CEN*^dl@47W7R#QWOTN^~eiE+-_T7*WA z8+ey&o|yNuW1lRZcA)n}z0rqiCEf~%k=ZiSjov0>X_kU_efcbfN1vIAwKg^C+H2Rx zO!!TARpUmz^7N@jPgQ-rm|W2>=ml{b_O#YDwV-lP?eYum`liOUrgPm`h)Zl#QPin? z`g(p#?HZco9GrCaFqy4pv^F3cwZ`bIUZNjMtiZ}>Y^`gnjWw3VX!@R@P^z2A$xEwf zh_-DN_M{k1O5r6&6Uq(vhpwB|sO%v=l1rSn)nVVOuBo0TI9Jp7c2&zpoy4rFmZqh# z#`X2JEnOsj!AwsXABe7QqA1p1Hm!W};)+G97EYa9F>~(pRppbXE}FLhnJOcW+K@eI z-3h364RI&&^CyOe&{&0ZVvG)rG<ktdl+-|{tucyh@d2`MPJ!b}WE}joyuON$pf&LM z#Ri&R^t9mvt<6oXG0`$wn?*IIBSz)zC!Msh3!P~{o7p5zo0JwEeuL0a%-FI~PiMt1 z^AR!bN5zzcgXa?Qj6&H^Qhp7UlTOXPi(fZgu(Vd|qxY0il#$y^*4xzH%Bi3>8f19} zRlXxWn9{0u#xlE3%(3{-uf7#DH{$Lpjn7EfT8%jy8nqELt*zLwP*wQi*Shtd(7NNU z#DkX`c*`UlyaQ!vud3H^O+Uf#^{rF&o?1F*psNj_k<d61&QV$wI)Chpt(g;RZRL(^ zS?}>pcOg^ztfWznE+}!a^k-1{c|-yU5_RimHd7$pO<bF92gFlO;@xhunQcw+MlnBs z<&-1ze3sQ4+c@aFk6PO{x2l0^ZQ6;|wawfRRe3j7LR-_c#_Fb;+L}0tVFroDSkqAP zFc%(wQv_}z7s`?PNtHdS%6Fn|ozPN+PRd3<x)Qo6X~M;^kauXyW7O28>s0tsr6MZa z1s}o3s=Ui3O_T3(!58qQD(}Hx`ED2d7ru4L_sDx)(kgkM3x0$zUC@cw7?V5jz$69( zj$};~18^}Lb28{>8fw9IWNlUb<d(JV)Q2*F#Cq4)+~iePQ3oJzb!}cF=4`{R9WpE5 zi?HzZJZ*K!a<CKS`{;1Li+Pxr1bM*4GBCw7I*gMabg?WJL?jZCXOMSH^T{(Cv29$< zSCN#(s;XPi%c2*gD5CY$s7u~2V@s8l_^4P)qRJ1u<VWSlRQYk2{Dl0Ziw$4{UGh`% z)2jSumt<p-Oa6=ej7$Ej{H%)&lAlxM=Uws(@{2B3$cDP)m*l^>*a%9!j4AjA>wpbn zgIz2_hjDBo9VWZj6gJJpW>ab=9cI&wIhaCWUvbH=VqM9v$*;TEBDR=PZ@AcMR_$VQ zsgydr#@5qm6HPLBO%;Ms{o2|V!U)-zO^37CCOUo7CI6k}VC&!2HW)KFs(iakeoKDN zC5=b@k>8fzaj{F;RW5cDyO|DKU2F>-Ze_b%@;~Hv<E0orfctQ&*!Ns)4||0UPt)N! zIy_H@7wPZ<9bTft%XIh~J@HSM{J#7zI(*=go<W_&)Q5C<h7KRm;bY4DDy2SA<v+UQ zPe~m{%b%(8zv+?BRrw1S`@8%lWqXYd?=k4352EF5K;~N3w&pdox3=ZQ^$bHVm$aIB zRrx<I`78Nrm$X;@#wG1TY^D1t^&q7jlFKDI>0m<$B|F;`*P5Oyok*$v>yj*#(S|yT zxxG|^+a-UCGD$uu8+qzsI14F4Hd)Qe$*VC2L}kotYszcJ0GdRoT1!*-ZFzhp;XDkN z*I;*QT1!h)OI~4~-W$$qT9en*SesYh)YP08Yt3t`tIgxRX1Y;@V%JglT(po6%ix8Y zyaoEuK^~7k^Yl(*YhF!L<KVVD9<`L@p<l||(3+>p-?^kq<?m4(`3JQAl+J<_fx8M9 z`<|rFk;YL4AHWo|yQC6nf=m8UK1ivfT=F6EJS@*8mEm<f9OaUxQ;x%=0*B>J0<P1g zfWlmgq{#TFqTn?;wV-h*RywF;CWq;ojZW=&kdC300}t#(B#Q^9OR86#q|ujC%0(J- zpG#^aU)E<1dWnYihCHKZf%TAg0<AM797kcmR#a5PAlgg56Ud7RcZbi6p`uaV6WCEM zwt#RuLBePvTg3f6G!et1Me%UC`^~sJRNUzB6pxZdhjf>;Rk{{yMDe;5pOQgC@I1y# zqT+icRK2}it0{Fqr5=+WcS%p<0X|YPvGs8&n&PLEtZwd9Hy^Aa2mZM+#!lYoV-RGD zHTmeCujk-)ykt{EimeX6gstM@#@6=cX6pOY@OBqbGMPkns@9XQ1IDnne@cbq{!KJq z{-o2aD`+GHi<?X{xcM`OOr;;b<|i{hX|t{+Tk^1kicc|irsXHUj=ZnXY0ea@33=0A zn5_JY6i$c2D}IZH8i&q}2cs<m%9|)uSM(p(%*I9x%Im9ITlx6N+;Z#{1uIfMh^1yG zyUFJ>#R-GyKM{f_Ejf9lr1#2Ndg})Egg_tfp$WPkE_qJ8JeNLmGF4P?C|Ol>EkL!R zldYv0lyH8sk-e^r-E_dDNs(SXV_X)Yk8b1@_1hS>8k17?6*E)anaP*y*~QY(MNKKx z6BR7O$YTzoE&2NTwzOF5jM&<`h3(j;tks8I+L}0O`UJm{KZF+Lr5;V=xBW?%awBmc zU;Dpm;i3i9H=n#<!Q|zrhE+A#!&KXv1dXKY4u&MTMg#e^@g)@b`ZylSfmkfj?TJ<b z>zxi_x!0O3OjeV<<PYV~>iu?E@3+g3n3<Hln6CV4T~+H`KF8DDR~a~^4(s(SLK6oa z5eVbsj=kFyE7iK$Hcj*9CXdgnm<BnjTJ<JkU@vQ4%xl$>sxvBVQ7>-|Bz2Rh&*rg; zu7}b7>c|lE#mD~q6jLzVQc$r}KEcbE*(TF0@*>qu^lAeqX&T9mgZz^N>G;^9SX+I3 z(K%8<)3VWMpFSXNLsn7S^)_c^iV34wtBEw8nM%Yn6B0H&t8L>G0cr8%yq2=qT3X(x z##%)xn4~f6QpDs<>k_i@)yT23CdNlP^H<KCsavU)l9aIImzB{-o~1<}a8l5K^c6$N zdh|=W2APczAQa~;S@#;lyWTtQOQ0{f;0=0D3IgyZ{2ds)g=Z36kLPcj&fR$aj_Ld# zc>b>G{5?GXC%kW*{|j>91Jn73JTLar@%RZ|8HvBxqXtW4AFw-lmQVRxSP~vPK!JPV zGfcVkOz>~`9DnW9vlj)-6a{2No&Z<mUcg{_E2zp&P~=^BS?0xAd6pMUMP<N$;4A$7 zn%|Y(@+53P;2WdZDWX_+qyyws1-@@8&}}Nv0+JKU+e~8)qP&YxAPfE$V0p?GuqeAC z718|@<<f9y2V_UXBTAHjf~5GZO)}fr`LT&yE~t3?0gnfe%Y%sNA?OE(VF0EhjBz&n zNFfJ-BQ_MG1mD5;f}u1}?1#as!VipPe2<K5#)7_0BB~{YsLbC@)UJ|+sCF7p5#`;4 zjL7&q6l=tz*U0h-TS+c?Vkn5xMnd<3Rl?d;@v6LQlSI-g3DU9%q_HS?Ss`SzA{fYq z!eC4nvJsq<2+HWf{0F&iWpG5^=SnkFRD>7H(eLUASkevxWAvAC0NJ)9e90=?mI{IC zKULYCKew`Ny;L?k7F2c|*jXjyuqx=sR>J^HM_BDIsBC08S!LT(iF)!+R5p#4iSo*f z@}5M7cY+$(3y$3h<y~VgkICo)^zu}YY*SUHV2Ku^#AEQ6>d}WBIxC{wCa7d3+Epxf z59}_mussGG_=G6hf<&y`&wS0vN(UhwsZ7!-sRpHKf_D${Zu7ZQF#n8+c~5ud?Sgq5 zvx_3f<D<li8j*t?;Mr|BG`*}ZOx&uXEJ``Jo>D<hQP7)M5LN8b;C0}>AJUfl()WS) zp-}wHM`y^lh3yU^*BLi~)#u(#snAW(Cm5>KFFNRFCs^@9X(Sll3z@qk!M&h$2{{5q z1E~lUX()K4;oy@-Ku8(|dD3X;CyjxKG!_b_5*RIwhgs4DI9e(-3~&~*?n2hd+Ls#Q zEM;yk4y7F2D8J@arh42KNA?t^qM#n55{7}q^I9XU1N;eqNh?g?TLlF>OEaE6Ry-Zh zq2OiAMwzpO&P2Kd^%0&@I|{l1z0Zl@k~W$O514A!2C_9>XiK_5s$7sti))L`;Mk-t z(r-<LrX{FLnO>%cc}1DWVVR^0T10pKk=+qg`0Uwq3?#CCC#ce0V3+QOH0d6bB54Nl z8uJ-yF9Ry2od$~qt$zrOTEH7hREy;kw-QCUH2Ne2!l7+2I)Vz4gKl{XM7US_ca$TE zndr7Z%J1)mptKF_Jj17S#iUF{;6z4W1h@1OGWjxirB^_cUWI|uYY>&*fDzK0FiLt0 z%B8oVLVA}AF$(R~Av`&Wv%nB%fe<GRri!~>n9MS{!jXs`u)1}hZef}&3#HWzX`e?~ zNi7#9NQ<)OgtoxgNJy!P3me@eb?)r^%n%muXGcYbxU`hxlZYH53o^uwAmbo)f*UEN z$ueZf3Jj1f5Rp|FF56(F?0|CF2^F%(uo)B;8&h4>g@&jL4N=R)T@uhK1eE=@Z1mz; zEIXOegc6KK9^B1n0xX9cO%@A^r|&~HsCl9W+7a0=kO@5q;kk0LqAA!&X@!~+(UcLW zhyI0|6sqdNF1dLNB~JsVT#mBO0G~V)g7PdFjK76)1t(vM%%CB$5SK=SY~DbV0uB`{ zQA(HEjqRJB&j(=^#=Ck2dqHuM{D(kQQ5y~b)p4$2k>`jyj_Ahk%k6+Z7578l^2lA# zw*&g^gZ^_0I$%JwU@r{xx%a}LE)jB&J&;#p<5vw<xfWdV8WdqI^pRtn{XD&7)`wS+ z3vyW=>x*=QXw>~!e^EhbWL9v{#E4+&HsSxv<q71L2k(GV^0)b3HhDW_QgX=BNHD!( zFGQB^gpjy5WjlC{d-Zg06GO-!zSCfL5XLJYH-JNK1Wj&2R-0jvd^~Dd3yhIl;V8T} zP2OO51qn^&knqCgoM8|er5wb7tbaBSfoMKPFn$Z-L5xp}L~r2%%M+lYtzdYjM{rSo z+{Q0F0^u!?9_2sw2%1fFS45VhvYxX83U(#%eJMV68L0Aa(MqlWuY48c$yY-^^mxNC zwl0>hGkLRVET4x~lp2C5CcLLbRatrl@*FXEzEbd9BAE3M?;@g!i_wF5B{`$IO5X!E z8GVJk53=PB$dT`bA@Y3?l^-xMSb|Zh&R_{EFc`Fh)n>!k$eNBU7Gl7f7!O1-;49pf zV5$G?77s*?c%Xor1r;<@6m+Qws)umFP>v_Tjebg%P+DbIRGg9Q(k`l!q6E<tJHml& zu;K!z;s#AggMg9_{S}`{-G>+~3=u3)Y8V@C_#;)N0FeHWyAdhG9GW1eGX5vT9Px|A z9F{2N8WeLa=7^z~>rl*k6te-vZ2F~QZe}CdD8bzon88ZT9J<BfTOdC=r(l06cbVZG zkW+yEvcwVzSUO;Y9@&%M{J<1lbEl)6i|qXdg35U?K-mm~FkPTrWUv<mCmW4wMGm@% z6$@1>Vq-80XQJ7Y4?`Lc@BMmsKlbNyII=emZ$=JpK@N8!hrdS-Z$S=s{SO@4**I1r zI9x1LC0&F(SdT%pwNYI>c&L&TG->5Yuq#iSbSIsS7u3?(1fy#wBAsz;q9CyfFUbic zLP<z`h$KEj5}%lKqbCVUl^RX5LF_0&Y^jjP8~2!`m?+Tb1Zoy+4lOD;EOwJXUW1yK zO)`9mg54s<iA)wms)R({h=h_5DMBJck;rh9NIi*As!OCexhV#@a?!BbkO+!WoM6wE zwWiW-7{lnL+t^f5x{a0b(j7Fpub0U*ER!^I9g5(Lq8Op;NsOo%vGHMBB8G3c|3;nd zc10?-;JG&v)htR)2aGAU>?D7WXO##;u|>072Ug8O8jS(W?>b+`w1G_tq63zbz-2iZ zJeE@-%W@hFvYY`!EN8<w%Q-O7axToaoCixR=fg_N1#q0@BB-)l3~Mcy7_kg;Zb-V$ zkaV4plv3sBKx7z#A?kD<>5PNnYzC$*9AyohE~cSJIfxO&Bt8z|bx>DmrlCqEFN&y- zO+<ZHLg(=-;YD>`sGxZLeTz?!buQ~t7wkA%<ca3yutupY4TWzqSAr$9D<phHZUld$ zax~sjZb5W~zj#kdMD}^qx))IEUP5&L2I-bpAkTt9zvVR;Y<UBQS>A*ZmbYNM<!zW_ zc?afWdWq#dBlsT;eT~>~nIYFQ1LI{vSMy*jn`H$5KCs!C<skT(gCd$7J)oIw_?Z;~ zOwHs3;_d#pM6)>vs^t*aEuG!ERdKV?dODlgKjmx^Nm%=VYV8kp>%gDyY-Sr8a*Pnl zZ}tOmsm3IdoCG%OWN=ugnxyg@B>hP|PDN4|p!9SB*4Poc0OJ0qyjTy$FGI#JN5-%C z1zv2<k%3i`Nb?S)xf^NT)eS7!0BdRwu;v(oeT1Np_O3M9TQ^g?31v2)Pb72fZg-{O zYq39|guB_CCA@2sj6Kf}OeR;1-6gQTg6zJE?7j{`>l-k{`gbU_z6C?A@4#5=KcK|= zPncwVAC9*E3l?H}x%DHX13Cf1+}sG%m4<*Tjhb6&0yT|{EZ5>7Z{^o5Y%ZH8q^=bB zW(&=iMN58dk5NUAuqt6#C4*hHm=Ml3YBk$rWLA*vE<VsW*9i7k3u*yV&xE(LsmS#K zo0<m>wV#Pxz#tbeX}=1Jjp_8}8}uF)KD4BZo?bD+iH2%KTy-M?z<p&%uQK5!KQb}I zdqHX`GISI&G#R|=6v$DhLVvXkhN;tF1g6KTGYpRy#uzK^5lf6JDiKxW#bEVlUPU>O z#}=4|Lo7CS7<`PeOueoa8YA3WMO<CfRaab!2|b47bqS<|G3kETmj`t**5DGX!DW!H zE{8021q@JE!XQi+sK*($>N5?-7YV@AyA8&>usd=HU4%XoznPZyi6~(m%8XdSZ}e#w z2ZpiZb*HLhA5v;cqx%VWrKZ>-7h5%JXa}r_XjaaDu__naG@GXEfJsr!HcC^s!*I=t z?O8rvwd{btn%V&qwm<;yDwU(~Ii-?6xgG49br=5MWJA#(+GNG!EheigN7zBd@IgHV zg+C32KOKVV8PG>P69%ehL6LekR^cX?qMie@)pMazJr7#d&9Fhe5H{lV(=pFE>SY|H zV^GBLP{x)ZAT}5a)7etC47D&Hj^)5nu<;u)!+<HaoUK53vY?r*<gf;zo*l!hy${r} zW4WRXgw^agBiQH<HV^B>N3hepN@bOd{s9(_%26Wy02W<87O^U$6_bQ@8Muqa3_Dp9 zJD@btx^^KFw<8jFn61m;Ilz`11Ci)1Jq#;(HLDht+#)LZ-0qbe*U5>|{iRsX7y$NG z$5^M6<5fID)GDv!?WDk(m2@DdXDzGBE~Q%?o0NPmWT0fvqGZpZWG`SHzldh~64vqG zP|;t8LiH6GqrM80)Yo99`Z^q~z5&bBzrzakZD>>9!Mgq@oQU^N!@Qf+kBqu5G3t7Z zQP+b_b$zaZ+qp(vH?bOF;`OXn)b(0k>k16$R@Vc-PIc{1R@Z%k%&6?uhHG0SDmyLi zMmylB4w#fs#Wp9pMHg6Y9#a*k8LXyZ6~`SY9|ofuj(0<E6y4A<T{W!m8cx|Cot(Ts z$~*P8D0plIkZvo20k)w~Xd4DYF+JKg((pM0uur;1^hw7UJdR;&jXr5QSUl(*Rdc_& z&hR_+znb5f7+1<7?stakekUR{v|mq+wC)5KSI9q+_ett^Y)2yi3lM-skY!s8LE94O zV_OOXZOfs^wgSf5R>Bn9F)-V9EL7T#gI3!r*nrngv8{pAG0!=+I+Nd-{D0_o2KMH6 z4v;2Fx-!<qqck=Wi=)Zy_8y)`M_!*aT^0%JKr2yAF$WpgEmSH)1hAq590?0#v5qWT zP{%bZ<-d+%sh!}^EL-)c3UU5}3FlH&ZLpn<IB!Cn&qbVn1G%>IV6bg7;(I<!w_N}W zY!^b6?INhQT>@)tm%@76Wzc~6T5VTyd}p8_3os~+A*xoi@N$l?f=G{M>#%cZK@YjY zh`rj4SfpK;QWhL1<~az<9I|WPN*;tD?=coIblq0H$y^`zrszF%YmQQ<I$|2K<x}p_ z{afQUK1JHzBUIAu>n;rQ_JG574`kT(f@bT09NWDRvfXd8{HUQAQC80tBR=fO99BJe zTF)8;Ps;^Q8RlS(HzZRNy$lAjHVkBKubXIP7_>52qq!lmQA5&XG$akeYR`<5QU0em zK{wICq7jjIaRW})hRD0*Zf%H?(1zH)MWMb!p?(0b?EnJ$BLr**(Pj@pzU?rKuyw)& z<a?T(!5q5;i|h(4v0I_ZuEOzlC+brtY{a~$+tUrZ9c{EBBMiIkXR_Nf4am+EcI!3l zRx|82VAyS+#5Tm1%5L*=y4sMY)HSTcYq%_-hV4<X*$cp7FG^9v%{^*(5j$Sg@BrZ* zmUi{5qWdTM%Bc;JY19X6bwpINj3}`NtWT0J&5Z=e;73#4OS*UEjSU6_rJF2RThE4l z<=gcU<!~3PQ?P*m`#fZIKC-$1-1fzgZeI!+_GJ*VFNc2i6)@Po5+e3vVWj;y7-wIF zb+{U)*sHM~m%(iNTEhqQgZ>!fe1-Mm$9g-&QPwBOb&;2{R^BYRVHRuSHI$BZ+Rkez z1M7JMuOZ!^@_KQCmFk6BE~=J;kb$S(1Aw|^u}>nzPB0L&3&du0LrgLQR@4o!90bf5 zLf|d)O<iEUXo853_1Morh|Wcb&O?YcLz?}3@Yyebp#4JVYrhBv*)N76_Df-m{W6$n zzZ@pvy>fe(d+ZB+1T-29H=vneKr_RDX1stV4aNy*d{AtHrZ0J(PH-fH<^YJ!>WRj} zjPr!P=8H8G*Xc_mf|V13G%_~9yojRv0tw!Ev+uz!%iUnLccAF^g4g~4X!Zvo%l;7b zu|JI3@u*3;^NnfUd_G$p@6;+*hsD9Uim&o`T8xO4>0E^bSE0&@CI&+~Yc~3s7!2u5 z>RgLay<qogY2KFEKS7Q^MUKBfj=w~Xze0|`MqU062H3yHN;(Kd*a;i%02u9HFvcOn zc!vTL9ja;2rOc3|Oh^LVCaCS8S{)9TY9X*U8eq4JzIv_!c6@P4@J7DKK@N6fn72ZX zzMwezfz>ep9FBqDb_@p1kq=pphzZ(UgP~mB2WDbjl5DloNZCmS3mXLs{Zg^OlQrFH zT4!SlvN09en1*bWBO5c2jhV>CY!e&(3^w{DW8-9_g13obv{9mhuLY+`)AUN@oP;WG z1iP+zkszLR!-uP&qYfF1A!F;o=cq@f8X@3lf}rDg80ct$sH4qPaia_dN3l~x#f=i9 z24X(d>Xa;L$n2@cnu#lfHb%voNAez#-TJZ!jvgkbPYj_~<#pIy>G%kN<4SNku0qhR zflS911npV~JFbI%j_YB7W1ES;sKH;9oyPrt7(ATQxMC?zhAQf!xZ-q!!^;GRLyYw@ z$YXcb_*n=~Gb+1PuFl^>pgJA~yW>yD<D-!7cpUtWClJFYA=mMAw<$u|m?G5q^J7cZ z#h(piyY(QriM=xn_BILj26T^QBb>b%sgUDyZjO(@<M<dk`V=|(3_1EYBKL)fqX7m- z0}PHl-8u3w0oa)aM>_;Z<GKLji8yA&)HX=xE`~6x`3V4>>7Y8jV0UIfx-%0poPG#6 zvmolsh9YN<iQRDqyW<4A0m$oK!FH_QEJj1bXBqsOra+L<nF%XfoTF2$pF3MjB%j4L ziGuctH7?`h(@h2X0x{B)(lE;0KT;4DLeAo`0>Ti{uV@O@4@(q%5xAU-!Q)&Cna*V> z_Hr2HTmc2nl`zhEoH2Gc2=&A-#_q-&ERJXAh>7O$>|9JqkO_lLOPR3tT#VN8q7c7f z=ZUubalT#%;1(3Z8`X8HK(9!~eOYN3&Gasqy}JNUux~_1%l%NXd>_myvC74&riL}8 zW(Sl<qMAyQV$^#bwfdte%B?K6MG7<<UAJp?em#uA0N%1A0{6mP36^ShO{pwacXsXz zVC+1P0Vf`?(%F0l4+3_~j+WqISU`9w9IxXrk_6|8;B#(7tWHL(PJyuVROstG9R@qk zfI{b)Q0zPlaXTBPI5)v;=Q%Lnc`ht;o(C(Oo1xlyKGZocfc4Ic;AH2;aF+8DILCP@ zT;jY8E_3QD?A9PMv$2Pt$%Eo*j4KFr>J8jtpni*i`Yi(W09?eoSTc6cPG_5WJr%-6 zc0P|piZNuqfL(~nHVzuNva0MN(3eu__b$eJR9_g=`na`G&}>tgqW{MjL}i!oI3&PG zyMI90u}UvxmkGV3DMH2-oJk$9Fj2wpGA-RwjrER~vdeqe2Mx6^N__m;6!!63>@P50 z&=sPf2^4GtpWl(Nq{WFPeQGMnW|U-OR|-qJlwFm4vN*9MmpfsmsC!A2S|DbMu1>|> zlEgCeQ*d{h;O^>F-1R7FdJ67N>%rYMNx4&!lv(o=++CBDyJRJubA;SE=(TjcOlh!i z8Xt=#vD`Cgif|O@3SB-oI*O%Rz!_noFx6O3zk%IjnS28EkS|By5%&?&P0);2Z8yP~ zO)AsW(01@^O0k`L4Qwv<!m_11JOA9}MCbxOK(1zI=Urj!UZ;KzoB=B>(=$DBhB*U0 zu(Pv)e9vB3j-F>Ptmx)<&O)fbbqy#kY~ftjfy;FRcwO5-bM1hBuA3m@+6lv4e}HkW zTVaChHaN<)3#PbkhncQF!UETBSmwGDR=Mti)vmjt&UFveyY|A#uKQrK>mm59>ruGc z^%!h*Jr3JlPryyCCt;84X}I6@3_R|79$s+00I#`THhdFSfKg!|8x{7ks4z-h%hwCI z;4L1PDKHG~W!G^(G!AyN>)8#c1QXzPwvGG{90j+s?cCQ*ft|XqGklYt|98SS4FV^I zCLZQe$vHU;&xEdN2k#_}&FZ7tefa#1hFcne^tnQzTT+r3@mD6lWHbEIjmi9y($g=w z{k{4n2W_t)n!MY@kk0ll?KK*?xPnqgRxTE5s#&meKP94B_Cii@I}~Ut<_>LvKtPFT zR=O-2GR&?N+pt%wS&FTwqxh^+tnyy&etO77%YHT67RX3^GN1&MpJ?pd`JlLmfYluZ zr@H{s+=Y<g9tt7%FzDwV4g=jIAm2R_irk}Mta~&}b{E6Z?lG{)Jr<U_OW-*7c&Ktu zgc^4#taTp+4erTsvU>_#;4U*pfDjV{x$OcuN?ps>tvTUJu0}G1U=we|XpHAf(Z%iu zr}2i;3IpL}b_+g1qrNAyotUy2YNS7TvC+Y%2$x#8Ot5#gZCr!0HM`TD#x)>?Q%uw# zckCw`lp9ky#U3SHc7zQIsg-bw@*MuU5U|sdI>oqRS(M@~=O-6Cuye6eQ_%-9e}uv( zeYyAqjb5BVS2jc`c4*d3R)*fpfzAmZbObEq`BanE*}20bXSNUTEBt(C=WXP3mF-Xy zm9gAnCnp07buyZB`!A=`VWP5YCmf@fyf~^Cy%&Pl{_?W-n##VF3UP(WXdGlT36BLV z0ZVG5`5Zk4xObw_{2q<wR*VvE1Fw4*Xzo8kuKNz?>)s86-FHI7eHRqE_rP%XJ!m+4 zq0Ei-<nDm^?t5Xm`#w0<eLqyXAB1N2erR<+3@5oCfm7X&!Wr(z;B5Efu-W}2T;_fn zu5tevwz>ZTx4NH!J?_84UiY)`ko!4!)crg>;eHWbalZtwyI+QXxL<*Px?h72+^@sO z?l<5I_ut_w_uKG;`yFO=|AVEu-(^1cdo1YwC+p*WpY?Npz(%+~WTV|5vkC4`*ir7! z*cA7_*);d(Y_|J9Y`Oa@7IS~YHTERbz-wSB`#qYjlXNkzyO<KXiz(4QU`n(PtVOgB zxvY{KwgvjKW7!|LIS*j^go28_iKQYIj<7}C#O+YXj^-xrFic!8<6<%FI|lr`rRbzJ zo!uf>-OPhNpWR6raxifKoKlD`aKpdVXga#yMZoxKWrDGKoJn8cxh=`lN|L7sCwbaI zyYGnBf&?ee_<~{9^x_YhG$tp`5q3>)H56#ds17)$*rF-eov~`xg8e(7tw6K#tJqJX zF@Nm;tPE~}ahi%JBQ*=!XQ5_QYV^5+Z4fTJAHvJAC_1g#2givnlC4<TX}W3ccGHTE zMlH7RnSu-Ac?$NM^Ar}Qwv^S7jX;b8#Zv-S&jfILCW6;<6!<-pAlEY)`g*27#4{Df zc*<asXBtfRl*25~3|Qfr36-8%u+}phPW4p4nVz|@$ukeOdgj9oo&~T2pZUFK5$yLY zHkz19)U4aN4o!m9?2lZphG8>tikM`0!SJ>(uscw%Xbj?hwi|U&f?U|cwNu81V>i2# zYitA~mAj|`>e4@+>tfOC9f(bgqm#znNb^)ysjHseeJYj$2SC<myY{fVk%a#KqUp_- zRS7R&d5-U<FZZy$s3RA3yRr|jbdZ*@dr=Sfu=|WTalQFU6Pgs1Bl|m`vWozp%kW%) z^??0D&&B3Badtlu;;GYkvuw<X6NLwQrBIbf0Rte<E~N0s1PTwPrm(+P3ab+-`~@jI zgA|@kpzu&?3J>>6p*oSmr%2&5r0{tHg-23T_*1VGY7!`<IYCKtfi=yOK;hBU6dvo9 zLTw_2C{idu3PlMNR-~rzc&`-JBvP1-6e^Iy+yn|wq^9s>uN2lMQdo}^>XAZY0)?ki zQ+Qf<R(e;ErjZuu6vCkzikGhEql5H{m8PVp*X@J45=)4@DaPP~HEZZ5!0;is7h+2> zf*$b%xG5^Ij@S$9mU931dH|#9^<8Z8wTx*OA)6N?o0oz!?J`JDyBspou7JL2S3)H1 zDj1e_HH=By0;OqNVFq5Cn|8f1oiqSlOne4(kzt05gkY5Vv*>OuVt?V$u@h#pXSj3f z3nSTIS%1+KW`LDPyNBpi;b)mIU7tYO!=4k6e<uK$bHsq;bpwPWF?27~>qz_~0SW#Z zZra0$#3P8rqlm;~h{WTF#FL1`Q;5XVh{T@}iDzIko=;DE)`UWT1BE$;tC(Y;Fvmb) zj)B4y1BC(;3O=xOL*W3VaS)#WH9;ua3k|)2@E-)>D+J*i1mV93!nX**_Xxrd2*Lpb z;YS4F5Q6Xng3y@~gol205MKB-K^WOP2<iPmN$(HV^nu_^9|Y;?gCQe*2=q;lKqNg1 z!_o_2OnMPa#`Edv!%~9q=&ugKi@zoaqkjT~g$TkT1Yrq+uoOX9h9Im!5LO}x#~=vD zA_%Jxgp~+FRZ0*Z`PD&q>DL5d6s39rVH1LI4ubF-1mQdcVKaho0fKNLf^ZRna4~{# zDS~hzf^d0C5LW!^ApGsu1Y!7IXzUGydk}=Z2to&fa4&*zAA;}zg76@MupdEq2tjxR zL3j{Bcr+ylPyOm3y!>l|Fl;Y0^#;NR2*QU5!p8{0CkVo)2*SS+gwGL#FA#(;5rnT0 zgwGL#Z&HHr#IFv*D=DIqD33~-6QUAtIw)Q*SiKpkVrcUo26|NTs)$N51k5XS3i{-4 z#m@;&qI==^BMeUXG74`AayuTmod^zZDY(5;!RIZ5EblbP@y>vJ?<^SZoeg8W6;SG( z3)8&wU>;su>|J0~K-3hZtTg0YX^aW4G%8@Fr~sc4q~v!CQZhkJ5v9DQcaQjLN}BeJ zi7L1kT4*64pVPe;S{W*+xI`0)ZF37bUS0->*4%<8z+PBDc<7n7KwhC9%<)HQ)0!v1 zQ5aAt%g)ZX3I$wxM|Bpm4c;{f*II-t25H`P2vt1<ybaLL+YE!f$HNeBJB;#ffU({a z5U!J8y7y$5<2?o8Iu%xUPlGD&8BpUr%XsN-F!s}4N0?+-j8ebB-sID&G4^-%76&mV zv^ap>=eO~$1fyUy2TV5g`zZfA078eYR_8(RtLz^KArnFDCyD;xyBx^(1dtO1kPW{M zkOQK0Nmst4V7}fROumfJdnJN-6@qyUg1H63ycWT{4#B(u!Q6&m-iTn{gkau`VE!J# z`~%GP-U>&1cfoS+?Qop;k5KE~4Rzi-lK{Hh1ZaZ+XoE3XzsLY|Tn|7SOn_#fPId#- zmk~$wpB&NmMbEuXtibXbh_*8bcEE-%sdfMGC`$bpO8rE)7iIs&KHwaB^(r@UL-#%u z+>pl*)IZ|XKkkisv;$5^r2ZOGe;uj6nTk5$^V8Hnfz9kw_L=ZoR5Y3YvGfKz-@oTX zzJHI;-2oftkml@zljb5jC*KRF=*l4!X9%TQX>DFxiKUP{)bUG=n_S6`N9}p3yY}$r z!uvH!@(p;r-+|`+0m9xN(OVsa5#Gb7EuApU$6%gMg2g@smierPhLl1U`!~u+%6}}E z7I^A&^ji!xn8Ci_GwETN#9k-8Kp!=l>yKifqF?z^OeA<g@f?N#A76Y{W&bIl+0?I$ zT|7QUQWoBH8mndYLdJyP1C}|m{;EK52lS25qKq8AWmsB4c$3WZ3yb+11Mh@`d}R$E zT$985;JAdQ)0YFPF9>#D7(BjQ@cH^crY{e|zP>QT*AGTxdc1ESO!5taDZYGTEk_nM zp7Hmv=7_N`4;;l;CNgv-<Js4I>?;#(<QroxM>bgOo!GIph(RqH&<Y=*7r^c8zs5?J z7NL;+ldTmxm0o?O83Mi@tV<X_A>}JaA*MsRZzg2>W<g(Hg-KQW8$)#c*|$bRYN5qJ zv@^wbM?${?PV1F^4C${!`t?Y^0qHj#IsNYq`X`EDVMsFhPe*STk&Q)3eA}u-E-pYW zE<`RaMlLRa!M@8(T$q<{C2-+KE`B%?E;`_hBjDl=<YG5+aTjv22f4WC$hr8|;9`~F zBG8iypIhpHGZR86-}6ZI1*G~?w|5)k)B+}I`rB7_cHoGKos~%JdnEP)68rIpiG9m{ z6vUnt#$B!xbI}UNpjZY+BlN<;X)r!WL-fII;O6E{C%SRJpUkTHipUHfq-SJ+FGGW@ z3_k=ivY>xPHbgT5FdEb2GeU+XhoFyP$>j#`<;W?84_Ppj9psiAfI>dnEyv#(N@s^@ z_7ja*Y?*V&0CIwu^R^Li9dLHS<VA*g!6?0$8K0-@)Mq@=|D`BtQ({RQf1)I2EPFG} zofarUam*!M)ot$7C`ppybElHby}MmfQk8jDVwro6xJ-*tW&`N&qlV4P^CG*W>3JP+ zE^5ZWf^NGtaYf8{8(bOhfG6W!6Tz@#6$HZq4!Wij6e>weA|*8y*uO~-CsQ_qZIs>x zw#^WtRxGa6x(gAZ{ie=KU_NsUxH89rC$q%Fyk?-K8O&=*n71Dh$<2u*>ycywl5F|~ zBppesU+Sq+ndcvI^*d9QnW$2kw;XYq4#_3TJQ~fD%-fD-hUE@8Ke5m!j91`k3Nl`( z-6+&93Z=XHTh$KwaD@orsE6+)kEVMvpS~Q^iJ`t4=KH5bN-UbP1w5#|7nD#x^MVSw z*or+)%}R@>R87_W9$#!_qXnCqtwvvWsmeRSqS@&rd>z=*(|1BzIDOJhn4CnfsniwQ z`L<^CjJ=XNwhk<98;lG%Xr+qE*I6CUV?j;TY?Z~<O>!r4W!(wsT@38({43ATS5sjW z>FCzm<;z$yKL&s1Cy<@_83Z%`4SAWL!=TJBAe#9fD9Zc_#%6vErJ3Krq|9%jJo7u4 zm-#&$llcQ|$UFe&X8s5lW*&qaG7rJcnTKIlW+&XCF?c|e;VDhw*f;A48rVN;VE?Rv z{j&mly5?cS5%nPKk<xfXS_Iq0GM2G$6<-6TqAHyyrSmz<d2qVq<!eCC#VD2fEDo;H z6T#(Y2f>Ho*dfTI-Q=<uo6IWMEVKZKFOcGM-(sN@#_#$A&*r;GZ<Fho(o@H@fj?Wv z?2=E)5XDcY;6M~FqY7V`Sp0mGU6_l{WI3XE4O3(nexuO!g6B-^dvHaI?k^=z9v0=B zc2w2Q0H=1QNrX&;My5d{Q_yfCl`NyFw18xr%+O+dlGvnBITM*qNB#$(uc8I!SzAGi z(n99_7+s>>*b4S@!_gGJsp&<_eHZV8OCE~uFSZoyr?)pXD|T|Jw<J19zDrSWX<b%> z?=niECO4oCQ%_2>JfM`QQn5`cwoAnhx!9>W>Al+(0abI3+zJ&@%{k%;m_|RGlko+Z z;_p8VkLVYt7dtcuny8B&Q5Nl_#b9V-cu}+MKwKQfHqBXV-{i!Y<Yv6ZjTs5a#V)zn zt+}HZ!;Fh+ZX{DsfIqzOew3mBQvazb_Gq3Pz@@pYny0R^*tN-xr9GkX9V%`09dLQE z%dm78w{$n>;$|d`j}j+Zz#Y*%d?`<C=_U_8|4G1IpxH-o^S4ELDx<R4X+nb@MKq2< z(L9L8+^FV3HmB1MM`L0ErZ~eRBXm)7lE>)6!;=CJ58^=_+_<xIC0|qJK|a&8G|eOU zOpEiGrt^u_Rgy-YDUh~1kcLJ?FKC(-5xa$xP!S)1u(luiXn%qM+M`gUJqaVUr=VE- z3ry6Wfokm~h-t4tz4j_JX|F+x_IEf%dkZen-iGV6cVL_LF8o1zAN|k2phNo*9@jpC zr?rpaubA&8?MrxF`wzUSeFJZ6-@&`u0r*t=5q{7P!a?mYb8DT<=LZ(l4zRv{g%$a& ztkiE~Wqt>n=XbJ|_*><7v-SQoc7or_PV)QMss0RhhTqT5_h+%|{n_kRe}LWY53+mx zx$Gf-ANG{LFMHYFkG<~i&)&j(ANV8eGk=tQ=P!_Ce^j#ji==e_P$|<tOv>`>Z?(UT zAxJxVWr|vz%ncqXfGH3DP2|_yYz9WFl=85%p;Dy26xY(o?&8KP4Tu{rrgY<_R1RNX zM5!zu8IQnDd9A(<o_#I_xu1=(`=yW+Mn7B6I;33gXPekPQXlSTTi9Jv9;O`dHY?|z z*$MBmsoV>@SSftKy|9~o24khZ#2<R<Og{dU#+}A02!)yF5R78ziM`+=Hw+7Ct4~^n zB=yr*Aq~lPsTg~!hv{8tmX&*e_G=2Eb3RD@8pu8fec6y4o<}-Fn^W^^Zob#9)L$9^ zUE2YX-*m_4%tL$Ow+SJWe-0@AxnT919j)8wFSywRF=+0V24c#z2`EyEM>p(r3LSu6 zOHSxv74Y$D?DXibYedAd>%8Tfg-l(4VS@~{R9~!DY~w4hgA^EC3qhq+Uyz*>uolqb zYHnG4)imWoBco+`kI<%^v_N{jxwE<eGEuq{!Q<Zu>Hd=;(|-zN`A>s@|8(f%KLZB( z&xB$Av!KL(Hcatvf?57^V4nY6INJXkSmr+u*7`4iCcNM7zZf?9FM-qjml-Rar(mCn zUP!jVEEvdlJhQ_{ysEEDqZg9n_?;=X1;LcmU%Zb|Ck^6y*aucigF)X?;20^N>)|js znro20t~sAJ7qHS=wS*Tgp5?D9k7VozASJM4WekxbqB4eyedpG9n=;TBfa<SLhBSr0 z@j5X~r=?+W$~Q-IhKeoWiJGNUpH>J}hHLmMLJIk2{Y5TxyELxLcS6SBo<WuWZd9s! zP^tET!`}gJ|9z0*zaQa$0O3a`=YI(L`5%En{y#y!|1l`?KMuqFPeQT(DH!K}8piwo z45j{OV6p$NaE$+1sPaFD)$u&6^FLz@+KofikBXOR*BfxJmxc(q*K^~Pc*-x{GhQZ^ z73v%E@QDQ{vsr8u@e~-NbKeN7IkwyAoU$EqBD8RILNMLE4eY^mhj?*Jzg;tdI{G;i zLv&q>1o>9V>F({|+r&C|f-6K%SvN73_$DZybMb!xs{c!{`@aUS{~HAAztG?REdumC z0`wyc^&f=M{=*1NCrn3t=VVE+FiVCdSr#L7$pSCeNfQ280mx7&k_!3A-Dt>{iVXYp zg4Iq7&ZGl?vEcy5Y#aeEvP1}!h=DRI4GCSD5RqjKH1!s(2J%*Ym{=Oh-S03xw=|qb zXd?`4Uli}CP3>BgJRykI&tDByY9{LXH8&C>SD<JLftg(xGQe~d%KRjAw`p%?z6E#I z6i~9Jf;DRzIJ3$jJ!?8-WX*)EtXYtoH5&$IRlwM+IWReEo-sm#YzX$97+vdoHDy5o zM~qhY4P@<n-e4f)a_khbL72=Zqz<DGAag|da^mmcvM(sS#Y|6#cW|#a-oc$1RJMT{ z()XQ4Wy%bC^Wa8w&7@Po4!CM}C|Fk-x{ZSgbsTfxl^GK0L0wsS3cV?f2cxw<U@5T% zEp?U}a;Dcp2)(1KDU0bxsnjfsH>sWYe`n{vXj~~^-3M3mshco)V0~MN;129I(YFAO zU&?oR_%fh&v+6bIwjiq>A#Om3o4}FP4DPHJ@MX0^Fslv1SsP$T)(J2&>m(SHbuui< zIu(w~Ivr}W&Vc%?GvWBGv*6UMvtd)#Cb$UGS7n_G+q2GtTeCL9o~-lXKKy++>q5i9 zo`~@4&a@WBOCve>^)N~rg((Xh4@0HVYz1oA?P%49coTgqgt+4*_xpsQl}|`HV&M92 zshC&m7`Q|lW5n=Bfy>HYYGoJ;<uQ9F%4ri_B0i7}Z~(&J1Kx1OUkLzujpJE<$48Yf zjTOqh8H=YbL{#iUV2^}4;F{ecl#d9niMZ0`xrK4tGHrODbu-wqZUIl$A5dX$HT6n* zzC4U6E}MkvX%!P(@eL&`oUL(!tu3JMf<H)TBTX})t<mm#?t*a6V!qwpfBBFjX@<cO ze>XhqF|6~)LCty+&FU#Msi)DTp2GV6i@{wQ1`_cdUIuX&ME?c}<ed=2dRZYHj~ir_ zwl+s(58#PiDluMP?;4~E(vaAeM7Q%^^0z6Z@tlmEzA-6E+AahxGJPxp#l4>I>W@}; z6IvZ@Sh=+WuH7A>_rb2(3)dyQ`<nG53Vslk{V*yzhHBXW8QBu#WXmuh+hVGkB7>JA z!3(7(a$oC)zEY|AjaTkD(mA*B-GENxUuFTgLg%(XysUiv9EzAq^;SEm(Vi}vMHfM# zH_0sAeRv|l0-4VeZP~3^!rM{j3P=|IicnglK<4lC=vT-~;LVA`<SFRVD2~F;jxF3g zYB4wbPa=ko=!VG>&;YXYK*{b4)@+P$vj;$W_8`!*2SYGBANpnwfkD|3$j>f-(b<JC zDSH@{XAg&p>=Cdadn6o}JsN7Vi(y^%7--8L3uoZ(x!EPgI_w4!#oM3;hDnpSaj%1j zG#OK5(pMNLUtyqpg*1gnR2rNvP30&DVI%kBw2Y&bBX1EK3)!sp!!!uOvYg(-;Nc6e zNe8pBF3M8r;0*~nn7!a9bg=A~=-{^9Tm>UNbufE9;$4q;HzM9msDsU@gDt3ot*C?T z|FaI3{n|QsgV4c(NS6)@6^#5G9W+!hl0*kDMNBS3On!@)T!A`x73$#CsDsy_4sJmm z+=@DQ9qQoqsDs;42Y-h;xC3?YM%2NZQ3r299o&gJ_<PjBov4Gi{(qr^)1-2tIq}a6 z(UKw>yt3;%)pTu2qpRY5rgi^m-M`Ibn?|}gJ(X5(Pt@vHe?qIL8(Mv*2;YWL3m3dT z9vhbi!(urSUBKRirM?n%`-a(E#kb5h^~(4xR`%Cm%l-x&+22B1_IHq({XGP-f51BY z5e8#FwkZ3MDMlM+a5T(7eVEYgG{jhcw>=X=9BV~vwIJJQ#Sqikk8h9rm|(x8i~TND zPbCQE*oK1O&$VVjc+eTZj#(fCjzBJW1AQPf&=&%MevljJ5B&oJU|?Vn3=a&3v4MP( zKqZDiC5AvHLX853K)Kxna?pOQ_P9hdOke2HmBneq)4xmT-v=gx5|{$kK$%HloTjhz zh`#&`X{Isat4IH?_?ou8up_ZhjK>1YvCx$!)o~eexujXrY%niqlPY>)`GUmKTd?$2 zEWN#VmMeN=`NqUTH)EmaW1$xwDa&&VmY)$*x+TV!btdTZA2RRpb-+#7bLNAi7+cXw z7CF2)q67m9#^*QFXU}d)_<&B}7H|i4LR#Qfbbq%&PGA@G3H%ZI2JVDGfx93Y*aM>i zcN=}(__u<XNqf>DDz0fTP@2olAqVoLd6<&X%rd3<=(gg0UD>UFRL0Bo=jbDsZ0FCF z>{*oTIh5>0l<Xyx>~AR9D=69PDA^k**_$ZY-~Z1fTVP1`nP`BQn|tvSE98kG8nvDn z4UH<rR`>T?z#XOLcjw}r&<}tAV7}nR-&?nUgI~C9G2bHiQEHr`-2!F)N=M*FPy+|S z9_R#54g-G<GMyts-y8*^ITjd^V}%JhDoo9>!7RK#KgVgb-#O^xmU7|JVUn?r@N#4I z&1`9*vHPHgJ@-Sj0aztF2stbrqi8-!FD)`Q0l!&DKD_%_oV-h(D3?Z}D9Y&NrP4O= zoV{a|CEu6+nKmlz%u3s~ZQHhOJF{-3S!vt0Z5x%g{m*Y>`q#5&_4Le}=iXR1Uc|b4 zKPTesIA?!yc?^AnkH+S*vIs)k(lPOU58y;3Aq2hT_@14@1kB{XZk_UG_=|zUzR{m~ z@w-EMX8nbOKHB00_q*l67Fh}!T1FxS$3qsu;%T+GMw(hMH<QY)$*{y`di`GG&7gHb zM)VUG2BJkTa>-w(y_YNs&SSmV%%GW^^*^c2+3v?n0|Hay{!TEjxJGA_KB&RK55W%3 zM54Sx54E$|irLk>#H4(@PZqk9er@GXIl^)3h2t(0kHC*O62pyH1_`FpjaV{<8MoWg z(Q3WAjG#%^dD+p~rX=I|Y*9Sp8gG#*GjR4y6nyWMJF;cQ^ecz##|ZlEjHKaA2kbso zSb~%yXgGCP0-w@%oJkEIHa{b=4>#;y<SJai-LE#~K#;YI#!s-a?hX2g0OrOH;*9~) z4jI^q6W9qExEb8z_Kw(7^`6$V<yX+t717fb($f{w(-qXy71h%f_HSQa_<_7*daoCQ zb}f*@+7&*G?MprbWbg&Z5Q!4Pe~tDZZ*t8N;06&2jt-b$lqm*}ZkWixsKkG~H2RCv z`#?Y%IfOf!F%ZlJ3y*mA1Q?(~7`FY?xaVK^bmXspyyECvLsSbu&IDcB;c<XG5;nWG zpn#(b$W6t^(|P|ssqByD8zrAyIrD0O3>#6x<jBFzhzaaHe3OvB3?j7MGl5n2oPkq@ zffLx5#J0RePi5zg7bQn<3gMq_QNHQ`gKMb~L_KgM8AMn+MvsRK4?IGT$@8Id92z+@ zv!>G&#<#bv)Xm_Dt=I`8dd?Qav<m^VD^as2!g|Da`iUyGpxkG2hpZb!&-8BOG48-# z4CR5fdnEaf{u~WGA3-e9v4M!-*OFP2L0^lgIy|w&i(h52NeTC)I*JalD%49A)hOV1 z)5!LWNtLN%d?r-uwk*4LG;h?ka+@vWm66;1iGs_KF6t-cONEUR-E@?`oZue{L)EhU zW-g0gG+rf#x_87VipD1>4vz*Up5<K!-1eRkTdh5?wu4fH+mJr&@S7N7CQ{p@^P59g zo;LW{&{7tt8p6gsSlF<EGaOK1WZ#$vk%$l}LziQURNQov)6(?hSgErCi%XAM{U@Mf z@=EgtOg<38&ll}MmY#$CS&z=#fIGo$P`UZTJy^a+!LLpSb#^vSdD;f3Rh<|cI@Z#H zrTVvJ1De)Y`pWy^qgHMML|=%zOAwjOgc?82g@{3R!<)(-m_|Xbl1-MI3wDyn=#Ma+ zk}lw`fF6-H#=+(ICo;Iokfx#)a4DY;OjzXgqPqQo^g_tNrqWY{o3#PH&owYxz_`03 ze0tN+;*(+}w5GM&aVNXXqRh4H1bi90ke$z#;86K%L1ne@#8TK??A}%3UU06IH9T4k z=<AR=zM@_iH#OfD@KYpt`(|u{3={l>ek=@ckir*qt{)uQr6bLWBvg2I5MM5T|IUnl z&d+;wOdK!tq)Sf<*iIm3VR|9iWBVGqd!~j^y-;SM>R$L<b{XDSNO&j$madlfoaa3! zEStpi7|UNQHJZF`>VE}~!}-W;p^P?h|CAWg-N@-0?^%WZiVMuR0=FvN=&crg$kmqi zU76D<r8n$J!1l!wj;J<*(ipvU`IQ1uq4*JgHB(5>)9~oi%y>`iAq1)T#Z|ix&G3^( zn5Ckpqy}87pK1bX-N11LVK@X&0mBWedWmou0xEXy#)z&&F?~odqEDqX^vO<4Fmhq6 zvJN#&($)vl2?B19%{umK>fBIouFtK%_76D?Wqboe8~3Zp`(VIZY?fJmZnk$pShN5% zBDl2&2S*=;t_SLKUp^tV4jkuhE!o=`bC+-$d6)1BXnaHOu_NHA<~U<QiX4-74P!9o z-RUz@X7s*L&BkIsYoIr`L?TqQ9cR(MX_knd+ulbX-P12z71w_Xd5zSSb<{_Lz5|nH zmoz6VMNrFw)1!a5XXm<>fz1auX88WV0ZnbvN&~x!F|ujnIqJ;m25lLR0z<ZGi)URW zY1UxSKpG-=at?Yfvdsti1yYOm4g|(5{#@OTgzyl0Y+&S5N#C<}<vq50QB&y3o)22i zG)RW~8ZME14xA3A^>aKrsmfUzlIN$}t|tgDAes-%5Yeu%&ys*4M4k#A)*%s30UaQ2 zQTAC0l+lOr_fmj&=KQ8SJvO<obP!jTyR)ublN6Yaw!f7?zByQ1nPr^q^Mq$|E%dB) z2E&mTanYE$Y#4k8S|93UH+m+KPK>n`Z1Di*nBaSX<!*V-PaoD8D0@NW6&TZ9YeS?h zZKN#(>;CRwjb}3pxNVThUF}>}ADm3=E%1!~=KjN7{=T?tJO^nH_IKdvE2yhL?>={7 z$iJ%umjT@&1Oev#Z?UYchP6c#Fc?Dqmc;tK^;lt2<Tt9kI0j)ZbsFP$AU=@WcTFdX zC#YSZ3S2xyS!2yP;{hLYmKz&&JA5ZDc6OXK@?60g+SIt@S)-N;ABf>DkY@wos<p1% zlO*Pkg9?*_3_qJ@ekKoTMEEm@G_}eL<8exJX|MD&=H+5Vav4RRV_ccK^#r3FAO3c! z;Hjl;;4yM{u;xjtSqcdU-t`aSedk;1gDhDk2;zTd4C(tL@aNiG1N2Kw_6x*%ms+`> zRmrDwEn4=IjCjK(V31BxnqE2DLvBN(5Nb@?I(r*Mt&E-d&6App&uze8O8C8=#PCDg zVK?I^vr?XjIb>o~%{PtRr$;gGm><2WbOovi5_Lht6<@uL9_`b#0B6_Z)j~A3s_QX8 zbjjup^+rHbM0t>QvMWozi~{E3wW##Icmb6%NyQAwSL4p<yK%>)AUPKR5(MVe1N*BX zS>qXXkrbHJ<aO)Xat88eGvbQVT~7)(3`lD}A-y{s+z1|Qu+y+0Ni!IX6M5hD_u3ql zOA?ByEVzBA;-2S?QU=myT(iG&;V-SQ2A-EfB?H^6t<pJ^?v$CC?Ql~Qy1++ARUsFx z!+raypVD?{JSpwidSjJg>Wtgkt*%3Q*7-gCY&lno2HYZr&M#bpM>D;jVZ0%YPD~Za zQ^FrbX<bhRlYQEq<XO|5szBMvbU+{F3I4z74zzetnj|oG>tP@qQlv4A$3S3rk!x9q zA#esExw`(wrmu%>9>NXLV3)SW`l}nGRa$j`eJL{^=1;55)tEk#s5t;VMBa<}C@Sbh zl6uuR@)Z_ug;b%KBf45DmR1oD!cZx+6&bLuvwRSb9<1{icI1S;aN0s{0wab$yYs&& zvHKSc1f`pm&LmbDxscBLSM2^!>r%qnMqUydH>OFgncmO7g5{|Nr+M=|#JiU0k>dAP zx}P+*58=*B=dFs23s4;jN1enkBeXwXIPbbun3T<AH^-z`zeSr#S9W&%WFfyjg3-8X z9#ZF%cb?<2o^&OaiMP0HLFR4>MyziEz;>vy*puHED~A$TMIAdKS=RaCC@0-Lmz^Oj z7$&)J<Rojf{=5TCc0e)|@BZuNzz-)H+x3I>m1yBuy62BKrPaMK1ILpgX8IdN%!Dr- z*&!doywe|nNndQWzn@rflONP7M||OHZ#)Z!T|j5f`XNIbDF(uq)DBjc<u#N~vMm%( zR}QY1+76(fTZwOU=Tp9jkB6VI_@f^{pXqOeRuAMQvw!;7TmSUOx9a!gZd9jbzQH>m z`c2n4`5Oc~`J3cBBi0Xkbk)UAs68lZxDvo>zkNxyKkk&2F@Lt3yVuMA{$;Xn2bI|l zJL2MwqPLp_41*mlDXT;Y0G1Bs0YhP6XmD-NSleTvRmSWIN+nY85rGAzN(Y0AC@}Fr zMHNLY|H!BPZZ2{HXNzaqd;d1Y>%B^nff|lAlI{I;?&%wU_u941eo$Ad^BQv{)qRuN z0F)YO;qhZtib!WgV%_wwb~QluP2E&JrrtscdAEO9gPe`ZdduH1=~fvEvr)@wgChhq zYQA&gkK|}>A}MF)S^<f9h+@9UNFYG0@HZhjzIe)SLX7O5BdIW^8vL&x8MdRIK!ow` zJ+5$UF_sVzGhYG`@Bkl4=sHmeEWAU#e9t|uMT3c-hPPO0%R3BVHvmL!RB!K(h-L-7 zn}V5|!XeDEWVHJ*9+$*o#kqzx?%XP`C>-)up{j{u31Ra~#8#SCYa6K6J+4NE0~qeC z!B}abs<2ScW1G|igw{I;r*$_Ep-VHk-Qu{48s_|#+FbbJemQkVV_&tA&H}$(68n*i zaOMYFj`lb{oJaRR1qT)!hZ<le(6@(RaLFi)GIByX$$1iTLo}S=)&~oTsy7h(Pg=RQ zKeSObGezbqgXFuuE7mJT3o8r@k$>j7G0buoTH=-LDg=`~(v|e!IRww91A<vJ`C_y8 zv88aGS82;6-<7D#Q0~uwS>iI3_A~e(^(&b47G?4^vC5@N+^bBdL=lp`%mH3zAINUd zb7)IX7gHqHE;Gsn>iN;pLHN9plmns<-UQ@F+(+at6X}x$;y!|3b}?j;PqDUrGdb)? z_b1f9ebnRx^;!LoG6zvGX=i+JAtYpVwSzC+)Jw%bOb686aBoP<<LB&s2OG-9;k|=C ziFC~-QT&9H94OQHbMM4eKrvw#aqh{z%)S)NpTc>?-H9helO2YTn?fG2#;OnM4&{;I zNHTsJ_XafjEdOc$u>%5{_(JU7ZXXx?_mgufXS%V%D~|fOIy=FzvFLS(%bdXWdmo5M zGEKjLCr0fIT*$#D#V@po(dvAWtzae1NG8ottU7GgTbz=lC!@;DNZZ?t6-x76Pt9PA zL*EtQEB#!aN+-Iwk+)gG?oe1Ke7@xEp=}ddzQQB_G4L>DIu;No08(;vtdLjSSmBVv z%P&T$rSB?DCu8iKegY!SVO?)3tvaTw6RBkdgmF@XoP709k-ambO=r<c8oYw|Dh2;j z24Nd@<`=6NlxYe))#x;%@bppY8l7{M^a2!7sqz;G7{*%Z!#6nSk4vg9qt1NYu^$hx z-HwQ2B`N`FoRoY+WVC#Q`-+>%Ap1z0$*Hv>?^2eH$i~?#l?_^0mTl&P26I--F)*_Q zY7pWMf;{FEg=(%lnI73ndd3{dkr*wsVw{y#8LDp@J6++K?`IAgR^`z}c$K{k_{v%| zW9e70F=Ul$@2yc2g<0fY<_l`9iT=l`Eema2=`z=>*;4P}7YYN>d!&`f+&v`+J&#+b z3;-Xl;$?h$EQyAl)v}f>nLOvCj>^z9BsnMd{HWyL_)RmWjId^?r76b2U1X>jwd5Ga zKfSS@IVOH=+LUGVVr0@GO&ILh{aI_xQWI*YXKiX{s!iz*5VsSI+mPD$K$U3?PTZH1 z`PCqvNN*7313iC;uQJ-1O8aD3wGm%<Yg+NEdJpLZ8$ZEz-~#dnWi`(A7ISI-NnYu* z_z>EgwG||Iuo}(j%0>p=8?}3Kkfb){##J#4+mNt$t|ih}>$|hko2$a%#aLcYJc(LV z%3|vT7!7*0!dRq|RwPxT%3A1R6sT1^3*J-oGU}5?J1PBSq%NjaeXz#|L<KiDKiH}v zqg=s+#E=yVty{<RrQ_lB)rB7o`Pa<8hTL!xd6kOep{R9RP^KkJ+mgK?->lHu7L^5a zxJS|SP5K~a(%|%Gq?(72HG1SpYluBE3?8Lpt^E)EEW>m^j|rgLNf|iydWJsSRHq+| zTXw@9n+S5IW$@*$LwmQ+#W!q^=6gG|1N6Sdf1V4?aMR2{R?Qg0(ufsJ;`$_{;+fkA z>CuR=x>a!N_EY4J$^A;zaW8`ht{!t@IO`F|8my5CPJ#zIVYIfsFU)a;?1m2yrSsfO zG83D?*Q&z7K`W?SL-MZ`(eu8@HLJ)q0dlXujBzX5p-IDpoo1RHRxwRpd_MTpEGp~_ z$xG*6>;Z7+4dr6rTOX~jz#PW|(n8K=Dq4MFN=CkTo8~qvp%Au0pa$3`XstB{&nnrQ zd%N`lr7EHQ=<W0KC`jF?=TL5-O=8sgxS}-ePiAm$B$vw>;~|e(+Uo}fU{?LmbsnJV z7cNFkSf>fKgEZTgNuCIhyB}fc;YjT3j6*y@(0>&Z)9rKCc*3ynIIJcS7Ba}M84lm# zJdxwmi)+?+j57jmUrrd&ES=y=JGA1^1j>h3*-}^0*C~n>*DntZD(l3Jlv4;SB{J8q zL2ruq;9k2ps`hejXTDJV>@oVqR~a}f#@ZBYTG2`J6|jF~o*VI9d~W6b#_BDnDye9P z)wF?0oDd8dw0bShUYX{8Xpc#}dcLpSM<@9b^8fusPBdov`(0k*_DksZm-_d&2<<OF z>EGRQ?_wmqVP7()*A?{v2Q=(eifVfe#{TMzc8cUf=y;og2{czmaaKd7%KJj;znF&- z+l&pHv$P#|2$X$U7CN@>_=NGCGrqn_5MoNt;03Fpkw`mn-!Flr)J1e22UkVF7VrVh zq_F4xui#BObTdw)rE;hBu^oL~N3CVkhG>;(ubCnIa)I#<Bx~1t@zF&R9XLJ%@Hks0 zS@^06IZX0J)bnXo6W;c96Rvv;U&WIz^r9JeotDP)q{+!_fR~YIo`Clep^*`yyvc9U zX)r~;i)cX=j_p!$uB<cmTIOX6Tk&h&<Y4xGOKrTPP1EpAL(ybfm&JVfL~;hrJhdP7 zl#-^-Umo~i70fFU^s_aM4zw$FV&%g1Ye8zdhnC^^Ou4iVm_bhXYHf-wsm|f)s-L37 zTM+sQID0-?1U>E|$U<(hc4FC!A>Z)bY(UqmibNYv`zw#5U`KH|xe?=SszY?N-3=cu ze)g_~SJ%oQTkmV-yx+LI-c6vdt4=X(xa+&n)6ci4ER8t8&$RXD`X^r3gY9c^zW#ub z#YC~90UFd4n+nI%nr(##GWxZ@XI`*gdV)i%M}%9GSAvV^cp(!Ogmw8$g-sysO(2e? z<YY<DGnb|re~WJQI%7(sr_^XF8#-X!`!W=OQlSswFzbD^+x_QlDG~+!U6|fyDKUS1 zP(g?m8)~?48O?GtQfY;i&bBL{%f@o5*|E3jAkO|oE%%nR_B}lkNKJ0{)_5S|G`ncS zNa7u)Sw%W5uJ|lLU@X%?Y1GmkKK*2vTZ?tK^r}k?dm+UB>$QQe8@6}slqiCufUO(I zok#8H?xHFsPj!*4a=P1{)wHnb)dx%!t|ae7IB=ywH6R|hzq5`atb?H&$6g%z^>4h3 ze{B)}-<!vaJ5K-}(SU$Lzli``|5Nk$f5;Z}-{4?7XPa+$Fukaqi=~UFpp%oKr}KXR zFILPAP*s;9uhX0%Zpi}@Yl-HdWksW+f-C|kD1MLx{G_n^O{%$Z9<~``mhTS81EGR} zBGLdB73m3DA${EPzWS)`aGu&&%^GIEN_hgE$lSJNcE6lx%_#od>YT2txSR@YUHC0m zE>2rwPnRWUexP6ted}CGkVR<z;cOY;ul7sY{MFq2a8BUMMu9Ht;!jqBbnr(#VJpi5 zKlMbR;pb{=D~k>n{a7wi4j@M{=T0DB&{*IocqnKnkPb)}3LCKv3KbYFSW2KUhr$A+ z1WpAZDv&IQ4q{LcEeDJOx(rMfq)@<80j&g^1&alo1&sxs1<wWgSZT&IXIxM{z%0Nl z$Slw-_;0}9pud5CgV6)fgU|!fgOdZQz-YmB!L=Z?5VU}`pxdxr;E%OtsAjBYuxDIz z&IH*5mV)fSHo>$YwGh{U+OQgs8lYWZEtrqhX3%HUW^8lT1>FNK!8XC$a2ntn@ESl} z5Rdg{<Ys(xbaUPW+XWE=9s?eO9s}{gc)`3d@1ZRCj}>QtXN+@(1?2;>!Fa*Fu<zlH zHD?4B;Ey?H?s6~$=!5h?I^n#)@2QSiXU=li1?+>iKsw>QAn)mpd1u~o5CsT=_&|K& zUcv4ukC|tVa_9y0gStR`;a?%{X^**Qo^l8T_=EgFKHy%#@2QX3XRdPi1-^hkpkHC{ z*^dcoz?*u(%xXZZK&xP<fI)Q-GhwR`?SSl{_`o)xHZV89Hc-!l5GM=KeK4OLu90?# zd&L7Y0^=drAqhb3fbF2|!0q7eK<!}dAng#RK;41d!Q4UIA>4rpVEGVycv`5R!5r8f z+#L`d<gX)l5_-sky#wWe|G-?rUxM<%Z(#UvJ;OQhwGg!MdjPcn`H(%+Tnk+Pyk6aL z?g{P{?h)<{-7(y8?(Odt-9g#`>?rQs_2l;&_Z$Te2Mq_(1L;HIBX&XI0%HVA_Z03> zc!0FP=^(@fk_XX44ELh#fN?-qfysju_gFfhwP5pL@qqK7@xb%o`9MD_U7PNV_o@e& z2bc$$2bu>T1snw(1s(-s1YiVV1Y!iI1XP33gX@FqLFggq0qa3`Vf(;8Yh6=aTU}#c zyY8IzvIi^&*@JC^=|SotZUJ>+bs%*>`@niIKdW7%U#nf)?yUE^2V8+|gLmO{z<1zv zfchXl>s`xT`|jxOy!E#CA_hDKJOw=k5`gi8`C-08dGJ3gUISkn?+o|K2mAr!2lvB% zhkMq%7Ic7r=Dfb!!RVn6(g*2=^8<gUdS<;o+hOmq584LlhWCSfr+enTe%nFp`L5f5 z_``jIy;D9jUmxwz_vi<8gZRULLcG&Hb6-F05cKc|`Gb7HeS*JJKeJz7?eO<}0e?Y% z!oIUV6L6s8;vn=Iav)@KIh^*527+=t>>Tu!A{GN@hB+Vv&O^x=bI9(ngzoooqD~n) zAcQ-EWfJe=f)`_D=I^qEJHut7J81P;f)}%9vN^2vSwa@`X7X_0?YM-@L(7?S=<eXc z9&vCC_n*KVfpKi^xP;Gx%E@z(_i;i`jXHSsa)M8lI(YS;fF7}M`0i#R9KmtCIK1|r zAesYZf^eAkal%dsa0KsU!XM#s1n<HHGNZ~7W*Rz7g)-yHA!Q;ti1lHCAMtSH@5YQe zPE9+0@4nv`6b<e4%JLX{w%dn|dObp<uBj9rj>F?&Wa6A-#g|NUr7e>hL^kcTEw^m? zJCZB7*$)|q$<%TLy$>rEPl3smV<1qJK>Vfq%XU6T-)}bOGc7&**|4d@@3W>aPsUL= zR){z|i=WEh=L@MHGX9F6!QZ245Aa1d(p0)mo*be2-7WTV#WK;B^CO{9aoviABRK-0 zvWg<ENK7PZKbr+FlO}RNTvUlM5}r%-u(rWAi-jYN>I}OyCNWXGJ(+}>>UU(rltO%! z>TId1Zn+XbgbTkk%8gb+<$J5=VX+dx($anl;cBJy5xNpbS|+Zj%%<FVc#Z0vpz=KR z$^Mt^V&n)=Q>chb6sN6*3L0grheW}g4(Ds)z+~(ZI%&Bw=`6GHo@}4GM@P(TK-)|$ zd<k0P<0BD#rsEVid`T>Ug0{1bdECV$<1{XJs<F89xk+5sgN3$TW%KOwwwd<*2$#Lm zE%M;W*cNhSb7f|ShKrS?PCvYo2C}S*rAs}k8d*6?A-3K9C0lg?S5g!i%hrLc!WIk4 z22to>>F6LJaVVp(*rj3M>O`$nOLrHsP83p7O>W+zTx3+`1T5Arfp8xnxhM&5pW+r- zusw>0TrmD&<}URsD%sK@<z5kq@+Q1XJ4#A+maVmF%)_;<uY2mkOLsA8lXcB74<CDz zI9Ob&tUM2Ui`r1Mg5*$tT&`3bOH!1jP5!kqA}KjNdYv>$I<JuN3;&88&wbvaxpf#O z7XMdS=>+d3Ae*d!h;-A-s)HTnZMlU$!u$CUQ3^Lh1yA;D<jq_nQ$IOMW@&tjUwMDR z_WTcN|6$625-Il7(q5TH#{zve@p7_#_T*=))@lX88ozvhkjDh#k@Wg!TKh(~z+TY# z3@qyuLZ?JJhDn$njW8ORFfCv#xGuJOfn(jHlm$Q0(kF=pAC*OqY`Vo@Kma~jdOUYk zTZ_=qu<0lX+uXZL%ZqN}-X|8_JVT$F7!88B^7oi(ZIp#p|Dx9F8&u&qs~+*q$hpR{ zWhUO4mn9z)^Ah~r(@4%$qmrjg(`~Gh=Ri;2t}ttdWZ(V0!Q-;zg@jwl1Gc%g{dI~x z!@{IiW@lwAlM4x^SAyCU&#^X341}=lk~;5Oj(rkGI-Xbb&}we8)SZRd@w!Qg1;fHc zn?Zf-)eOh_v)l)SDfZboF6=*2c}uRX|5xNOxk);6;;}<`-)8z%h@6>syL@o<@2ePj zFyKCxE><=!ZBAE<`>o(ArG<-o#V)o!_{3T_3(F?nMGw!VivFR&=FqpTY%GEDgX+Rx zfl5AM488>N;r_T5O$Y^9@`Davr;6UFqfV!r53;dFzhNw1O=?#Y5Cy}(aLD@;o4s)B zwkkzkAuVn&fonxjcl!u3R{bQyBxtb>X#9J(<m(ivtV<SZHcDy5egD~EGK4r)l=R1n z_L|(*FDqVs>LcNgJDfuw7ny1M-`121_GSLGX9W(a`Yn1@CLXPRXoyyqlu=1(-fI-5 z#6*7a83ieTT<$hesqmz?O`GJLZfKSpIO(@ubl)rLJX60v>n@Y#e^r=;9UacN3u<VX zi`#xnF*|!z>j<*AfVU+ULB?L)VN?>F-x9d~uriAPcW%>$p`V&K0c9$_InTTVoRnT) zc~xhUzu);f@hx_jLmq1VUgfMzBMeQ_(qLAeFW@g`tuJ_Lm?)(yOJ9BUh5p-O7PnA& zd(>i9b+47x*`MyIq;(>1J?R52B~v3H{mxmXSyHXTFwDBuHu+%B$17W}KMCV2+j07; zwy0AcYn;#-z@M7?7Qc7uv4QBStcV{wY@Ebrvy3M>_J;jd%U5W)s-a(A&`fx@pXN;R z=w!Zj<q+rBSuA2ao4CD;>sxJv24L#$#r@zb&O=hx=P%u=s$W1obB-U#M|p4GMf^*f z0O4rwd>lUhP&pm)nq9=SD+Mjhyt{~;Y%a8EpJ-w={nS2%DAau>bL^f4{ZYl7yY2de zZicrn#DvPo%&nKEKCSdtSQmP>w6-DA73W7~Nk#hK;X6_}5ALl90{R)zZ<OS_0zq4| zEbQK3n~JetPGmb%63s*ZVOw<hW3hcNjDLJmiQL-_l`rsbWuo3Bog@2XDPvN<j-~s* z{N3Q`jK-1By(4D@PZ4CS^lRthW(V4bWxvhDnvP-OQtg_oRBZFsNuo$6&^Cxu4rq5( z8j2CU?-7hX@n|y7uFNKX!D1YX4{GE4>BByNnkVlIZQ6>Ht7aT_Ipm`b$?lRtPjKn5 zjQ=S#;!nR2_e+U(8UCh+PTe)94;CHz)Zek}vc8IqK&-^8r{Nx7ne(g^pkR0Wh<<RJ z`>aal*T`!|p^qGTcdZxs<3fc)KX=4Rn9Xw6W>PCa1*ZLuF)%UxyYdsquunDmU}|sl z1iNw;Pp)mwd-FY7J6|)0L{HadPxceCSGyU)Wm^e5TIKliJb<pa&!F2&0L7STWf6Dg zGFpo0udt^8yTXZ0hjf)~jO42PSqH?)`w7mwt-*#5wAnE%s%*hzxMfoqnqbR}K69<i z3-TnQGBV1?wN&fHiLy+C3OV5+eF>KO2|2eNQD>+~X*cwZk?bYfss^(g&&5~j^&abM zKwWJY|H+<A#S;?!<bZXfAKMZ}83)c;W|G+0Sl;JdW^Mx8PcZj0`U;D(zKTe!HpQr7 z;xs;&;>5AOiuI3=+|Qc2b%`Cc(Wv^n``E>l;mdsca3_6V_WOolJ7emE+a6nwcr%?^ z_utgy&{qZ7nI7Fw7Z6TNz1)@*<do~DFJCX~ef}R2bTrw=A2|<IH3QO7TlVk5+-}(K zS94ox)>eYFwBuuq>7((!R~2dRQ_IHxPj|?bnYu%JsI9MIPet|dcFrq};yd5u&Pi@U zuC2H3DkJ98(~s?*Y5{Tu_A8C)_RPy7M;zK4I;VC~Zd$()r^`no?ge4%YQK!N)8$pm z#md4@p=!VNwbP^X1_kL4G`$bE#>ML9`LU1fhYLr&kH_z$?s=>4pGwsEtD9co-L=9O zl>C3IcMID-;9N9dFDv<%sdpROK4hFXq%SG?7pZqE+dgb&E#)>Y=pQUz>1coSyJ>}g zpO&P){dQt-N?(r~-ML?z^|Z)oz{!#-Z@uNY4RMxAH`(rd^mjAsQgkbAKg;nckJH5d z^QfP0j@UYWvV)J-I}6;qb8%(MfVJMfY0dK}>q54zO3TytNUQQ#glm)tD^zX?9Ht!a z;daV~OH`fU!}Rd4M%+jE;v7g8HjVBRDYdxWknZMlUgy#`P-9B(Y=m*+z9f%PZr)6E z>kA?d-QrRZ4|Eu+;X0=(Fd3whXM}M^D<>9`VMZ+{3o<sC?LzccBuETTgewZHk}J{$ zz0|xQdZd=9RV)sLQ?H;4P(?%@!NM>nThJ~cOw23d6@_bbAOc7b!N%g$EJ%?sCN7T1 zq?#L$um|uF$;M`q&8ZKtI<<{p5rt!qVw{jWr2;;QKt&MPm3}%EjUb6lA!AWE6#xW@ z%%gEl4{!m!M3XUaNLW-(4FDm4A<<-PCN-1J0VeV7b4J_`OGA@_5eh)E*c1vD?cCT1 zCg4s~3kQpuNv<Fk04qX=YH4lKF(OKI5hEfJCAx+~iA0Gu%8ZPb_H(XRB2A)ILY$Zp z5J{93qeFv?abi;-L_#<>D4|rKbf7_;AfiMxj3pVZ5{YYHpk-1gp-!wUQWTYGV3I!K z0<aUKLuyqiXa|go&|#by9>4&wh<IZsP}4}A@&Kzu&LVP5OzI}tBcoz}qiKGen408{ z5CN29XwWr@oXP;yqRCPBY)(ldOaMNy<mieYoRcF`fO64S>{hV@Ex>$i1+pfsQy74i zXgTr#r&aF&0^ldM6tzJyw>=_DbS46UsYzcaSkN;vNrWRh#Zo7EfDWjSu|aQDHOT?c z5^0M<V71B~xB=>8Hwc}IM>xeUkz2J*Y5=xG>!M+ptAtMRBMQV%QRk?XEKYw$=m3Ud zml&(GPE`O%k;e!)_BwTwKN0`{q$oZzmf?XRKwLx&dzJpSWQ2kkQUo7`b9!W-NIoKl z?Y3Y<naDVXhxRsR<V7qSjgx|DNg{T{nP@+ThyFHb1YArH)l>37h?qXQgNSKsq@1W4 z4eg?4WS#$_PH)?A(bA|A;i!(iU@Rk7=P|iw{afRD+P^is=j~eqd&0jJ&@;TN^B6f& z{H<vtN8cJclJc!dBg@|!JJS5EStC#18axvJtqCL3-x@tq{jC`zSKk^w;@{VLE)VGb zR(pWIQ0qh^ZM@Dpf+_Pd87sme^RnB*X$Vug^|I<X^dZY~m{zBPn)8KD<7;lm-!=FJ z>@cPbYl6Hbio|uD_FAn31vlr5A}c$J?$*a#tME{!OlyKFHxY{A)<=MqcxYXwHM=r5 zSK^UQd+QowuFTOI?SfXAQ<inJk~Q9#Th*pmr7gvFs~dOYV{XjRnx_?>5a)CwcbO}U zDev-S#S&@alg^t)<GxVZbYr~w8TOcOm2Z$%v%;hE#ibRm(93kAcUczZSU{EU@3qlf z+~c**1vzL_!DT+xN_PsxHaCLCd7-qK#<#L8{ISp~-!Lsd3Y<1K{>IN-pW`*q1sEZ$ z*~V!VZt6r7UGJQ=90fI(i~7YW=tI$E{0cUbL@ZtJ5-mdt_O?fcMrYyG*~aj4w9wmp z>v#nmtg&BJyiyk(3UMwMvsT7JnsbfQ>Nq%K301su7eNX|E*G$iL*Y(^*7^nL(5BMM zbZXSlhu<Hn(P2zQ*76F}u!l0sbn4Neb>BxS?Hq~hy4+Q2NMo5*Sqjo&PQ}*hWwJ1) z^2>6ig~BiMjpYkv!dMH9<mIx^hYHKtWo)#GqPpH~Yoxh6r)w!?y69sCRlcojXt_G4 zYs?E~VRfa}(@Gh5W5rdx;<k1a`E8FpjW4;Gr)#ha=wWqb*7Qo+xMSs2ogx=w3TCbs zg;wgJPUY70%G&s2RaKorwx$%_ZI6pq%OOk^*81g5REfsA-i>S6wb3B$au;5;5(exg zm1xum=VFZ+15zN`#Z7t@EH&^}?9rm2>m^N+HbMr?CAR3)u;*%xv_^-4wyN#2H0UcA zR_+n9aOZN3?E`cO=XQ;@MmIf8<rhE7q0aFey$6v4FI3v)X|Pu48s7$~K-ViD16B%p z9!oCJq`{lyF9d5{3=m6sY1GhGh^^iR%Rs$VE&^5#dhnIKb!?;z<V$!d*;s3e7qZba z&{vqPrlVvL&vUe5S4abSiyu2y3IjWH9`jaA13L>I>sAf}JM$jPR?q@Fiyqs|Wh=0N zyK<k4_9lR~m3*`v)dH?4y2?4Yd!A6Y)iY6cAfpJVrr@uM2jkI>z@H=cilgp8-(_x` z2f=~;a-R$L`hdEX-nASR1GXvr%3C;ku28$xb&z)uqxh-xuy*95_^IjOuQ3Mo(W+st z*$21LQox_X_xw>)AfJo(^rNUj-nDNC29qEppF&Ki_3(1+U?S0~p%vUiRm5-BfLygD zIHSrz7JLa86E=OP+^EIfpB|iqyuDLgG9>C`T|nk^iAL#a<pkO!Nmfag;3b|S7DQgF zx;M+Jec4?;%k4Lrep9Pr+cslcCXqc?Q?&&b^!N3jLHv$`Lacrh=c3~2up^LcisuAA zxdg-kb~i4P%lq+~Xz!W_r_`$6A8Id&m-5==wW%|z>gg@o2D4}G<+%@+YKvQGFEs7M zy=&VS^e!5YEB!++@A&^glm2TB`M;{m|In0SyV$Rozmc<9-^khjk;m&|X=_R^@?BU~ zFm!S@b^4ErvZAych#+c3c+a(>py)l&5F8G7@8Lk|vo=5?h}!L91uMLV#S*)JRmTGe z(bQ)X1q}&fExM{hO7+lJZ#!Eb$i?wT4w}Iqg>)%q<&gXu_TTbKF{a58fvlFvB3YT~ z>n=1^1*%B7Zk-W}3q@QR;1(!TODj%8Wua)k7+cHr3!F=by6=PCCf$j~NxTv$u3;N0 zc{ci5<uYOxp;><bAzap%bCKAmF~zpw<DEX&H05;_#l~{_Qnz`Tu9AMn%}>N=+I=@y z-ghch#_KQqY!AG-Y%|U%<rxdC%MP&jWX^jHAqp8HBc(9}Nf8ewedM>m#eKIvd(!e2 zRYfQW>RK-y&S?S^J)Kg3nn0pu(kk3!UKEGjn!Vbn^kFVGUOU5eW6()7b5L#_B)1oO zgDbp$!tt+v`hSJvA5!ea<Mof-e+a-}KtL@2W3m6AaEKW?yZjRpF?%OlLl+Xpe-BEb zvabC+11hiGJXwJ$&ieDGnYYHc#*oK(LrR=f0tkH;6?}Hbf)y|6)Im$cA8>jZkVt}_ zcp;s3MO6r7RHD_V*XL~S%f>AGZGM07n()aVt{YD`KSjV1g%_?zhK&j2F;Cx=B%ON{ zHm%?>JM8#S;l^uK_8v&M(Oy&k6opg_dG^f%FV9s;&oCQnGO)xaBDZCHcQ$L-h;`<T zdghcLB9gkL8COLr)QQy-5i=t?z3IbsBKB&XYFYK!GSrZ2_<10K7FHg@6yLnZ{29ls zwZN`brf41|6C;yvJa$K>ZiMd)9wlc@=sNc}-O4CLy}nPM4i`w-h`Hpi4vc4bnrQz1 zVuiW)bvz&_*1<kou}1C7sk9-(a?<&sTpqX3xc(NMH3m!>`r(s@GMmuU*!Tz3&BpXz zMz4%y64vS@iDBPoB_uw;&>M+%eAU7TiyDqQnin^0NuK~n_-LEnC_wks{Io_t3Bnb+ z4d#}pF2<(P7x)p72_uw#hHzjpvyln$OPA<uRZiOJk3zi7J}ecveDfdOoY!5Ys9fpU z?64%t3U~N&yY4{N3Y31YWk=A(Bw^$hO_+0}X{KN{(=V_qr^gqNV9mg0odw$s$49zL z&IK!-LL?=ZNmZnGpnp>6UlZlOQs^H?4@a!u$9$&{)Hfgff1g7C?rIX&e@~$#C0Xfy zfgir>4Y5Ni)*nr1JRTOJ*oqw*NWF*@DoACW)hBCJWUIdmg1&|_FzB<v5I=#C-o^Jw z;PbYSS4_4t(uOleyZk%5fLHpWfZ?OLl3i$+51tCh`+dV~8a2;mjuc$M`&Fd9_H2&z zpud9jIR_H8#=e)~y)pGcr@_B588BpIlfMgxLk9kASyl3z-UGFJ3N@u(R@F1$+&Ht< z&UFcO?F+t+2;a+m3%p)-!-i|Mrp%-Rwf;@2?t1vZ+por&q>!%}-3G~MP*QANB)7Ud z^{a@gLD+6P`&N*ta8^xt8=ag9gxUY?l>I$!zAKJ*T`}<9tC;A#yecj#lE%q|c#{qj zyA)gOs|4>=<iWx`;VUwh#c4$(%uf8?<ah=sr&FOpn#1V!>=2{oh@)CO^>&7jLG0$e z1Y|!o0_~PTG2%9LKqb#P?KmT8Zx7Vv0%>&&#qc6!&Ag(CtL#mYS#iLn!Yogu4QoOn zQ+SBOK!poOJDnH>Z~^Xx<02Jl`>R0A25acw(9-`J)BhgrS({Rpl<%=S9vlcr_<ucM z{71CEans+Uhq<Sqor$`oiHpU5j2|l7@+g8oKASq78gP|>k-*V@G}7|Ry$~)CSuv2v z!lW+<Fm%zF&f_<^Pi~^`%Fp`uKzcGF!CNGj$bZTXakML-854wrXJn;iy!_2r9rb&w zeM0KNWMUL?WQ9RlPLvp!2{M6I!c;O^87SehMOns52R(77jM65v`<2AsfLT#-2IF5f z5i9@(r_4D`zt%AZOKOPGAvNd>+CH(l*Fu{WRdeL|^Gf+t_!6>@pkm(ylW01VRny2o zGpq<}*!6%$n9Nb8!^SDHH}!4_Ojvu$anPu;j_O_9r%@*RF;ji#ko1y!jL!wT?mz+Z zhHHq|-S#D5E^8l90;=FlD@us*{FhKqo~U_>y+t=cZgq+?a6(FuGW(CD(p_$y$*~=( zAd357(Yr6OuDJJV+0vV)B@m-?pPgBxu(jT8-#ob9V&lD>$erBmVclQl6Y^MW9#31= zT#c>r7jVX_5;pF*zcFQf=yJvrLU6@24TN@vxF}>~v>O8<p_DQi63iQXNEooq46<i= zII5P9!HcenIqexd=ybvyxyend&<Jj--1zh0U*3suW|5H54X_PuReW41qZ`{U$8}*} z;fP2juSWehR=}^vsu6R_NJ2W3zZ+Vxiys5THW0A+EvZeyPi&++L8aj@ekPu73O+X? zoRh2~1Rv0i@`CutD-bw@@%Tbo9t*MOu&Rbx%AzTmPVMq!l}%8;=I_myvO{%--rz3H z&=JAW|A4knSR1H8Oz@-oH9JwmQ;~0kO5g`g+#x#}Mz#<NH7fs&R2Shh2GajEu*@$} z=ns&}hwN1G0y1|DJPvgLbR-v*e(Dlc%6rEkJmP(jy<U}BEWVq*LNvO8S9<**^fD1Q zz+z0lfFd071Nmpv``2v$FCYAK;}o|Qj9CBn0noP(#Qyg_aI&;>F?AwQ`M#TK+1r_l zSUNk{7<x*Zdj6*sroXL#`dPG@MQci_A>fw?LqW6&QvQAmDJCh1Y@~<+1t}*p9!A%s zdu}J|wZDBlnJ`p<fzmq=JX`MnoAETm(h|ypQSWc3=iSy**VE*=-`B$nYyc;X_-tev zf(Qc+Us1%pP3uP79>U*)lgvPHOAJ$!*&bwJam#gD&UU?3!{c%MsO7#Y2)kLnXgcQW zIW-09InH$h1}RN?`U5&Yx^}FDR>aLZ93CSH`44y-_kAZtt8hW>hezl-?z7}9^F^hp zQk!U<`be2IBsBF)Z9!U!7QU>k-m2D5Ma6||E>;NVd>uEca?#y4ghP`$y~7@KaUy+( z^A2??Pt$F>sN3ESJcY(ix_1Lvu&L-MZG_CR0aFQVD&z*zsPky8SzZdTf+4!#OZKGQ z!DI?u?ZA=l4OH<cs!`jWsz7fQjURrwoTeUBqC!qbs;a1wM*h;2qho&A+%C7hPEtnR zg1w~*Z7JL~<-UB8gl&ha)Sl*>NtJJO6HL^wG6Rm=A(3<_j4m0+y=Z&JMj-6)JO&ys z`o1zUd+5T`qFy2|x1b#3-0ojeh+ZJfUm{?}_ch!nN#T|P>2Vz`xC)x-idhof7zJ>i zSC-WYSv7otnkOhBVy6+BqaM%CU~AkW6(pM065N5Gf~rsRUhoh-z_IfweZt3khHy@J zl6E@~@jFz9G%Svc0fqve(0l!f>_H?#W9?!aePcMJZrC@Fu23ICKV3lgA*z_gQWv76 zPMowF{wTDDNNEt{KE$Ap92f6+%d)$`7*`7p6AmVit87(jq)pbLQ<Kq`f=il4Ne)SM zhgPx9ZT~1WX8b?{$VPHjI&hz2Ch%GocM5i&b60wapD{?#({4bquW`xFZA16~aS?>{ zh9m7m-`^sUcp$_2pvI5t@9syfVlLhrK`0N%SS46erwGEJ*CwtF<Y4jFip*8i5Lop! zXcaSxut{kmO(b~C{`<7xUrh6Vvr~Zo(ag7<ME-x-N!8B5(8R>lMAqKU#X`)|)W+oh zdNTdTPQ3G*ZsT=68c`skqJoqJrqs`YLNOYImP$QPMn1-Ecm|HEwoTf5SJ&jvd(rd* zU?M2__Cw^p^O#>zH&acNA@PuVWbNF}PFI{qTikaSSK;zNLyX@qd2_-V;-JD@EHLec zpu}8F7>armM+{JW>#*%CFwG;5Fp`ta(VgnyB8%<PQl#=&u3CGCGHElBg8}ZkyGOWs zr4caw{Xs|7866Xq@P=AjOUXxSGU4rKC}sxs(9Ut{LE=0=;(gcQL--vsouUZYY}?%& z{s>AURx*@uR+C_^!8B2$muZXc(%<C?OXTfnZfNdy(LT8<z_Zyf%~4U2NJxS2Rzczr zs%MYw9@aTXkK+rI>8^aQ&UZ1N3aK$kEz4c(aht$(Cpndu#HlrMwUvE_JCdIwb}Gl8 z{>2j+D)`6OGSbOFS)FCW<d}0%SPw?5xmCF^3iHKI6Q<?CC_Cj$b*PxOc#Fh$wEQ(W zwVpJaXKsg4(mn_8s6=;|7ON$69inZfcsDLka%0h9x(D?Y6aW2+1Rm4E*n+>rp|*vx zBEaz0W}z{czjO@bp+6(;*V^O6yHS2E%ZaNXwiOpWWHwJ}H_OBtr@^t@QJ7qY`Cl2f zQJiKP#Zowvdd>S;(z)Il8T%9)u+46YP8Mh(<c9Pd{)FRe{1pURqT`(Ejx+^6Vb!jm zlHU2~AydDC<Ot{%pvBI>0LSZMZZbq;%fe{@F*A%dOLAt6T%lb5@#_%_7mTR3HrR)f z&?|;S0zyT7+7>wybzX_k1KQ(3(WovF>!e@fDtLHBZ874WOw5bxRo!An1<kzeuT})J zP}!Y=J_S#_MoKEsq9`IjhvY_M^e$B0v-$6wB-vIG#n^k4I=!mDPZ0-+vrY+d9N}27 zH|fW7i(iNvj=Uqfh3Dl~eg%hJD33JOe4bgrPl{OhVU@`jLz^)m&3^&^+tm7Bobum2 z#QKScZu9LS)^88-{C~bBshgTwYnmGV=R`ZfP<~zkHEesm@oXsxz8N~IL|Jhd0u?+K ziIwr^=x=aT=%IM`L#8O*_6EEg@s~l7{O4YRop`2fZ+14;d9XT{&Zqm0Bj0Jxi}*j= zU7#)TkmxcSQ$(@coF)#-LTGnRs?4<pMzaIR!LzF;FG0O)r><H=r}pP!KO!tPj~r=? z!iFaqthhVIH-&dw42w}9YWMGQI`>HQ#5po}<k&oj^u+XjMOfH{Xc<fJ-+<724qZ2R z`Axjz2Y2CLCNvAp!-{;((%DNk51Ji2`NxZAZy*MFIUNHYCU6M1I?;HHJY2+H<`Yzc z@k^TyL}k(v=THT|uT4Vr2&bU8T^H&6Dhw`q@h=kpUzjr<bwf+@N`ed0?5hfAeKBHH z<+ep`jvpp=R_~la?ZG}_w;V9CmxJEwE-3M1jJpgI@BPBUFxbNzSBjJ|KHAm&dIwRm z@=I#poK(`$8pc3V9L*KBA_m*NY}u>Ds95QeR1H%PkFI1UnK&A|=D3iI8K0>)H-<#i zN!YBR#~LgvE|r_xuiE0+4J1guRRu_ATR=>Oocgd_Ja&r**>K5Bibar^l)55YQkPOz z74!k6QqCe7%PX+j1*}HpC)S$ynq_Li7mrdvt{}V82sRg;f=$^U*#@Q@HH=89`J{Pl z2K7ZfCVoL~!KmH-UuntmF)>D~9~HpSvk~;l$s`>_rgLI~$fvOSxqkv=Vk$J}!oC6H zo}p#;^WjY}sl8~S^akkalyB)&S-Wk>WpE))5JFAJ>3HQzB2yF}MMj9K=ebd_I4v*X zQDNFq%;C73(G6oc2-LQUu%{Hgui*b=^}pusf6wYlJnrp~@9Cw)_w<tW|23<XUF;py z4PA^aNR(Z^ry3;8|2e-Lm&0L1<(-0?_@UHSPFYApoRm0xtx;5_1pbSta1*RhX;CRH zG6_@md^V<Ez1A>vAP8|Mzf4bCQ6-e7FX_DXXk~bL*!j;FA0IGBuN)FS8)ygob)4Z% zy~>=AVaa)u{WEPma@DKiu!+*cS*2D=ul;GZ0Y!5m^0s)tH9+_FEF|@zDb925Fs;Eu z=GE+{b69BHZkR!7Vd6+S^t7|!y`#4IM?^6Xegwr*f38|<xySblBUBajV*Zv$NY&!% z>?N#Z6S<$vdBZywOMY=!Sw+d3MLvneLJu@lZub<?gP{%TnrWGC7FmE$XEbsya`WvF ztnaxl-xjk-b%%0*ZCJ2+B#4i}GuK(@k>9WVwht_Vqm3zrjJKU3B$x$cHXn9$0pDG( zL3f{LOZ#x%fK6pR0f9TB3m`wjg4ToEAJU1d9>Gbqet){$Dt9(zDgD2SX=D-)Q>6U0 zJXw`nxx^>=nG^AsaJ7cRob5L0=2wa)guw^vi7J&?glt-ccK_`G;9rCJUt#{IilC9| z&C2&ZaP7eX0a5;sVRm(}F{M{9wET~es!(my8ATQKYtt-&bR2{>6aqErR*_AT&<9$` z2pmR&&}SvlN-)H>O}2@o-LPJ87fH<U9n`_&UR3WjfLTs}n~N)MKgRwO=My@PIJ>@G zcAjLBf$w0;d7Agh-S23BYtr7|{|PkU<5{E^$cc#z^?s)=NH+Cg*B6U`BI4(8KPsZS ziO&f4vYK!&D>%U}7rp)UEky7!QxV$z4S?^!Gj+H37h`!&KptEI;>2hRWj@J_HY=_& zy)3reVngM)F**2vW*}>Rld7xhc-De6E3wb*(cb1Q0lgnago(_!i#V8&mXDGEcB465 zpsVIQ6Wzktd>C`Ce2PRppY;*68o7fOq|_*Fx@usS<~n7;eN;9*c4>z$T|%{rWHSt; zl3k?|lTwPyyd*3f&2Wpd=D_MEynq=|MmDB={11hAUTO!q@u`z$*J(OeN3W@o_7gYR z4rx23(NtH?2{y368e{aR1}q{7p166;$uw|jcWZ>%?(9)~TYmN}LH4{CL6^ZYN`qE| z7R~q_2-+<`9{STrB~icQAKLO%%Mg{L81Bz(bw49{KI%4OnH7-qCDo`sV=&8h(SD?r z^+f=LKOZ)u-Qqnm>-Z3YX|z7!xpMN^4{6tlIym!&0`+o;jJGA$WtzgNvn0H1H1*!> zY?PG^OZEf_hpD9l9bW&02EBw?-h4RJ2dmjD2dgK>HtquFi_EiBwOrQbuH=BQ1~*&r z{*j7{#D`=$t8+KFOr|^8r_Fk${^o)1)F-k##p<ohhzaQ=JEVaIWzH)@#w#YM(ENk* z^aOUf44=S!9}7h7GRy(Cz}+tgCN;Wc9kIP&pQ4IAAcQiGkYJEEH6C7FW@+XylmX!n z?>_aC8iVqZotPMHkPp1MyggdnM8P8Bk}{6It*t?<Kn?5KbOv2~E2^nI+|J6%lN3ko zK~Eo=n$GBgG7cE2jW9V?O_k;YO#^lJYFyq;q)sKq3ar4=uQ!IOL=&Rwwx(*<@+MJt z8_jHRw~B}p?@pQI#j4;ub;D@3HNVB=<MT_G;?KdZW>@JQiSTvbMx2EP772na;E-eG z4;a1B97kBa{1?|(#F=3BoZm9dfkPJsoO1O!oS7aFH>}Wv=Q)gfl=~}^`KLGrQ0*2= z$(DO8;sAl)Iarr4B)@@7fq9i9512!;n+%G0CxEwM`d8pR=J0=qgm*QhSe;)KcKYf8 zy^;31*VXzZEQO~pg`fCC>6QjeD|xs|RH{_Dq5YrMt^>ZQa_xs9Th=Wb3P_brS+aym zn+^(Hw55p3NYl`!&8SIQTCN~L*+UsB4rGO;f*=k=KxKnWnO;C-2{Hsk%4G=O|H;Wo z^X8oM=EVEu_v5zU&GSFcc%S!K?|X**I?)l=Ys<u!bkoAi{Cl3m@wn`X=ib=5wnm3$ zo$plZJSXX=&t?v~HhEjeDFxA&8g)4SQ?(-p-#mGu|Ls&;#d62n8T#cW{V}5NmNV13 z&%WC&zC}^X%QJ@e+j{x;taEMOSbFb5a!RN^`Ommkm!=%Ja@M-2O7ETT@0@&Sbo*7u zpU4|Bx@_yNO*0qIj&n51I8^lJx$kN;SWx@cfysZB`_I4o-5K3?_ur>leE0UtC3q)L zQc?Qh86AJBKlE6O%|~}ntW(jkXTX%O#}npGKfH6>f-mYmTv(y`>6Uq`x757-xQ^{| z<&e5pFJG+mPS?D6yLHN@1;52zxLq~#-ino5wB|aYx#xbWVZ39!|H*^#|JLrPKf3&= z>U~a?S@hnxx4s$|(dOR$VXJ07dSmeICpT@~+<0WqBwLe4FMV+R$7kBS*r-nXg<C?` zId|rzmrWYduEC?wa%s&A-}zwniR3?eqEq})w=dH_9XPH2m=PVye|dB0_E!gQ+PQK; zc!kwThgwI}OH4Un`dELvcgENei_O=TlzEVHaQ?eDKkEMG;lIykJ0tEoCcPQ6__4dR z>+5<`29zlqQZ7VOsZu4)yKu_~FB}_P4?FLciW*G_+_Ly_IqA2=nDof@@kz1aiIGY1 zu`y}s9TH;&3RO@K*0?E%-=LqBy??2xxgI$LbiEXOzef9k_y37s(3|jl=xgKfHLEQ< zocE2Y;ukdZjm4gC=<;>?9PAx#9)&0Lhx!-u#UI%(>aAw8)naD|P%X&&9sJV3`xiof zC{Mtovt)PSl4;J6=>iE5%N_>A=Mczb78p%g1{;@L7(>p+Bd51o^aVDX!Q$XjY|2pl zf=AI%7>HO4hS)7Gu_C=8-(j>`n5XksV<<zgGvW$G@u88G!_e~AD60w!msWv8mr2oy zkA?Bct>Tfh8Ah56dcGc5POtIExzFqH9<3E4wN@24Qu90e!=uVRp@mD8nv6VJtkr$Y zr6t6PKAIqZ=H(E-)bRd=mg*%C^Lit*4mQg?iT{_MV!j*#_vrU!7+eQoy><}St1oB% z^g1&1(pAy(&~5MQP6XFI1+0GY#kq-Q@HniUzw2J?OFbc88<UiVyEuy+!t)6f+%@i~ zlMNr?xfUS(>gIhujmG61SdU{HqC-lzqTge*WXBZgO$Av7Arte(pjBIMTi$P@L4N}Z z7rxqYIoH(>0wc{)Y%+vJ8%F91Ob!v){g3jnr*F*48PY_fF%A)$mLhj9r>kMGu<{69 zA7otU4yHbUH>0+w_;ERh_uwFCO**@Mki%%Qhs9H?V5ClO@EoV}7u|`6t21W+p(-r* zd67JRx}5*TxjjXP=i}fb9aghZpQamWh_@IWMxDtxTAZ}-2Wws~tE2?P$3j<le(%TS z{IicbFs;$1FEBcyYzAGP5=x^lT20;qggoq<QC<vUDG3~^VaXRousvbBkSd8R{PSJ4 zQYyk{o~y3WjAZa8N2<e1guNM~bo#t(o3+4_<s-*1<^Pmwu;XhAYTXyrA}s>JQ(MF$ zeVJ!!5yyEZgLh-}tO6`Mfpsma;y9`)FM;`H!&i-AK#yx`G+h|91IZjTvuCGE6n@5< ztU4J0THq54FN}A<;cSH~Ds^(C(u52SK&sA?Wi<;9#JwD(k5AM?cSXC-U=2(F0_@QH zaXCYWaj1(sYofuNX|M^)EvCqz7r2p!id}QdNlR@Vg3D+x5HXUY<3RcCl-eAfEzR&s zfx)6Tq<hZJT0Nx<-!(_pSwG|Kl2ELKK0swx!^Ld%h)D%zgUzTHj_1bM^}2ky)kk;* z6JigI0M-oDU|0_AdH)b^kj0>cNa~A>UR$ypvb=;p*rvQ6movu3K}^qq6Uh?P<{3ir zl^s!TKJMK)8$ho)yb0?ZW9=#_3n+0|*ZC<nLzYpGf}+$kNN_Qo`lQCg&)31SWj9K* zg9GLsantHd21}OCmMR2$h-{@8#L)bq|EhTf#!wd+tfe<B4ulb1fVm4$7Us4Dxusk4 z3<^+xJvG&~403x4aO~D)9TNyj91-(Od~}s(W@pvzvljtjG!UNiYMs{7sMmr-5NArH zK%|+_r%%57GBmRd{-G}e<aDYA@-*#{-S_C$vD5I>0+WIr%nhH~+ya(<$CeVypbeN9 zESfkXfaMDprHnaj(JL$d4N;2qaS_(#Y(F&+rhm0uVJ&4`-Fb)tjpgtStUXkn&Vz7A z;PGb9UXgAyqH-%$6UC}ePRXABEuOqR7%5G`$sX>{^ogvKlG72b`iH8tI@YhuUArGT zE{|R28BqlI>2j95$$3P<8!PNwJHF|+FAr=Fhc??XH0#gf(JYPNI!n2whuu2;)WBpA z?h3-J^`Cm5Ls$~H`2-tMAhQ0C=Puo_4M5c)nK*`nx%1Tl!8@5KrIn3vq@cvz;f%wX z4`3-_AsS6j26W#-m7v}d1ZU^3_2K!uwP7nix7KL7Gce&RI54GQk~co$fQ&tJeNTtR z8qHOxDVzaW26I)6N8L3AVc~L!zZG$)%3N?zh&kvs4Dn7UIK-1Pb5RuF(9N#Dze^&* zxeeG+J27;dT;tFcV<Pwb1c!X%cGHiC!>IPb(NUXO{J5OEA9Be1?%Bfc@mZX0l`LuD zky8`C2Kn0X3dm@@AD1)paZpGBaLSkbci!asm`MjndoKz(52vP#vX;FQ>KtKJD%`%* zg2%r|%bg*e)gTaQzpd2M%JdI(=7jgE(;GWnB;tZd2BB-CAQ1$M<!`80>P<h~7|fIh zWHbYJrm1Q;&xT6gSEomkn_$HM=uA?7LQbqxY~S7`Kum?VWCI`bQ^6vpBM<VK5Au~I zK{b5zL$6VQ+5+Zc80Pjr9W>M^YqT-j=%ASj4rJj-eb;C}t_LKWSFdjs2-0W!&Nmqy z?vA&-3}ZGpHV&_?(X4`nw`3U0Y|BB(Kt&)+HtMD2`LOqrAA3P5&!UvhW_EQWI7A~Y z7At!52uI!PMm$B}s|%w3TgwS&kAiwrq~@#_Tdn0#7mH8P#*rh1G+QbWBL8NY<c^~u z_mz<Q07fF`;#H7mN=!ngpJ22Yn17ZB9@TJuI~M@Y;t%Wfk0x+{X{{h9&Ne8?Yg+bK z;g8{xv*8C=XL%@56<zOYjHkuukV{HQaNSzo9DM_V>w+zwb(TF+c{rs}Q70u9Ql8I9 z{2KaLTiKuV_(AGOcUB_3e`2*m(?Gg)HUB(d?u#7Kz9Cnp9n<T2hi`#NDUn`wtb(Q< z<Wmv5FuO(07_JU2N@q9fg>5nxpjMk_K-hPckjMHWzTT<@(E4l8I_n&(k5q?*>X6-` zvp50<lUajvKHo$}i|s6ySuyo<)j=s2#FW%ll5(x6FX}Dp(N=54V8-WhFk>tQX3nO3 zbW^`d-Qijq!Wh`7?o1(vs?f)Zp>7t3c+SR(Wr|>FuY))n+}mH}5f`g<;hu7xA<G+} z$~zL*r0{wvxTmc=yhuAnHt9|dkUKVwB}<kqHIPyLxAU&dSzv)e3f4tEdWS<<DA{pD zlV7rZ<pF4OLqm<GGxNlkKH$(515=-3oxDUg9{zOu*Ramhcy?B=byslcd*iqiAuf?8 z{?Xcb@BIYgGqKv(NUqJtfr$G>atdko#6Pdyp8*8%AeAT~mvh*sK_YaM=OK1Tnep54 z{Le$NNg{dtbU71O2Z^B7+0itx8!UD-4hjtvSSbgNv~SexwLkwdxO*A+{Tb|;p9hI8 zmPSOtu=LUKmXTH|&+hP16B6+^@Wud}4Y2<BLN%@@U{$Wd><$kNE5@$44W`FB$AMo3 zi<0h%9Q~)+eSJSkw0*~iul$0{{w4xD*4!h$35e-F!KtNr2zjv;_ijJ1E)lQczZVz( z5Qw-pE|rpYw>_Vosu=~1jK!Y_#uBdVDx;!}%C<f8t>zB-HY<wS4x_>DD<jf=JMD?b zL(?>xJJ*G=LJ`j8+_#&<hWi#vjwh?OVcG9wRB&5<&cNBEta8RE2B$Hv6zEKL_;>lf zC_VVL1&wBZgz#Yz957o_{xwtuLO-27M{CV8L<z$oQbiEP4#QsO$|p6Nxlj2AMdy&< zD^@o|E=nubV%V#QM&{bAc=zFbkXI`>fJ9Lb_~~-q>!Siq#1J~YX*pJ#18Mz8V-fQo zq>K{uiz(Ul8)9|t0CYbFI<jx@&_*-rm;q2pyz#GYyh^CEfXdbn4@GfMDGraZ=&f03 zUrN~_!g-q}?463WS*MnNR1_T(fH23VzukKC;Ccur6grAxgcO#@p&BqmR*LP`bx8`D z1gv8cr6eT%Pk6%Qx56fSw6i8@GEh%QP~%hnA5di~zNE3M`E_c21DR4Ki*<Q%sp?Rr z34xqk32X7t3HnvohF*l{j%M^|O8duH+?Aa>bnHDUoBRtY54*gky`T;eF|TLn%x$1y zVp0-Y;3%-k>`=6*Ggi)9FcFzzF6y(ay%xQs4%HpXYtgn>mDJU^Q*Tyy6-@Y{Qpnb| zEd~yrPu7rNv^xwIgDtHfKOgQ(esPD{nl_=!F;bAAuyJPjd=5;4RgXrZAicC=i$1c@ zYV@3f^WPK8{Z!?R92m$0FheIQ#E;8a&dx#bYxzf6ttNv`rh`Z}7=Gx{)0e@(YV2TL zMEdyYa_)zrDDEtN5N;<gl@clchiRu0^@w6akpQvP|9WFN0AecPwl7-&CDsZak+`_^ z+3`s&VbhgRq-VJ}Gm!)0%_n@?tx_%sAlb6B+%GWUb<O<~qHOfr6vgBQ5OWFvL`t8e zG_BH#<m+&BF~DG#$kKP!()ToSQ*;iLg)CyoEyW{#)~!AH#8%kuJ5W7~SN22Ic%E20 zT2~xzp+jk$;%OyIlWuomRtqI=_1Oi%;sxrnMtqo3_&Q{{9|pm?)p-kp#S#;kB%Rry zoKuV&KHqR2(sV$Yam*r`;R+T}JRvJ^$r0(&JZGAGJNe@BK%m~Z-*fm%W-}zK-2T<w z_bZbm5yG%_<E<-s5bk!eXW*#x{Ex49BkEoBTPj^a?d3j-3}~!*KQ3pRRUGPmRcWbx z6YU2JY-g8)A`QZ^wDU2)sJLFmfSJ3AUL958Q8?UXB@kvkn*Cc9w6#`qzRrfQlnXM< zY)PabxH()W8<JMss{(|I>Qc$j$~V_q(Sm}<fmn%bF8U0PbqACT5vDe?lsJjK$L4Vn zxmXDKk}dJMLn?`Tq#_qH5kkd3|41qV!ek(@TVll{!6I~&XJW^ZzX#DYflUH&?pUx8 z3bE}w?c2WL1jI}U#G0Rjg-}?#XNxv`nGJ|c3B=q}!9plBG|dT<{~(B53B)i=`l&J{ zueLqc3;FwqIYr%H3j@S4L_w^&Tb&CQqPx7hEv`#i(#3Re!G>|4T?i6FK^4zcJTr-o zdlyL%W?u>tK|xFn;@|5<JWP=wjJOgcLJxT<&A7UE&T;snGKi_!vYGa}3Irwz59@EY zT9|*4Vv?&`^5DVghv154RM-aAOthI5?aMuwjVLIG6EM~+>0IGWkX{dgrFwTB3VSc! z<B;}Ap=IZ6FbVFN&UUv=({=VdDQo1$?jHZ>7PV-?;Dy;3<u7oo$eItnQc9%cIHxol z{(UEKOfz=r496`V{f~&+9D_d3Jp*5;GvU@bos?%%XNPeyLkA&}IEi8i%kwc!IaNF> zx22?rB;{taho^r63DamU+i9JT(!ClfQ~Z~eW-#mWQO1((=n`kOf5=%e9&%lVXeNr0 z?V2haoYDy=WH~f_Y{*JQiVMg94W)K><A0+mRz0!>w&T9I1_#gGP>PR<iRu1qSEX!< z#5Uz>{_8(uVI&~PVafLo;gM%2&0!GoTA6pfO>Spsq$6yBb-3djswXcDSIHw-(i`Y3 z$eE3eu)-L9)P*T1>fPP7mr^7R+fMBIHUq2YKAxM6`HrDVsz_1HV&g42nCwRLRxc#} zQV^2+x+=FVb3-u32&u5)_N=xX5ck|V(mnT_u>83YVqr?v<uxn9XmTKSwzBnl-$2yS zPxrh#YLLZ<f~O(CwD`s6r}a95g*Oy<ELKT02g`TzEYdUzucu146&M1{ggNV+y>k?* zc>xy7F7j@194vQgPFG|Kl^FVsKTc6+aNOG~!BY#E0Bg4P{(*4B5`ZT~SBMifo+vOj z0reKx?_wCU9h(p&g4UW}Jg~qDkD^=$Ad|bTf0*AD+xiJCbu9x~Jtas;F;!LuBrAN- z^U{b2XiE>vh-3iQy`UP<Q+NOpD({LTX~bX5YmKMq0apQV?0m<Fmjc3-cHV@!A*5{% z?*(wakt#7ZqUN$8<6$2Cpg=ZKZ9gm!l7Bj`FpHltx%)GXVCCDe&9FIP?GZc(cRH># z)J@MGl613u8A$1OJUdHxqJcxWwD+bIbZpsn^zP?XH5wBZj9+gon?pF$b5L505fw9K zdieZNPxl{>71Kl_l@dD#gPJ#K2Ht!~gORz9Uu}x>Q2qQnl80~_Leb}!o(q)s@_Y3w zI`4#`(D8#l%nES5&mrp*`XO5I)Zhce3Guy`J~aS(tqqr-!ayDSP#u(Fl<98W@R$0U zwI7V>1tz1Q9CoQMz#x>O{CpUt{lK1MHDv`F<)WqDBe5WN95(!7iMskN;lM$dg$A2l zam42Mpo5*>L!5OT8#6k*-jB=K^g9k&pDMq+8JxNO^L#BN(;Cq*yPeeB&7td8c#pOg z$QEO0VSN34{uB2+VH`We^W_2c2nklX<|YZeZmhXGiqo1kz+l@f)zK+b)UPlbDOACz zlH~bKag4D^;|tY8>S;7pfWfj+?Pm^*7<wfd9646u1e#P4B&JUr|G2;mHYPwB(O&gZ zDmd<@3i|2A`JNDBFm89y>ug!{FI<l`<(aAZ`gR&kBb$GmH~e-mi1Pf@xp~P(rTtLw z!}da&H7l>I7Izd$y0BtS$a8PFJiwd>b=pUw(bBq=zuu!;1OkXbl4GI!9}RZ9E?W_X z%*$|k<L!%ZA9uh9doJ)=w?Hs(Ok!oJ^w(6JM3kEYC9ud(G*@dO*I78mzg`^ioO&>M zdHs@np)dNJnr|c_&nKopv`Yi;$n0#JAsbOD?<^{@@?+zHi4U;9ybam0Znway9*#y* zQmnWGHxOKQrz^wJ!qJR^7wF3@pEIwhhwHB^)Ok`1?!ni?!#D3M1lrp`8^EAlbEro{ zZ>990tv8hkOHN6TPfn65k)&Gl*uEJ@AyJy<U<1jMqtpWjVv&$;k9h8lNW@I1(J*DJ zUJYLjgf!S{Q*w1gTHEvY@kg+iHODr|?qy$1;*j=9%jAXgaQ1G~KI~)toBL<S=P;eB zxDyB|nDoS}Jjl`K*S{EnB{TvI^k-Bb;tB-fmw&~lCDZxPz!?h(?Wdffqu;5EX#xbW z?EbT7MR2%MzG(mX?(?*Y=o`6vCR&EC@4r(`-;)ugk207F4gIVIyn`(DGZR-mM9*zF zyehjvT-y>Ppgc#r7H*kU3u|RI5=&NM@xSl@eA|Y+bmgtpncvVXQV&={OGaWF&T{BS z8I?{Hk($f)5Bm`V37QG;ENuRE@gj$)n5s};Ox$uhDdcanmfm?^zIV0ba<C8zbHm@Y z>HMfaxEL?tV$s!LArv|R7t*7T5*M!nf(=}g{s<C6K~CfPuMZgs1d{}z6>gkTbSHAE zQ0V!bsh`>M6`H3+6vkTU&D+5t$gco<yCrYoK%&fjJU^6qA}|NyOsL}ADH&|LHE*1w zef~MD1hC=#xSUUyQ-Kj5EnCWPFNHH<d7pr4KGrXrp^kn+1?5!S&VhsqqvoD#g%oc0 zA?J7F@t>=6pk^A}VYk({Dyx7(7D_iVWCcJXrdI8`*LE$$bsvVs4z*_1P=UlCge6(s zgBdgx!u$uRH4yZ?35#3p1e0S>l4k3=Gi!06g$jjm0STv-Refwi7NywRFh$75$?NKI zsQaYZvaKw6Rw7-y&hCH|r@}ngWGORL9aw4cLS3(8*~5AFr$T2`wodmNIi+XsH&chG zu7;7EFL%iX+31DI+No{u1PEvS^4w)D)IC9hZZt-uIQKRYjP|1+6GmXgorWIS;H>*I z92kn6Gk67zftRoMr3t?!DDkqs?nVa=UB5y@RI$>PD$Y$y))*n4F~DGJeBE)sxuUmD zvO3~vJll*zS^-Z`HG1cMFBg=51%FsySH1@aL#zQ%MlLgANo%v*^7G##E!JE?EWt{r zY)_Sx6${X$)tz6zu<30qm`E%bmj3uYD(MRi3Ykd~qMx~D)|QQs{?qUPG0gH9^?XqD z<7nR1sCU<NNnWHJsShAXLx*F%Dnn$WA+lHoa#>VRkm!cMfnrz@O)GcRL>Y5YuZrJn zh6smZfkZNxE#iX0^exgT!>!qPKAO&_4FDt?45kd=z@>o|x|+@1{0~r@ojgA3%fBJT zTx<$y3`e<%Y9R#6a2K2ttW?~H9EHg;p)(q9$uFRTUIv|6sz$Q>gr{mmY=Bc81HZs_ zc`xGtzv8-Oc;swLiz6B>{}bYy4+!>jWto?F<lQ|Tp$6b#&tAwa2{axwt7irTsg*=4 zFXKKKWj^G9ytM$S$jI^!4T=rv1gjs_z<(oek`)Y;JayOp5ufd?jk|Y|)36)Br)D1Y zV$7;59ipYDu933o>QY!3IZsy62gh;fx(kBB%rf_2bG1V4tta98qfxV9^MNByb>!Vw zu_~AnS!zi4hl3sPaY*z1#w)aw0wI)^|1jz*76mz-a>6^?>_9ClGUZAtk1ePEBfP=r z{VP=-OU!eBUJ1=y#UFMav&sw=U<p=hUO~Q6|1G4>(f-tJ-3`gHz44kDJycv9;zWUm zc%m*JvJ?IyHC>X}_7rXFiol_vlsGUVeq7G4-cpZ~=C<S%?-9WOpugUlc;`cao`#y( zLRsfIszK%XxiLcj+7kHxB_Pkrtu-d*1IjIt-fMxEhfxIY`CT4o_uAV>D*>Yi93`7+ zb)6R^4tkkfsBeBVR>=TM&l8-eAN+JVm%kqbRFaj8a`3@RukHfEuP_8QpVNOB1PU~d z&OR5Z?!1rA7K0xetYlU6_JSagP-il8adw2wocI^GnFRO7PLdZcQja6A{$~qnq@F@+ z>&s~W;Bdz>6|~a|aMOj+QJ~m5i-_7$M3b|0ojW^*Q}(++^h-Mr!ouhE0ce+*eZ27I ze3<bhtVUMz(c9ExCF>nJQ-ED~%c-;D>C!_Q`e8Hq0lU;Ac?X&D@q!YJ$>1h+E45cr z4Q4AE!tx3`j{5?sNZ1?u9lMB3dpOWO1@thg83dSUs&(P~Od3GH0oAc6Df>7meiKcJ zIF~xIm_m7ZUg{P<Zh8j@@d!X88HdpPU?3E~dODUXB$r(*j5kT)$UZ)<w|wMTFoi(L zFHxC*%Y&3%DqS@0h4YlTQ{3;63wT1N_OZj8sj^P3DRx)-`9!dgsH|HY#j&WY2dJ*M z>-ptL+BPU8VnHjP3LaFrnJOTs^-8Ya{unxx1`*BA1OhD`K2k_A6YtK?>xz|as_5S@ zX!Wal;_iVFdDHm&Vaxi<A+n)x9c+%g={ygBy|q&Qpi$TgxTYOZ2OFcn*ySbv_SClD zp7=-C7!;XJ{_|grpSjV;ijwk}=KeEOG50x4cn)WBqTlkj_SB<lI4vADzJ9V&1?7b! zR}EJ<$Fcp$f1>I1z-$S^(JDbAD6}O89qa!Zj^1jh)XVa){>dN_dP;4GBG6thzJ6&T zlBaAK5R33yO%({jJrAA+jue3$*xUO~+%myJUj|An<1d{U*i>|2q8{9{>n7YhrnWpz zT$THN+}W+z>cX)6*sV_2Mg=BQn?}*vT`5pmwAQAiKS|eF&xTF6V%S~Kjss00ufiNP zF=XuW%4Z2Mgkdm*whYzIxTZ`|h@~@iN}0}*!|e@+L3kXT6sw)%&vFR+RKX)<uMHCp zNJ=e&n9*;0b=MIvkqr&8mG{t|>M%=-;oR~tfwi>O|Ah`)bp?YNjO2#*QU|844z4v> z?MlVc?XAa68-g;+MfCdFz@$G+MNxY`LZ+5`>3IsNSZSfn+4kNTiWJ7f`q-((%CQ_2 zgZt$*ZYKSX?}s6!EJ6Xk5GU{HF0FoO8kv+ryuPP4*Sdz~wi<l0OD-o~9lB7qaz99v z(L$GlsDLKM-?QFpI|sH@4e)F>cp#AnU3wvz32&;7)fr6z3+l@jq_r9hsCYoJvwQoJ zRY7^Hn=oN27f4k}M*H`$&no`_V|^A-Z1Oa1AP2^;_aIMujAPF^I{!QZrot9ZR-|%h z`&`N!mQ-L;sB!03J@CTCp&E_uxPL8fTsnuikhdyq=A_~{``%e480?vVCuXzOO`mh< zx(hO;8JX~g0C%Zg;nfsXH+R3$1;U~GDOkZb+RekEXq%2g@FMx^B{yrHCBY+kV7J<j z_XMIXM)E>kQOTL_oP6@H=|I3CEkA_od(|Qc9E2$xnDl*Jyq58%Cvk0nq9=2wSRxM| z1Tp!Ev}6r7W;t@C*6LQg&kMEL{ptK6)qvuZ540rrPI~{4G|uM*#4Kj#qrqZ|*Anoq zIwL-PUk}Tc0SZq9i^;y|*q=M!H<YqHnuL>qkV<nNcUmI8eAX9&+?VhB_F6Mm(gj6F eWh-$fCcgQ|6WGc$n#N@sm-)o1(d;@$fBiqE&z<!E literal 0 HcmV?d00001 diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/clz/AccessFlag.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..74c8c09b58 --- /dev/null +++ b/group20/1107837739/1107837739Learning/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/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..cc23a7799d --- /dev/null +++ b/group20/1107837739/1107837739Learning/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/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/clz/ClassIndex.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..86dd768e57 --- /dev/null +++ b/group20/1107837739/1107837739Learning/mini-jvm/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/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/ClassInfo.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..6d4b1b0614 --- /dev/null +++ b/group20/1107837739/1107837739Learning/mini-jvm/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/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/ConstantInfo.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..f95b04cff4 --- /dev/null +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/ConstantInfo.java @@ -0,0 +1,30 @@ +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/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/ConstantPool.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..b44e7fef74 --- /dev/null +++ b/group20/1107837739/1107837739Learning/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<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + 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<String> clzPaths = new ArrayList<String>(); 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("<init>", 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 170/287] 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 еDzdzɶԳֵ + * 磺 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<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + 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<String> clzPaths = new ArrayList<String>(); + 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ȥ 1ij + + 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-128intͲ룩 + int c = a & 0xFFFF;// λڴнеģҲ˵ǶaIJвģ 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("<init>", 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 <xukai@raycloud.com> Date: Sun, 9 Apr 2017 19:53:56 +0800 Subject: [PATCH 171/287] =?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<DownloadThread> downloadThreads = new ArrayList<>(); + ArrayList<DownloadThread> downloadThreads = new ArrayList<DownloadThread>(); 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<String,String> parameters) { //根据映射关系将值放入 view.setJsp(mapping.get(result)); List<Method> gets = ReflectUtil.getMethodBeginWith(cls, "get"); - HashMap<String, String> models = new HashMap<>(); + HashMap<String, String> models = new HashMap<String,String>(); for(Method getMethod : gets){ //调用所有getter方法 Object getFieldResult = ReflectUtil.invokeMethod(obj, getMethod); @@ -87,7 +87,7 @@ private static List<Action> initalStruts() throws ClassNotFoundException, Docume Document doc = sr.read(strutsPath); XmlParseHelper helper = new XmlParseHelper(doc); List<Element> actions = helper.getNodeByPath("//action"); - ArrayList<Action> actionsList = new ArrayList<>(); + ArrayList<Action> actionsList = new ArrayList<Action>(); for (Element action : actions){ Action obj = new Action(); String nameAttr = helper.getNodeAttrValue(action, "name"); @@ -95,7 +95,7 @@ private static List<Action> initalStruts() throws ClassNotFoundException, Docume obj.setName(nameAttr); obj.setaClass(Class.forName(classAttr)); List<Element> results = helper.getChildNodeByName(action, "result"); - HashMap<String, String> map = new HashMap<>(); + HashMap<String, String> map = new HashMap<String,String>(); 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<Element> actions = helper.getNodeByPath("//action"); - ArrayList<Action> actionsList = new ArrayList<>(); + ArrayList<Action> actionsList = new ArrayList<Action>(); 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<String, String> map = new HashMap<>(); + HashMap<String, String> map = new HashMap<String,String>(); 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<String, String> 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<Method> getMethodBeginWith(Class<?> cls, String methodName){ - ArrayList<Method> methodsList = new ArrayList<>(); + ArrayList<Method> methodsList = new ArrayList<Method>(); 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<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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<String> clzPaths = new ArrayList<String>(); - 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<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/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/loader/ClassFileParser.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..165427d0bc --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/loader/ClassFileParser.java @@ -0,0 +1,126 @@ +package org.xukai.jvm.loader; + +import com.google.common.base.Preconditions; +import org.xukai.jvm.clz.AccessFlag; +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.FieldRefInfo; +import org.xukai.jvm.constant.MethodRefInfo; +import org.xukai.jvm.constant.NameAndTypeInfo; +import org.xukai.jvm.constant.NullConstantInfo; +import org.xukai.jvm.constant.StringInfo; +import org.xukai.jvm.constant.UTF8Info; + + +public class ClassFileParser { + + public ClassFile parse(byte[] codes) { + + ByteCodeIterator iter = new ByteCodeIterator(codes, 0); + String magic = iter.nextToString(4); + Preconditions.checkArgument(magic.equals("cafebabe"),"无法解析此class文件"); + + ClassFile classFile = new ClassFile(); + int minorVersion = iter.nextToInt(2); + classFile.setMinorVersion(minorVersion); + int majorVersion = iter.nextToInt(2); + classFile.setMajorVersion(majorVersion); + + ConstantPool pool = parseConstantPool(iter); + AccessFlag accessFlag = parseAccessFlag(iter); + ClassIndex classIndex = parseClassInfex(iter); + + classFile.setConstPool(pool); + classFile.setAccessFlag(accessFlag); + classFile.setClassIndex(classIndex); + return classFile; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + return new AccessFlag(iter.nextToInt(2)); + } + + private ClassIndex parseClassInfex(ByteCodeIterator iter) { + ClassIndex classIndex = new ClassIndex(); + classIndex.setThisClassIndex(iter.nextToInt(2)); + classIndex.setSuperClassIndex(iter.nextToInt(2)); + return classIndex; + + } + + private ConstantPool parseConstantPool(ByteCodeIterator iter) { + int constantCount = iter.nextToInt(2); + System.out.println(constantCount); + Preconditions.checkArgument(constantCount > 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<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(); + } + /** + * ---------------------------------------------------------------------- + */ - 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); + @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()); } - return buffer.toString(); - } + { + 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("<init>", 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<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/group19/527220084/xukai_coding/coding-common/src/test/java/org/xukai/common/StackTest.java b/group19/527220084/xukai_coding/coding-common/src/test/java/org/xukai/common/StackTest.java index 69fc9dee6e..5f8cca4559 100644 --- a/group19/527220084/xukai_coding/coding-common/src/test/java/org/xukai/common/StackTest.java +++ b/group19/527220084/xukai_coding/coding-common/src/test/java/org/xukai/common/StackTest.java @@ -2,8 +2,7 @@ import org.junit.Assert; import org.junit.Test; - -import static org.junit.Assert.*; +import org.xukai.coderising.stack.Stack; /** * @author xukai From a54235aba523a12e99114e3560f0391f3d781ce8 Mon Sep 17 00:00:00 2001 From: GordenChow <513274874@qq.com> Date: Sun, 9 Apr 2017 20:02:02 +0800 Subject: [PATCH 172/287] =?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<ConstantInfo> constantInfos = new LinkedList<ConstantInfo>(); + + + 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("<init>", 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<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 c0e6f730350dc1d78aae373c477fd409ffe0a026 Mon Sep 17 00:00:00 2001 From: beyondself <1525619747@qq.com> Date: Sun, 9 Apr 2017 20:09:24 +0800 Subject: [PATCH 173/287] 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<String> clzPaths = new ArrayList<String>(); + + 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<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/group24/1525619747/homework_20170402/src/com/coderising/jvm/test/EmployeeV1.java b/group24/1525619747/homework_20170402/src/com/coderising/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..e52e9371f8 --- /dev/null +++ b/group24/1525619747/homework_20170402/src/com/coderising/jvm/test/EmployeeV1.java @@ -0,0 +1,29 @@ +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/group24/1525619747/homework_20170402/src/com/coderising/lru/LRUPageFrame.java b/group24/1525619747/homework_20170402/src/com/coderising/lru/LRUPageFrame.java new file mode 100644 index 0000000000..b1514ec321 --- /dev/null +++ b/group24/1525619747/homework_20170402/src/com/coderising/lru/LRUPageFrame.java @@ -0,0 +1,163 @@ +package com.coderising.lru; + + +public class LRUPageFrame { + + private static class Node { + + Node prev; + Node next; + int pageNum; + + Node() { + prev = null; + next = null; + } + Node(int pageNum) { + this.pageNum = pageNum; + prev = null; + next = null; + } + } + + private int capacity; + + private int currentSize; + private Node first;// 链表头 + private Node last;// 链表尾 + + + public LRUPageFrame(int capacity) { + this.currentSize = 0; + this.capacity = capacity; + + } + + /** + * 获取缓存中对象 + * + * @param key + * @return + */ + public void access(int pageNum) { + Node node = find(pageNum); +// System.out.println(node + " " + isFull()); + if (node != null) { // 队列中含有节点,移到头部 + moveExistedNodeToHead(node); + } else { // 队列中没有该节点,需添加 + node = new Node(pageNum); + if (!isFull()) { + // 在头部添加节点 + addNodeToHead(node); + } else { + // 删掉尾部节点,再在头部添加节点 + deleteLastNode(); + addNodeToHead(node); + } + } + } + + private void deleteLastNode() { + // TODO Auto-generated method stub + if (currentSize == 0) { + return; + } + if (currentSize == 1) { + first = last = null; + --currentSize; + return; + } + Node toDelete = last; + Node lastPrev = last.prev; + lastPrev.next = last.next; + last.next.prev = lastPrev; + last = lastPrev; + toDelete = null; + --currentSize; + } + + private void addNodeToHead(Node node) { + // TODO Auto-generated method stub + if (first == null) { + first = last = node; + ++currentSize; + return; + } + if (currentSize == 1) { + node.prev = first; + node.next = first; + first.prev = node; + first.next = node; + first = node; + ++currentSize; + return; + } + node.prev = first.prev; + first.prev.next = node; + node.next = first; + first.prev = node; + first = node; + ++currentSize; + } + + private void moveExistedNodeToHead(Node node) { + // TODO Auto-generated method stub + if (node == first) { + return; + } + if (node == last) { + Node lastPrev = last.prev; + first = last; + last = lastPrev; + return; + } + node.prev.next = node.next; + node.next.prev = node.prev; + + node.next = first; + node.prev = first.prev; + first.prev.next = node; + first.prev = node; + first = node; + } + + private Node find(int pageNum) { + Node pointer = first; + while (pointer != null && pointer != last) { + if (pointer.pageNum == pageNum) { + return pointer; + } + pointer = pointer.next; + } + // pointer == last now + if (pointer != null && pointer.pageNum == pageNum) { + return pointer; + } + + return null; + } + + private boolean isFull() { + return (currentSize == capacity); + } + + public String toString() { + StringBuilder buffer = new StringBuilder(); + Node node = first; + // 由于个人实现的双链表是环链的,所以这里做了更改 + while(node != null && node != last){ + buffer.append(node.pageNum); + + node = node.next; + if(node != null){ + buffer.append(","); + } + } + if (node != null) { + buffer.append(node.pageNum); + } + System.out.println(buffer.toString()); + return buffer.toString(); + } + +} diff --git a/group24/1525619747/homework_20170402/src/com/coderising/lru/test/LRUPageFrameTest.java b/group24/1525619747/homework_20170402/src/com/coderising/lru/test/LRUPageFrameTest.java new file mode 100644 index 0000000000..ff646f71f6 --- /dev/null +++ b/group24/1525619747/homework_20170402/src/com/coderising/lru/test/LRUPageFrameTest.java @@ -0,0 +1,34 @@ +package com.coderising.lru.test; + +import org.junit.Assert; +import org.junit.Test; + +import com.coderising.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()); + frame.access(5); + Assert.assertEquals("5,4,0", frame.toString()); + } + +} From 439f1cef56f49b067d54a0c0adff1e41fedf91e6 Mon Sep 17 00:00:00 2001 From: Haochen <haochen_233333@163.com> Date: Sun, 9 Apr 2017 20:57:13 +0800 Subject: [PATCH 174/287] 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 <haochen_233333@163.com> Date: Sun, 9 Apr 2017 20:57:36 +0800 Subject: [PATCH 175/287] 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 <Authors name> + * @version 1.0 + * @since <pre>四月 9, 2017</pre> + */ +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 <haochen_233333@163.com> Date: Sun, 9 Apr 2017 21:00:39 +0800 Subject: [PATCH 176/287] 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<Integer, Constant> 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<Integer, ConstantParser> 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<Integer, Constant> 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("<init>", 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 79af98a164e14624ebee442700898460eb2a4647 Mon Sep 17 00:00:00 2001 From: onlyliuxin <14703250@qq.com> Date: Sun, 9 Apr 2017 21:19:48 +0800 Subject: [PATCH 177/287] =?UTF-8?q?=E4=B8=AD=E5=BA=8F=E8=A1=A8=E8=BE=BE?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coding/basic/stack/expr/InfixExpr.java | 18 +++++++ .../basic/stack/expr/InfixExprTest.java | 48 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 liuxin/data-structure/src/com/coding/basic/stack/expr/InfixExpr.java create mode 100644 liuxin/data-structure/src/com/coding/basic/stack/expr/InfixExprTest.java diff --git a/liuxin/data-structure/src/com/coding/basic/stack/expr/InfixExpr.java b/liuxin/data-structure/src/com/coding/basic/stack/expr/InfixExpr.java new file mode 100644 index 0000000000..0a145ff047 --- /dev/null +++ b/liuxin/data-structure/src/com/coding/basic/stack/expr/InfixExpr.java @@ -0,0 +1,18 @@ +package com.coding.basic.stack.expr; + +public class InfixExpr { + String expr = null; + + public InfixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + + return 0.0f; + } + + + + +} diff --git a/liuxin/data-structure/src/com/coding/basic/stack/expr/InfixExprTest.java b/liuxin/data-structure/src/com/coding/basic/stack/expr/InfixExprTest.java new file mode 100644 index 0000000000..92d130cddd --- /dev/null +++ b/liuxin/data-structure/src/com/coding/basic/stack/expr/InfixExprTest.java @@ -0,0 +1,48 @@ +package com.coding.basic.stack.expr; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class InfixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + //InfixExpr expr = new InfixExpr("300*20+12*5-20/4"); + { + InfixExpr expr = new InfixExpr("2+3*4+5"); + Assert.assertEquals(19.0, expr.evaluate(), 0.001f); + } + { + InfixExpr expr = new InfixExpr("3*20+12*5-40/2"); + Assert.assertEquals(100.0, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("3*20/2"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("20/2*3"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("10-30+50"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + } + +} From 2172f1432310190c6cd76d28972727cf5f51312f Mon Sep 17 00:00:00 2001 From: onlyliuxin <14703250@qq.com> Date: Sun, 9 Apr 2017 21:25:00 +0800 Subject: [PATCH 178/287] =?UTF-8?q?=E4=B8=8A=E4=BC=A0jvm=E7=AC=AC=E4=BA=8C?= =?UTF-8?q?=E6=AC=A1=E4=BD=9C=E4=B8=9A=E7=9A=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coderising/jvm/attr/AttributeInfo.java | 19 ++ .../src/com/coderising/jvm/attr/CodeAttr.java | 117 ++++++++++ .../coderising/jvm/attr/LineNumberTable.java | 65 ++++++ .../jvm/attr/LocalVariableItem.java | 39 ++++ .../jvm/attr/LocalVariableTable.java | 55 +++++ .../coderising/jvm/attr/StackMapTable.java | 30 +++ .../src/com/coderising/jvm/clz/ClassFile.java | 167 ++++++++------ .../src/com/coderising/jvm/field/Field.java | 51 ++++ .../jvm/loader/ByteCodeIterator.java | 62 ++++- .../jvm/loader/ClassFileParser.java | 218 ++++++++++++++---- .../src/com/coderising/jvm/method/Method.java | 94 ++++++++ .../jvm/test/ClassFileloaderTest.java | 75 ++++++ 12 files changed, 868 insertions(+), 124 deletions(-) create mode 100644 liuxin/mini-jvm/src/com/coderising/jvm/attr/AttributeInfo.java create mode 100644 liuxin/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java create mode 100644 liuxin/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java create mode 100644 liuxin/mini-jvm/src/com/coderising/jvm/attr/LocalVariableItem.java create mode 100644 liuxin/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java create mode 100644 liuxin/mini-jvm/src/com/coderising/jvm/attr/StackMapTable.java create mode 100644 liuxin/mini-jvm/src/com/coderising/jvm/field/Field.java create mode 100644 liuxin/mini-jvm/src/com/coderising/jvm/method/Method.java diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/attr/AttributeInfo.java b/liuxin/mini-jvm/src/com/coderising/jvm/attr/AttributeInfo.java new file mode 100644 index 0000000000..89fb53394e --- /dev/null +++ b/liuxin/mini-jvm/src/com/coderising/jvm/attr/AttributeInfo.java @@ -0,0 +1,19 @@ +package com.coderising.jvm.attr; + +public abstract class AttributeInfo { + public static final String CODE = "Code"; + public static final String CONST_VALUE = "ConstantValue"; + public static final String EXCEPTIONS = "Exceptions"; + public static final String LINE_NUM_TABLE = "LineNumberTable"; + public static final String LOCAL_VAR_TABLE = "LocalVariableTable"; + public static final String STACK_MAP_TABLE = "StackMapTable"; + int attrNameIndex; + int attrLen ; + public AttributeInfo(int attrNameIndex, int attrLen) { + + this.attrNameIndex = attrNameIndex; + this.attrLen = attrLen; + } + + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java b/liuxin/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java new file mode 100644 index 0000000000..f4cca587cb --- /dev/null +++ b/liuxin/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java @@ -0,0 +1,117 @@ +package com.coderising.jvm.attr; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.loader.ByteCodeIterator; + + +public class CodeAttr extends AttributeInfo { + private int maxStack ; + private int maxLocals ; + private int codeLen ; + private String code; + public String getCode() { + return code; + } + + //private ByteCodeCommand[] cmds ; + //public ByteCodeCommand[] getCmds() { + // return cmds; + //} + private LineNumberTable lineNumTable; + private LocalVariableTable localVarTable; + private StackMapTable stackMapTable; + + public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen,String code /*ByteCodeCommand[] cmds*/) { + super(attrNameIndex, attrLen); + this.maxStack = maxStack; + this.maxLocals = maxLocals; + this.codeLen = codeLen; + this.code = code; + //this.cmds = cmds; + } + + public void setLineNumberTable(LineNumberTable t) { + this.lineNumTable = t; + } + + public void setLocalVariableTable(LocalVariableTable t) { + this.localVarTable = t; + } + + public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ + + int attrNameIndex = iter.nextU2ToInt(); + int attrLen = iter.nextU4ToInt(); + int maxStack = iter.nextU2ToInt(); + int maxLocals = iter.nextU2ToInt(); + int codeLen = iter.nextU4ToInt(); + + String code = iter.nextUxToHexString(codeLen); + + System.out.println(code); + + //ByteCodeCommand[] cmds = ByteCodeCommand.parse(clzFile,code); + + CodeAttr codeAttr = new CodeAttr(attrNameIndex,attrLen, maxStack,maxLocals,codeLen,code); + + int exceptionTableLen = iter.nextU2ToInt(); + //TODO 处理exception + if(exceptionTableLen>0){ + String exTable = iter.nextUxToHexString(exceptionTableLen); + System.out.println("Encountered exception table , just ignore it :" + exTable); + + } + + + int subAttrCount = iter.nextU2ToInt(); + + for(int x=1; x<=subAttrCount; x++){ + int subAttrIndex = iter.nextU2ToInt(); + String subAttrName = clzFile.getConstantPool().getUTF8String(subAttrIndex); + + //已经向前移动了U2, 现在退回去。 + iter.back(2); + //line item table + if(AttributeInfo.LINE_NUM_TABLE.equalsIgnoreCase(subAttrName)){ + + LineNumberTable t = LineNumberTable.parse(iter); + codeAttr.setLineNumberTable(t); + } + else if(AttributeInfo.LOCAL_VAR_TABLE.equalsIgnoreCase(subAttrName)){ + LocalVariableTable t = LocalVariableTable.parse(iter); + codeAttr.setLocalVariableTable(t); + } + else if (AttributeInfo.STACK_MAP_TABLE.equalsIgnoreCase(subAttrName)){ + StackMapTable t = StackMapTable.parse(iter); + codeAttr.setStackMapTable(t); + } + else{ + throw new RuntimeException("Need code to process " + subAttrName); + } + + + } + + return codeAttr; + } + private void setStackMapTable(StackMapTable t) { + this.stackMapTable = t; + + } + + public String toString(ConstantPool pool){ + StringBuilder buffer = new StringBuilder(); + buffer.append("Code:").append(code).append("\n"); + /*for(int i=0;i<cmds.length;i++){ + buffer.append(cmds[i].toString(pool)).append("\n"); + }*/ + buffer.append("\n"); + buffer.append(this.lineNumTable.toString()); + buffer.append(this.localVarTable.toString(pool)); + return buffer.toString(); + } + + + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java b/liuxin/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java new file mode 100644 index 0000000000..1f8ff8b0e4 --- /dev/null +++ b/liuxin/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java @@ -0,0 +1,65 @@ +package com.coderising.jvm.attr; + +import java.util.ArrayList; +import java.util.List; + +import com.coderising.jvm.loader.ByteCodeIterator; + +public class LineNumberTable extends AttributeInfo { + List<LineNumberItem> items = new ArrayList<LineNumberItem>(); + + private static class LineNumberItem{ + int startPC; + int lineNum; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLineNum() { + return lineNum; + } + public void setLineNum(int lineNum) { + this.lineNum = lineNum; + } + } + public void addLineNumberItem(LineNumberItem item){ + this.items.add(item); + } + public LineNumberTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + + } + + public static LineNumberTable parse(ByteCodeIterator iter){ + + int index = iter.nextU2ToInt(); + int len = iter.nextU4ToInt(); + + LineNumberTable table = new LineNumberTable(index,len); + + int itemLen = iter.nextU2ToInt(); + + for(int i=1; i<=itemLen; i++){ + LineNumberItem item = new LineNumberItem(); + item.setStartPC(iter.nextU2ToInt()); + item.setLineNum(iter.nextU2ToInt()); + table.addLineNumberItem(item); + } + return table; + } + + public String toString(){ + StringBuilder buffer = new StringBuilder(); + buffer.append("Line Number Table:\n"); + for(LineNumberItem item : items){ + buffer.append("startPC:"+item.getStartPC()).append(","); + buffer.append("lineNum:"+item.getLineNum()).append("\n"); + } + buffer.append("\n"); + return buffer.toString(); + + } + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/attr/LocalVariableItem.java b/liuxin/mini-jvm/src/com/coderising/jvm/attr/LocalVariableItem.java new file mode 100644 index 0000000000..3eb2654e36 --- /dev/null +++ b/liuxin/mini-jvm/src/com/coderising/jvm/attr/LocalVariableItem.java @@ -0,0 +1,39 @@ +package com.coderising.jvm.attr; + +public class LocalVariableItem { + private int startPC; + private int length; + private int nameIndex; + private int descIndex; + private int index; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getNameIndex() { + return nameIndex; + } + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + public int getDescIndex() { + return descIndex; + } + public void setDescIndex(int descIndex) { + this.descIndex = descIndex; + } + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java b/liuxin/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java new file mode 100644 index 0000000000..00b3857849 --- /dev/null +++ b/liuxin/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java @@ -0,0 +1,55 @@ +package com.coderising.jvm.attr; + + +import java.util.ArrayList; +import java.util.List; + +import com.coderising.jvm.constant.ConstantPool; + +import com.coderising.jvm.loader.ByteCodeIterator; + +public class LocalVariableTable extends AttributeInfo{ + + List<LocalVariableItem> items = new ArrayList<LocalVariableItem>(); + + public LocalVariableTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static LocalVariableTable parse(ByteCodeIterator iter){ + + int index = iter.nextU2ToInt(); + int len = iter.nextU4ToInt(); + + LocalVariableTable table = new LocalVariableTable(index,len); + + int itemLen = iter.nextU2ToInt(); + + for(int i=1; i<=itemLen; i++){ + LocalVariableItem item = new LocalVariableItem(); + item.setStartPC(iter.nextU2ToInt()); + item.setLength(iter.nextU2ToInt()); + item.setNameIndex(iter.nextU2ToInt()); + item.setDescIndex(iter.nextU2ToInt()); + item.setIndex(iter.nextU2ToInt()); + table.addLocalVariableItem(item); + } + return table; + } + private void addLocalVariableItem(LocalVariableItem item) { + this.items.add(item); + } + + public String toString(ConstantPool pool){ + StringBuilder buffer = new StringBuilder(); + buffer.append("Local Variable Table:\n"); + for(LocalVariableItem item : items){ + buffer.append("startPC:"+item.getStartPC()).append(","); + buffer.append("name:"+pool.getUTF8String(item.getNameIndex())).append(","); + buffer.append("desc:"+pool.getUTF8String(item.getDescIndex())).append(","); + buffer.append("slotIndex:"+ item.getIndex()).append("\n"); + } + buffer.append("\n"); + return buffer.toString(); + } +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/attr/StackMapTable.java b/liuxin/mini-jvm/src/com/coderising/jvm/attr/StackMapTable.java new file mode 100644 index 0000000000..44c5d90d46 --- /dev/null +++ b/liuxin/mini-jvm/src/com/coderising/jvm/attr/StackMapTable.java @@ -0,0 +1,30 @@ +package com.coderising.jvm.attr; + + +import com.coderising.jvm.loader.ByteCodeIterator; + +public class StackMapTable extends AttributeInfo{ + + private String originalCode; + + public StackMapTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static StackMapTable parse(ByteCodeIterator iter){ + int index = iter.nextU2ToInt(); + int len = iter.nextU4ToInt(); + StackMapTable t = new StackMapTable(index,len); + + //后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 + String code = iter.nextUxToHexString(len); + t.setOriginalCode(code); + + return t; + } + + private void setOriginalCode(String code) { + this.originalCode = code; + + } +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java b/liuxin/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java index 650ca8375d..c21a0988e5 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java @@ -1,75 +1,92 @@ -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(); - } -} +package com.coderising.jvm.clz; + +import java.util.ArrayList; +import java.util.List; + +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.field.Field; +import com.coderising.jvm.method.Method; + +public class ClassFile { + + private int minorVersion; + private int majorVersion; + + private AccessFlag accessFlag; + private ClassIndex clzIndex; + private ConstantPool pool; + private List<Field> fields = new ArrayList<Field>(); + private List<Method> methods = new ArrayList<Method>(); + + 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 addField(Field f){ + this.fields.add(f); + } + public List<Field> getFields(){ + return this.fields; + } + public void addMethod(Method m){ + this.methods.add(m); + } + public List<Method> getMethods() { + return methods; + } + + + 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/liuxin/mini-jvm/src/com/coderising/jvm/field/Field.java b/liuxin/mini-jvm/src/com/coderising/jvm/field/Field.java new file mode 100644 index 0000000000..bb4460867b --- /dev/null +++ b/liuxin/mini-jvm/src/com/coderising/jvm/field/Field.java @@ -0,0 +1,51 @@ +package com.coderising.jvm.field; + +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.UTF8Info; +import com.coderising.jvm.loader.ByteCodeIterator; + + +public class Field { + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + + + private ConstantPool pool; + + public Field( int accessFlag, int nameIndex, int descriptorIndex,ConstantPool pool) { + + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + this.pool = pool; + } + + + + public String toString() { + String name = ((UTF8Info)pool.getConstantInfo(this.nameIndex)).getValue(); + + String desc = ((UTF8Info)pool.getConstantInfo(this.descriptorIndex)).getValue(); + return name +":"+ desc; + } + + public static Field parse(ConstantPool pool,ByteCodeIterator iter){ + + int accessFlag = iter.nextU2ToInt(); + int nameIndex = iter.nextU2ToInt(); + int descIndex = iter.nextU2ToInt(); + int attribCount = iter.nextU2ToInt(); + System.out.println("field attribute count:"+ attribCount); + + Field f = new Field(accessFlag, nameIndex, descIndex,pool); + + if(attribCount > 0){ + throw new RuntimeException("Field Attribute has not been implemented"); + } + + return f; + } + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java b/liuxin/mini-jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java index 9c9fac2839..5c5173fbe8 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java @@ -1,5 +1,57 @@ -package com.coderising.jvm.loader; - -public class ByteCodeIterator { - -} +package com.coderising.jvm.loader; + +import java.util.Arrays; + +import com.coderising.jvm.util.Util; + +public class ByteCodeIterator { + byte[] codes; + int pos = 0; + + ByteCodeIterator(byte[] codes) { + this.codes = codes; + } + + + + 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; + } + + 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 nextUxToHexString(int len) { + byte[] tmp = new byte[len]; + + for (int i = 0; i < len; i++) { + tmp[i] = codes[pos++]; + } + return Util.byteToHexString(tmp).toLowerCase(); + + } + + public void back(int n) { + this.pos -= n; + } +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java b/liuxin/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java index 8e29f14a0c..0b272510a5 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java @@ -1,44 +1,174 @@ -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; - } - - -} +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; +import com.coderising.jvm.field.Field; +import com.coderising.jvm.method.Method; + +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); + + AccessFlag flag = parseAccessFlag(iter); + clzFile.setAccessFlag(flag); + + ClassIndex clzIndex = parseClassInfex(iter); + clzFile.setClassIndex(clzIndex); + + parseInterfaces(iter); + + parseFileds(clzFile, iter); + + parseMethods(clzFile, iter); + + return clzFile; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + + AccessFlag flag = new AccessFlag(iter.nextU2ToInt()); + // System.out.println("Is public class: " + flag.isPublicClass()); + // System.out.println("Is final class : " + flag.isFinalClass()); + + return flag; + } + + private ClassIndex parseClassInfex(ByteCodeIterator iter) { + + int thisClassIndex = iter.nextU2ToInt(); + int superClassIndex = iter.nextU2ToInt(); + + ClassIndex clzIndex = new ClassIndex(); + + clzIndex.setThisClassIndex(thisClassIndex); + clzIndex.setSuperClassIndex(superClassIndex); + + return clzIndex; + + } + + private ConstantPool parseConstantPool(ByteCodeIterator iter) { + + int constPoolCount = iter.nextU2ToInt(); + + System.out.println("Constant Pool Count :" + constPoolCount); + + ConstantPool pool = new ConstantPool(); + + 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); + + pool.addConstantInfo(clzInfo); + } else if (tag == 1) { + // UTF-8 String + int len = iter.nextU2ToInt(); + byte[] data = iter.getBytes(len); + String value = null; + try { + value = new String(data, "UTF-8"); + } catch (UnsupportedEncodingException e) { + 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) { + // MethodRef + MethodRefInfo method = new MethodRefInfo(pool); + method.setClassInfoIndex(iter.nextU2ToInt()); + method.setNameAndTypeIndex(iter.nextU2ToInt()); + pool.addConstantInfo(method); + } else if (tag == 12) { + // Name and Type Info + NameAndTypeInfo nameType = new NameAndTypeInfo(pool); + nameType.setIndex1(iter.nextU2ToInt()); + nameType.setIndex2(iter.nextU2ToInt()); + pool.addConstantInfo(nameType); + } else { + throw new RuntimeException("the constant pool tag " + tag + " has not been implemented yet."); + } + } + + System.out.println("Finished reading Constant pool "); + + return pool; + } + private void parseInterfaces(ByteCodeIterator iter) { + int interfaceCount = iter.nextU2ToInt(); + + System.out.println("interfaceCount:" + interfaceCount); + + // TODO : 如果实现了interface, 这里需要解析 + } + + private void parseFileds(ClassFile clzFile, ByteCodeIterator iter) { + int fieldCount = iter.nextU2ToInt(); + System.out.println("Field count:" + fieldCount); + for (int i = 1; i <= fieldCount; i++) { + Field f = Field.parse(clzFile.getConstantPool(), iter); + clzFile.addField(f); + + } + + } + + private void parseMethods(ClassFile clzFile, ByteCodeIterator iter) { + + int methodCount = iter.nextU2ToInt(); + + for (int i = 1; i <= methodCount; i++) { + Method m = Method.parse(clzFile, iter); + clzFile.addMethod(m); + } + + } + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/method/Method.java b/liuxin/mini-jvm/src/com/coderising/jvm/method/Method.java new file mode 100644 index 0000000000..4b30826abe --- /dev/null +++ b/liuxin/mini-jvm/src/com/coderising/jvm/method/Method.java @@ -0,0 +1,94 @@ +package com.coderising.jvm.method; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.attr.AttributeInfo; +import com.coderising.jvm.attr.CodeAttr; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.UTF8Info; +import com.coderising.jvm.loader.ByteCodeIterator; + + + +public class Method { + + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private CodeAttr codeAttr; + + private ClassFile clzFile; + + + public ClassFile getClzFile() { + return clzFile; + } + + public int getNameIndex() { + return nameIndex; + } + public int getDescriptorIndex() { + return descriptorIndex; + } + + public CodeAttr getCodeAttr() { + return codeAttr; + } + + public void setCodeAttr(CodeAttr code) { + this.codeAttr = code; + } + + public Method(ClassFile clzFile,int accessFlag, int nameIndex, int descriptorIndex) { + this.clzFile = clzFile; + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + } + + + + public String toString() { + + ConstantPool pool = this.clzFile.getConstantPool(); + StringBuilder buffer = new StringBuilder(); + + String name = ((UTF8Info)pool.getConstantInfo(this.nameIndex)).getValue(); + + String desc = ((UTF8Info)pool.getConstantInfo(this.descriptorIndex)).getValue(); + + buffer.append(name).append(":").append(desc).append("\n"); + + buffer.append(this.codeAttr.toString(pool)); + + return buffer.toString(); + } + + public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ + int accessFlag = iter.nextU2ToInt(); + int nameIndex = iter.nextU2ToInt(); + int descIndex = iter.nextU2ToInt(); + int attribCount = iter.nextU2ToInt(); + + + Method m = new Method(clzFile, accessFlag, nameIndex, descIndex); + + for( int j=1; j<= attribCount; j++){ + + int attrNameIndex = iter.nextU2ToInt(); + String attrName = clzFile.getConstantPool().getUTF8String(attrNameIndex); + iter.back(2); + + if(AttributeInfo.CODE.equalsIgnoreCase(attrName)){ + CodeAttr codeAttr = CodeAttr.parse(clzFile, iter); + m.setCodeAttr(codeAttr); + } else{ + throw new RuntimeException("only CODE attribute is implemented , please implement the "+ attrName); + } + + } + //System.out.println("method:"+ m.toString(clzFile.getConstPool())); + return m ; + + } +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java b/liuxin/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java index 4ac0698801..c29ff5181f 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -1,5 +1,7 @@ package com.coderising.jvm.test; +import java.util.List; + import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -12,7 +14,9 @@ import com.coderising.jvm.constant.MethodRefInfo; import com.coderising.jvm.constant.NameAndTypeInfo; import com.coderising.jvm.constant.UTF8Info; +import com.coderising.jvm.field.Field; import com.coderising.jvm.loader.ClassFileLoader; +import com.coderising.jvm.method.Method; @@ -196,7 +200,78 @@ public void testClassIndex(){ Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); } + + /** + * 下面是第三次JVM课应实现的测试用例 + */ + @Test + public void testReadFields(){ + + List<Field> fields = clzFile.getFields(); + Assert.assertEquals(2, fields.size()); + { + Field f = fields.get(0); + Assert.assertEquals("name:Ljava/lang/String;", f.toString()); + } + { + Field f = fields.get(1); + Assert.assertEquals("age:I", f.toString()); + } + } + @Test + public void testMethods(){ + + List<Method> methods = clzFile.getMethods(); + ConstantPool pool = clzFile.getConstantPool(); + + { + Method m = methods.get(0); + assertMethodEquals(pool,m, + "<init>", + "(Ljava/lang/String;I)V", + "2ab7000c2a2bb5000f2a1cb50011b1"); + + } + { + Method m = methods.get(1); + assertMethodEquals(pool,m, + "setName", + "(Ljava/lang/String;)V", + "2a2bb5000fb1"); + + } + { + Method m = methods.get(2); + assertMethodEquals(pool,m, + "setAge", + "(I)V", + "2a1bb50011b1"); + } + { + Method m = methods.get(3); + assertMethodEquals(pool,m, + "sayHello", + "()V", + "b2001c1222b60024b1"); + + } + { + Method m = methods.get(4); + assertMethodEquals(pool,m, + "main", + "([Ljava/lang/String;)V", + "bb000159122b101db7002d4c2bb6002fb1"); + } + } + private void assertMethodEquals(ConstantPool pool,Method m , String expectedName, String expectedDesc,String expectedCode){ + String methodName = pool.getUTF8String(m.getNameIndex()); + String methodDesc = pool.getUTF8String(m.getDescriptorIndex()); + String code = m.getCodeAttr().getCode(); + Assert.assertEquals(expectedName, methodName); + Assert.assertEquals(expectedDesc, methodDesc); + Assert.assertEquals(expectedCode, code); + } } From 73fcf9f2f91279c05325d21e3bfdecaff28dfe6b Mon Sep 17 00:00:00 2001 From: Korben_CHY <korben.chy@gmail.com> Date: Sun, 9 Apr 2017 21:28:16 +0800 Subject: [PATCH 179/287] 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<T> { +public class Stack<T> { 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<Integer> stack; +public class StackTest { + private Stack<Integer> 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 f462045656cd5a61f7a7a4cb33c3e8705ee906ec Mon Sep 17 00:00:00 2001 From: onlyliuxin <14703250@qq.com> Date: Sun, 9 Apr 2017 21:30:03 +0800 Subject: [PATCH 180/287] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E7=AC=AC=E4=BA=8C?= =?UTF-8?q?=E6=AC=A1=E4=BD=9C=E4=B8=9A=E7=9A=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/com/coderising/jvm/attr/CodeAttr.java | 65 +------------------ .../coderising/jvm/attr/LineNumberTable.java | 27 +------- .../jvm/attr/LocalVariableTable.java | 31 +-------- .../src/com/coderising/jvm/field/Field.java | 20 +----- .../jvm/loader/ClassFileParser.java | 27 +------- .../src/com/coderising/jvm/method/Method.java | 41 +----------- 6 files changed, 11 insertions(+), 200 deletions(-) diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java b/liuxin/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java index f4cca587cb..b0c67b4b93 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java @@ -41,76 +41,15 @@ public void setLocalVariableTable(LocalVariableTable t) { public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ - int attrNameIndex = iter.nextU2ToInt(); - int attrLen = iter.nextU4ToInt(); - int maxStack = iter.nextU2ToInt(); - int maxLocals = iter.nextU2ToInt(); - int codeLen = iter.nextU4ToInt(); - String code = iter.nextUxToHexString(codeLen); - - System.out.println(code); - - //ByteCodeCommand[] cmds = ByteCodeCommand.parse(clzFile,code); - - CodeAttr codeAttr = new CodeAttr(attrNameIndex,attrLen, maxStack,maxLocals,codeLen,code); - - int exceptionTableLen = iter.nextU2ToInt(); - //TODO 处理exception - if(exceptionTableLen>0){ - String exTable = iter.nextUxToHexString(exceptionTableLen); - System.out.println("Encountered exception table , just ignore it :" + exTable); - - } - - - int subAttrCount = iter.nextU2ToInt(); - - for(int x=1; x<=subAttrCount; x++){ - int subAttrIndex = iter.nextU2ToInt(); - String subAttrName = clzFile.getConstantPool().getUTF8String(subAttrIndex); - - //已经向前移动了U2, 现在退回去。 - iter.back(2); - //line item table - if(AttributeInfo.LINE_NUM_TABLE.equalsIgnoreCase(subAttrName)){ - - LineNumberTable t = LineNumberTable.parse(iter); - codeAttr.setLineNumberTable(t); - } - else if(AttributeInfo.LOCAL_VAR_TABLE.equalsIgnoreCase(subAttrName)){ - LocalVariableTable t = LocalVariableTable.parse(iter); - codeAttr.setLocalVariableTable(t); - } - else if (AttributeInfo.STACK_MAP_TABLE.equalsIgnoreCase(subAttrName)){ - StackMapTable t = StackMapTable.parse(iter); - codeAttr.setStackMapTable(t); - } - else{ - throw new RuntimeException("Need code to process " + subAttrName); - } - - - } - - return codeAttr; + return null; } private void setStackMapTable(StackMapTable t) { this.stackMapTable = t; } - public String toString(ConstantPool pool){ - StringBuilder buffer = new StringBuilder(); - buffer.append("Code:").append(code).append("\n"); - /*for(int i=0;i<cmds.length;i++){ - buffer.append(cmds[i].toString(pool)).append("\n"); - }*/ - buffer.append("\n"); - buffer.append(this.lineNumTable.toString()); - buffer.append(this.localVarTable.toString(pool)); - return buffer.toString(); - } + diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java b/liuxin/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java index 1f8ff8b0e4..22941f83b1 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java @@ -34,32 +34,9 @@ public LineNumberTable(int attrNameIndex, int attrLen) { public static LineNumberTable parse(ByteCodeIterator iter){ - int index = iter.nextU2ToInt(); - int len = iter.nextU4ToInt(); - - LineNumberTable table = new LineNumberTable(index,len); - - int itemLen = iter.nextU2ToInt(); - - for(int i=1; i<=itemLen; i++){ - LineNumberItem item = new LineNumberItem(); - item.setStartPC(iter.nextU2ToInt()); - item.setLineNum(iter.nextU2ToInt()); - table.addLineNumberItem(item); - } - return table; + return null; } - public String toString(){ - StringBuilder buffer = new StringBuilder(); - buffer.append("Line Number Table:\n"); - for(LineNumberItem item : items){ - buffer.append("startPC:"+item.getStartPC()).append(","); - buffer.append("lineNum:"+item.getLineNum()).append("\n"); - } - buffer.append("\n"); - return buffer.toString(); - - } + } diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java b/liuxin/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java index 00b3857849..fa69dc9bdb 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java @@ -18,38 +18,11 @@ public LocalVariableTable(int attrNameIndex, int attrLen) { public static LocalVariableTable parse(ByteCodeIterator iter){ - int index = iter.nextU2ToInt(); - int len = iter.nextU4ToInt(); - - LocalVariableTable table = new LocalVariableTable(index,len); - - int itemLen = iter.nextU2ToInt(); - - for(int i=1; i<=itemLen; i++){ - LocalVariableItem item = new LocalVariableItem(); - item.setStartPC(iter.nextU2ToInt()); - item.setLength(iter.nextU2ToInt()); - item.setNameIndex(iter.nextU2ToInt()); - item.setDescIndex(iter.nextU2ToInt()); - item.setIndex(iter.nextU2ToInt()); - table.addLocalVariableItem(item); - } - return table; + return null; } private void addLocalVariableItem(LocalVariableItem item) { this.items.add(item); } - public String toString(ConstantPool pool){ - StringBuilder buffer = new StringBuilder(); - buffer.append("Local Variable Table:\n"); - for(LocalVariableItem item : items){ - buffer.append("startPC:"+item.getStartPC()).append(","); - buffer.append("name:"+pool.getUTF8String(item.getNameIndex())).append(","); - buffer.append("desc:"+pool.getUTF8String(item.getDescIndex())).append(","); - buffer.append("slotIndex:"+ item.getIndex()).append("\n"); - } - buffer.append("\n"); - return buffer.toString(); - } + } diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/field/Field.java b/liuxin/mini-jvm/src/com/coderising/jvm/field/Field.java index bb4460867b..09bae5a1ae 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/field/Field.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/field/Field.java @@ -24,28 +24,10 @@ public Field( int accessFlag, int nameIndex, int descriptorIndex,ConstantPool po - public String toString() { - String name = ((UTF8Info)pool.getConstantInfo(this.nameIndex)).getValue(); - - String desc = ((UTF8Info)pool.getConstantInfo(this.descriptorIndex)).getValue(); - return name +":"+ desc; - } public static Field parse(ConstantPool pool,ByteCodeIterator iter){ - int accessFlag = iter.nextU2ToInt(); - int nameIndex = iter.nextU2ToInt(); - int descIndex = iter.nextU2ToInt(); - int attribCount = iter.nextU2ToInt(); - System.out.println("field attribute count:"+ attribCount); - - Field f = new Field(accessFlag, nameIndex, descIndex,pool); - - if(attribCount > 0){ - throw new RuntimeException("Field Attribute has not been implemented"); - } - - return f; + return null; } } diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java b/liuxin/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java index 0b272510a5..444ec4c60d 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java @@ -45,10 +45,7 @@ public ClassFile parse(byte[] codes) { parseInterfaces(iter); - parseFileds(clzFile, iter); - - parseMethods(clzFile, iter); - + return clzFile; } @@ -149,26 +146,6 @@ private void parseInterfaces(ByteCodeIterator iter) { // TODO : 如果实现了interface, 这里需要解析 } - private void parseFileds(ClassFile clzFile, ByteCodeIterator iter) { - int fieldCount = iter.nextU2ToInt(); - System.out.println("Field count:" + fieldCount); - for (int i = 1; i <= fieldCount; i++) { - Field f = Field.parse(clzFile.getConstantPool(), iter); - clzFile.addField(f); - - } - - } - - private void parseMethods(ClassFile clzFile, ByteCodeIterator iter) { - - int methodCount = iter.nextU2ToInt(); - - for (int i = 1; i <= methodCount; i++) { - Method m = Method.parse(clzFile, iter); - clzFile.addMethod(m); - } - - } + } diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/method/Method.java b/liuxin/mini-jvm/src/com/coderising/jvm/method/Method.java index 4b30826abe..ba5f7848d1 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/method/Method.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/method/Method.java @@ -48,47 +48,10 @@ public Method(ClassFile clzFile,int accessFlag, int nameIndex, int descriptorInd - public String toString() { - - ConstantPool pool = this.clzFile.getConstantPool(); - StringBuilder buffer = new StringBuilder(); - - String name = ((UTF8Info)pool.getConstantInfo(this.nameIndex)).getValue(); - - String desc = ((UTF8Info)pool.getConstantInfo(this.descriptorIndex)).getValue(); - - buffer.append(name).append(":").append(desc).append("\n"); - - buffer.append(this.codeAttr.toString(pool)); - - return buffer.toString(); - } + public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ - int accessFlag = iter.nextU2ToInt(); - int nameIndex = iter.nextU2ToInt(); - int descIndex = iter.nextU2ToInt(); - int attribCount = iter.nextU2ToInt(); - - - Method m = new Method(clzFile, accessFlag, nameIndex, descIndex); - - for( int j=1; j<= attribCount; j++){ - - int attrNameIndex = iter.nextU2ToInt(); - String attrName = clzFile.getConstantPool().getUTF8String(attrNameIndex); - iter.back(2); - - if(AttributeInfo.CODE.equalsIgnoreCase(attrName)){ - CodeAttr codeAttr = CodeAttr.parse(clzFile, iter); - m.setCodeAttr(codeAttr); - } else{ - throw new RuntimeException("only CODE attribute is implemented , please implement the "+ attrName); - } - - } - //System.out.println("method:"+ m.toString(clzFile.getConstPool())); - return m ; + return null; } } From e16c31d7b8dc9e92abdb9ae23f6ee9e5dee643d9 Mon Sep 17 00:00:00 2001 From: <onlyLYJ@382266293@qq.com> Date: Sun, 9 Apr 2017 21:40:11 +0800 Subject: [PATCH 181/287] 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 <xuweijay@163.com> Date: Sun, 9 Apr 2017 21:41:36 +0800 Subject: [PATCH 182/287] 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 @@ <component name="ProjectModuleManager"> <modules> <module fileurl="file://$PROJECT_DIR$/1511_714512544.iml" filepath="$PROJECT_DIR$/1511_714512544.iml" /> + <module fileurl="file://$PROJECT_DIR$/src/com/coderising/miniJVM.iml" filepath="$PROJECT_DIR$/src/com/coderising/miniJVM.iml" /> </modules> </component> </project> \ 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 @@ <?xml version="1.0" encoding="UTF-8"?> <project version="4"> <component name="ChangeListManager"> - <list default="true" id="d338ed3a-e900-486a-89a5-3e8b0a3835ed" name="Default" comment=""> - <change type="MODIFICATION" beforePath="$PROJECT_DIR$/out/production/1511_714512544/com/coderising/download/FileDownloader.class" afterPath="$PROJECT_DIR$/out/production/1511_714512544/com/coderising/download/FileDownloader.class" /> - <change type="MODIFICATION" beforePath="$PROJECT_DIR$/out/production/1511_714512544/com/coderising/download/FileDownloaderTest.class" afterPath="$PROJECT_DIR$/out/production/1511_714512544/com/coderising/download/FileDownloaderTest.class" /> - <change type="MODIFICATION" beforePath="$PROJECT_DIR$/.idea/workspace.xml" afterPath="$PROJECT_DIR$/.idea/workspace.xml" /> -<<<<<<< HEAD - <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/com/coderising/download/FileDownloader.java" afterPath="$PROJECT_DIR$/src/com/coderising/download/FileDownloader.java" /> - <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/com/coderising/download/FileDownloaderTest.java" afterPath="$PROJECT_DIR$/src/com/coderising/download/FileDownloaderTest.java" /> - <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/com/coderising/download/impl/ConnectionImpl.java" afterPath="$PROJECT_DIR$/src/com/coderising/download/impl/ConnectionImpl.java" /> -======= ->>>>>>> refs/remotes/origin/master + <list default="true" id="70c62334-5fd5-4cc1-80de-4d49703ede17" name="Default" comment=""> + <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/com/coderising/jvm/clz/AccessFlag.java" /> + <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/com/coderising/jvm/clz/ClassFile.java" /> + <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/com/coderising/jvm/clz/ClassIndex.java" /> + <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/com/coderising/jvm/constant/ClassInfo.java" /> + <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/com/coderising/jvm/constant/ConstantInfo.java" /> + <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/com/coderising/jvm/constant/ConstantPool.java" /> + <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/com/coderising/jvm/constant/FieldRefInfo.java" /> + <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/com/coderising/jvm/constant/MethodRefInfo.java" /> + <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/com/coderising/jvm/constant/NameAndTypeInfo.java" /> + <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/com/coderising/jvm/constant/NullConstantInfo.java" /> + <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/com/coderising/jvm/constant/StringInfo.java" /> + <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/com/coderising/jvm/constant/UTF8Info.java" /> + <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/com/coderising/jvm/loader/ByteCodeIterator.java" /> + <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/com/coderising/jvm/loader/ClassFileLoader.java" /> + <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/com/coderising/jvm/loader/ClassFileParser.java" /> + <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/com/coderising/jvm/test/ClassFileloaderTest.java" /> + <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/com/coderising/jvm/test/EmployeeV1.java" /> + <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/com/coderising/jvm/util/Util.java" /> + <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/com/coding/basic/LRUPageFrame.java" /> + <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/com/coding/basic/LRUPageFrameTest.java" /> + <change type="DELETED" beforePath="$PROJECT_DIR$/.idea/workspace.xml" afterPath="" /> + <change type="MODIFICATION" beforePath="$PROJECT_DIR$/.idea/modules.xml" afterPath="$PROJECT_DIR$/.idea/modules.xml" /> </list> <ignored path="$PROJECT_DIR$/out/" /> <option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" /> @@ -20,31 +33,32 @@ <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" /> <option name="LAST_RESOLUTION" value="IGNORE" /> </component> - <component name="CreatePatchCommitExecutor"> - <option name="PATCH_PATH" value="" /> - </component> - <component name="DatabaseView"> - <option name="GROUP_SCHEMA" value="true" /> - <option name="GROUP_CONTENTS" value="false" /> - <option name="SORT_POSITIONED" value="false" /> - <option name="SHOW_TABLE_DETAILS" value="true" /> - <option name="SHOW_EMPTY_GROUPS" value="false" /> - <option name="AUTO_SCROLL_FROM_SOURCE" value="false" /> - </component> <component name="ExecutionTargetManager" SELECTED_TARGET="default_target" /> - <component name="FavoritesManager"> - <favorites_list name="1511_714512544" /> - </component> <component name="FileEditorManager"> - <leaf /> - </component> - <component name="FileTemplateManagerImpl"> - <option name="RECENT_TEMPLATES"> - <list> - <option value="Class" /> - <option value="JUnit4 Test Class" /> - </list> - </option> + <leaf> + <file leaf-file-name="EmployeeV1.java" pinned="false" current-in-tab="false"> + <entry file="file://$PROJECT_DIR$/src/com/coderising/jvm/test/EmployeeV1.java"> + <provider selected="true" editor-type-id="text-editor"> + <state relative-caret-position="198"> + <caret line="9" column="31" lean-forward="true" selection-start-line="9" selection-start-column="31" selection-end-line="9" selection-end-column="31" /> + <folding /> + </state> + </provider> + </entry> + </file> + <file leaf-file-name="ClassFileloaderTest.java" pinned="false" current-in-tab="true"> + <entry file="file://$PROJECT_DIR$/src/com/coderising/jvm/test/ClassFileloaderTest.java"> + <provider selected="true" editor-type-id="text-editor"> + <state relative-caret-position="44"> + <caret line="2" column="7" lean-forward="true" selection-start-line="2" selection-start-column="7" selection-end-line="2" selection-end-column="7" /> + <folding> + <element signature="imports" expanded="true" /> + </folding> + </state> + </provider> + </entry> + </file> + </leaf> </component> <component name="Git.Settings"> <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/../.." /> @@ -57,25 +71,15 @@ <component name="IdeDocumentHistory"> <option name="CHANGED_PATHS"> <list> - <option value="$PROJECT_DIR$/src/com/coding/basic/List.java" /> - <option value="$PROJECT_DIR$/src/test/com/coding/basic/LinkedListTest.java" /> - <option value="$PROJECT_DIR$/src/com/coding/basic/LinkedList.java" /> - <option value="$PROJECT_DIR$/src/demo/Demo.java" /> - <option value="$PROJECT_DIR$/src/com/coderising/download/Demo.java" /> - <option value="$PROJECT_DIR$/src/com/coderising/array/ArrayUtil.java" /> - <option value="$PROJECT_DIR$/文章地址.md" /> - <option value="$PROJECT_DIR$/src/com/coderising/download/api/Connection.java" /> - <option value="$PROJECT_DIR$/src/test/com/coding/basic/BinarySearchTreeTest.java" /> - <option value="$PROJECT_DIR$/src/com/coding/basic/ReConstructBSTTest.groovy" /> - <option value="$PROJECT_DIR$/src/com/coderising/download/impl/ConnectionManagerImpl.java" /> - <option value="$PROJECT_DIR$/src/com/coderising/download/ConnectionTest.java" /> - <option value="$PROJECT_DIR$/src/com/coderising/download/DownloadThread.java" /> - <option value="$PROJECT_DIR$/src/com/coding/basic/ReConstructBSTTest.java" /> - <option value="$PROJECT_DIR$/src/com/coding/basic/BinarySearchTree.java" /> - <option value="$PROJECT_DIR$/src/com/coding/basic/ReConstructBST.java" /> - <option value="$PROJECT_DIR$/src/com/coderising/download/impl/ConnectionImpl.java" /> - <option value="$PROJECT_DIR$/src/com/coderising/download/FileDownloaderTest.java" /> - <option value="$PROJECT_DIR$/src/com/coderising/download/FileDownloader.java" /> + <option value="$PROJECT_DIR$/src/com/coderising/miniJVM/test/EmployeeV1.java" /> + <option value="$PROJECT_DIR$/src/com/coderising/miniJVM/util/Util.java" /> + <option value="$PROJECT_DIR$/src/com/coderising/miniJVM/test/ClassFileloaderTest.java" /> + <option value="$PROJECT_DIR$/src/com/coding/basic/LRUPageFrame.java" /> + <option value="$PROJECT_DIR$/src/com/coding/basic/LRUPageFrameTest.java" /> + <option value="$PROJECT_DIR$/src/com/coderising/minJVM/clz/ClassFile.java" /> + <option value="$PROJECT_DIR$/src/com/coderising/jvm/clz/ClassFile.java" /> + <option value="$PROJECT_DIR$/src/com/coderising/jvm/test/ClassFileloaderTest.java" /> + <option value="$PROJECT_DIR$/src/com/coderising/jvm/test/EmployeeV1.java" /> </list> </option> </component> @@ -91,9 +95,12 @@ <option name="width" value="1938" /> <option name="height" value="1048" /> </component> + <component name="ProjectLevelVcsManager"> + <ConfirmationsSetting value="2" id="Add" /> + </component> <component name="ProjectView"> <navigator currentView="ProjectPane" proportions="" version="1"> - <flattenPackages ProjectPane="true" /> + <flattenPackages ProjectPane="false" /> <showMembers /> <showModules /> <showLibraryContents /> @@ -106,13 +113,8 @@ <foldersAlwaysOnTop value="true" /> </navigator> <panes> -<<<<<<< HEAD - <pane id="Scratches" /> -======= <pane id="Scope" /> <pane id="Scratches" /> - <pane id="PackagesPane" /> ->>>>>>> refs/remotes/origin/master <pane id="ProjectPane"> <subPane> <PATH> @@ -153,44 +155,247 @@ <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> </PATH_ELEMENT> <PATH_ELEMENT> - <option name="myItemId" value="basic" /> + <option name="myItemId" value="com" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + </PATH> + <PATH> + <PATH_ELEMENT> + <option name="myItemId" value="1511_714512544" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="1511_714512544" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="src" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="com" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="coderising" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + </PATH> + <PATH> + <PATH_ELEMENT> + <option name="myItemId" value="1511_714512544" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="1511_714512544" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="src" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="com" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="coderising" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="jvm" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + </PATH> + <PATH> + <PATH_ELEMENT> + <option name="myItemId" value="1511_714512544" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="1511_714512544" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="src" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="com" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="coderising" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="jvm" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="test" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + </PATH> + <PATH> + <PATH_ELEMENT> + <option name="myItemId" value="1511_714512544" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="1511_714512544" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="out" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="production" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="1511_714512544" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="test" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="com" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="coding" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + </PATH> + <PATH> + <PATH_ELEMENT> + <option name="myItemId" value="1511_714512544" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="1511_714512544" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="out" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="production" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="1511_714512544" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="com" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + </PATH> + <PATH> + <PATH_ELEMENT> + <option name="myItemId" value="1511_714512544" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="1511_714512544" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="out" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="production" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="1511_714512544" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="com" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="coderising" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + </PATH> + <PATH> + <PATH_ELEMENT> + <option name="myItemId" value="1511_714512544" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="1511_714512544" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="out" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="production" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="1511_714512544" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="com" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="coderising" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="jvm" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="test" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + </PATH> + <PATH> + <PATH_ELEMENT> + <option name="myItemId" value="1511_714512544" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="1511_714512544" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value=".idea" /> <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> </PATH_ELEMENT> </PATH> </subPane> </pane> -<<<<<<< HEAD - <pane id="Scope" /> <pane id="PackagesPane" /> -======= ->>>>>>> refs/remotes/origin/master </panes> </component> <component name="PropertiesComponent"> <property name="WebServerToolWindowFactoryState" value="false" /> <property name="aspect.path.notification.shown" value="true" /> - <property name="nodejs_interpreter_path" value="C:/myProgram/nodejs/node" /> - <property name="js.eslint.eslintPackage" value="" /> - <property name="js-jscs-nodeInterpreter" value="C:\myProgram\nodejs\node.exe" /> - <property name="settings.editor.selected.configurable" value="reference.settingsdialog.IDE.editor.colors.Font" /> - <property name="SearchEverywhereHistoryKey" value="Array&#9;FILE&#9;jar://C:/Program Files/Java/jdk1.8.0_111/src.zip!/java/util/ArrayList.java&#10;Objects&#9;PSI&#9;JAVA://java.util.Objects&#10;ArrayList&#9;FILE&#9;jar://C:/Program Files/Java/jdk1.8.0_111/src.zip!/java/util/ArrayList.java&#10;LinkedList&#9;FILE&#9;jar://C:/Program Files/Java/jdk1.8.0_111/src.zip!/java/util/LinkedList.java" /> - <property name="com.intellij.testIntegration.createTest.CreateTestDialog.defaultLibrary" value="JUnit4" /> </component> <component name="RecentsManager"> - <key name="CreateTestDialog.RecentsKey"> - <recent name="com.coding.basic" /> - </key> - <key name="CreateTestDialog.Recents.Supers"> - <recent name="" /> - <recent name="groovy.util.GroovyTestCase" /> - </key> <key name="CopyFile.RECENT_KEYS"> - <recent name="D:\AlgorithmsIDEA\coding2017\group15\1511_714512544\src\com\coderising\download" /> + <recent name="D:\AlgorithmsIDEA\coding2017\group15\1511_714512544\src\com\coderising\minJVM" /> + <recent name="D:\AlgorithmsIDEA\coding2017\group15\1511_714512544\src\com\coderising\miniJVM" /> + <recent name="D:\AlgorithmsIDEA\coding2017\group15\1511_714512544\src\com\coding\basic" /> + <recent name="D:\AlgorithmsIDEA\coding2017\group15\1511_714512544\src\com\coderising" /> </key> </component> -<<<<<<< HEAD - <component name="RunManager" selected="JUnit.FileDownloaderTest.testDownload"> -======= <component name="RunDashboard"> <option name="ruleStates"> <list> @@ -203,136 +408,25 @@ </list> </option> </component> - <component name="RunManager" selected="JUnit.ReConstructBSTTest.construct"> ->>>>>>> refs/remotes/origin/master - <configuration default="false" name="FileDownloaderTest.testDownload" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true"> - <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea"> - <pattern> - <option name="PATTERN" value="com.coderising.download.*" /> - <option name="ENABLED" value="true" /> - </pattern> - </extension> - <module name="1511_714512544" /> - <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> - <option name="ALTERNATIVE_JRE_PATH" /> - <option name="PACKAGE_NAME" value="com.coderising.download" /> - <option name="MAIN_CLASS_NAME" value="com.coderising.download.FileDownloaderTest" /> - <option name="METHOD_NAME" value="testDownload" /> - <option name="TEST_OBJECT" value="method" /> - <option name="VM_PARAMETERS" value="-ea" /> - <option name="PARAMETERS" /> - <option name="WORKING_DIRECTORY" value="$MODULE_DIR$" /> - <option name="ENV_VARIABLES" /> - <option name="PASS_PARENT_ENVS" value="true" /> - <option name="TEST_SEARCH_SCOPE"> - <value defaultName="singleModule" /> - </option> - <envs /> - <patterns /> - <method /> - </configuration> - <configuration default="false" name="BinarySearchTreeTest.postOrderGetHeight" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true"> + <component name="RunManager" selected="Application.EmployeeV1"> + <configuration default="false" name="EmployeeV1" type="Application" factoryName="Application" temporary="true" nameIsGenerated="true"> <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea"> <pattern> - <option name="PATTERN" value="test.com.coding.basic.*" /> + <option name="PATTERN" value="com.coderising.jvm.test.*" /> <option name="ENABLED" value="true" /> </pattern> </extension> - <module name="1511_714512544" /> - <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> - <option name="ALTERNATIVE_JRE_PATH" /> - <option name="PACKAGE_NAME" value="test.com.coding.basic" /> - <option name="MAIN_CLASS_NAME" value="test.com.coding.basic.BinarySearchTreeTest" /> - <option name="METHOD_NAME" value="postOrderGetHeight" /> - <option name="TEST_OBJECT" value="method" /> - <option name="VM_PARAMETERS" value="-ea" /> - <option name="PARAMETERS" /> - <option name="WORKING_DIRECTORY" value="$MODULE_DIR$" /> - <option name="ENV_VARIABLES" /> - <option name="PASS_PARENT_ENVS" value="true" /> - <option name="TEST_SEARCH_SCOPE"> - <value defaultName="singleModule" /> - </option> - <envs /> - <patterns /> - <method /> - </configuration> - <configuration default="false" name="ReConstructBSTTest.construct" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true"> - <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea"> - <pattern> - <option name="PATTERN" value="com.coding.basic.*" /> - <option name="ENABLED" value="true" /> - </pattern> - </extension> - <module name="1511_714512544" /> - <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> - <option name="ALTERNATIVE_JRE_PATH" /> - <option name="PACKAGE_NAME" value="com.coding.basic" /> - <option name="MAIN_CLASS_NAME" value="com.coding.basic.ReConstructBSTTest" /> - <option name="METHOD_NAME" value="construct" /> - <option name="TEST_OBJECT" value="method" /> - <option name="VM_PARAMETERS" value="-ea" /> - <option name="PARAMETERS" /> - <option name="WORKING_DIRECTORY" value="$MODULE_DIR$" /> - <option name="ENV_VARIABLES" /> - <option name="PASS_PARENT_ENVS" value="true" /> - <option name="TEST_SEARCH_SCOPE"> - <value defaultName="singleModule" /> - </option> - <envs /> - <patterns /> - <method /> - </configuration> - <configuration default="false" name="ConnectionTest.testContentLength" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true"> - <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea"> - <pattern> - <option name="PATTERN" value="com.coderising.download.*" /> - <option name="ENABLED" value="true" /> - </pattern> - </extension> - <module name="1511_714512544" /> + <option name="MAIN_CLASS_NAME" value="com.coderising.jvm.test.EmployeeV1" /> + <option name="VM_PARAMETERS" /> + <option name="PROGRAM_PARAMETERS" /> + <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" /> <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> <option name="ALTERNATIVE_JRE_PATH" /> - <option name="PACKAGE_NAME" value="com.coderising.download" /> - <option name="MAIN_CLASS_NAME" value="com.coderising.download.ConnectionTest" /> - <option name="METHOD_NAME" value="testContentLength" /> - <option name="TEST_OBJECT" value="method" /> - <option name="VM_PARAMETERS" value="-ea" /> - <option name="PARAMETERS" /> - <option name="WORKING_DIRECTORY" value="$MODULE_DIR$" /> + <option name="ENABLE_SWING_INSPECTOR" value="false" /> <option name="ENV_VARIABLES" /> <option name="PASS_PARENT_ENVS" value="true" /> - <option name="TEST_SEARCH_SCOPE"> - <value defaultName="singleModule" /> - </option> - <envs /> - <patterns /> - <method /> - </configuration> - <configuration default="false" name="ConnectionTest.testRead" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true"> - <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea"> - <pattern> - <option name="PATTERN" value="com.coderising.download.*" /> - <option name="ENABLED" value="true" /> - </pattern> - </extension> <module name="1511_714512544" /> - <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> - <option name="ALTERNATIVE_JRE_PATH" /> - <option name="PACKAGE_NAME" value="com.coderising.download" /> - <option name="MAIN_CLASS_NAME" value="com.coderising.download.ConnectionTest" /> - <option name="METHOD_NAME" value="testRead" /> - <option name="TEST_OBJECT" value="method" /> - <option name="VM_PARAMETERS" value="-ea" /> - <option name="PARAMETERS" /> - <option name="WORKING_DIRECTORY" value="$MODULE_DIR$" /> - <option name="ENV_VARIABLES" /> - <option name="PASS_PARENT_ENVS" value="true" /> - <option name="TEST_SEARCH_SCOPE"> - <value defaultName="singleModule" /> - </option> <envs /> - <patterns /> <method /> </configuration> <configuration default="true" type="#org.jetbrains.idea.devkit.run.PluginConfigurationType" factoryName="Plugin"> @@ -572,7 +666,6 @@ <setting name="passParentEnv" value="true" /> <setting name="launchBrowser" value="true" /> <setting name="launchBrowserUrl" value="" /> - <setting name="depsClasspath" value="false" /> <method /> </configuration> <configuration default="true" type="JUnit" factoryName="JUnit"> @@ -617,6 +710,13 @@ <envs /> <method /> </configuration> + <configuration default="true" type="JavaScriptTestRunnerJest" factoryName="Jest"> + <node-interpreter value="project" /> + <working-dir value="" /> + <envs /> + <scope-kind value="ALL" /> + <method /> + </configuration> <configuration default="true" type="JavaScriptTestRunnerProtractor" factoryName="Protractor"> <config-file value="" /> <node-interpreter value="project" /> @@ -697,12 +797,6 @@ <method /> </configuration> <configuration default="true" type="js.build_tools.gulp" factoryName="Gulp.js"> - <node-interpreter>project</node-interpreter> - <node-options /> - <gulpfile /> - <tasks /> - <arguments /> - <envs /> <method /> </configuration> <configuration default="true" type="js.build_tools.npm" factoryName="npm"> @@ -731,229 +825,64 @@ <configuration default="true" type="osgi.bnd.run" factoryName="Test Launcher (JUnit)"> <method /> </configuration> - <list size="5"> - <item index="0" class="java.lang.String" itemvalue="JUnit.FileDownloaderTest.testDownload" /> - <item index="1" class="java.lang.String" itemvalue="JUnit.BinarySearchTreeTest.postOrderGetHeight" /> - <item index="2" class="java.lang.String" itemvalue="JUnit.ReConstructBSTTest.construct" /> - <item index="3" class="java.lang.String" itemvalue="JUnit.ConnectionTest.testContentLength" /> - <item index="4" class="java.lang.String" itemvalue="JUnit.ConnectionTest.testRead" /> + <list size="1"> + <item index="0" class="java.lang.String" itemvalue="Application.EmployeeV1" /> </list> <recent_temporary> - <list size="5"> - <item index="0" class="java.lang.String" itemvalue="JUnit.FileDownloaderTest.testDownload" /> - <item index="1" class="java.lang.String" itemvalue="JUnit.ConnectionTest.testRead" /> - <item index="2" class="java.lang.String" itemvalue="JUnit.ConnectionTest.testContentLength" /> - <item index="3" class="java.lang.String" itemvalue="JUnit.ReConstructBSTTest.construct" /> - <item index="4" class="java.lang.String" itemvalue="JUnit.BinarySearchTreeTest.postOrderGetHeight" /> + <list size="1"> + <item index="0" class="java.lang.String" itemvalue="Application.EmployeeV1" /> </list> </recent_temporary> </component> <component name="ShelveChangesManager" show_recycled="false"> <option name="remove_strategy" value="false" /> </component> - <component name="SvnConfiguration"> - <configuration /> - </component> <component name="TaskManager"> <task active="true" id="Default" summary="Default task"> - <changelist id="d338ed3a-e900-486a-89a5-3e8b0a3835ed" name="Default" comment="" /> - <created>1488937211416</created> + <changelist id="70c62334-5fd5-4cc1-80de-4d49703ede17" name="Default" comment="" /> + <created>1491741542361</created> <option name="number" value="Default" /> <option name="presentableId" value="Default" /> - <updated>1488937211416</updated> - <workItem from="1488937214510" duration="105000" /> - <workItem from="1488937378056" duration="696000" /> - <workItem from="1488943250591" duration="10013000" /> - <workItem from="1488968861840" duration="6808000" /> - <workItem from="1488982429182" duration="720000" /> - <workItem from="1489022372085" duration="114000" /> - <workItem from="1489050222829" duration="9874000" /> - <workItem from="1489066092125" duration="5000" /> - <workItem from="1489151157201" duration="7163000" /> - <workItem from="1489197882583" duration="3320000" /> - <workItem from="1489201425876" duration="5918000" /> - <workItem from="1489231488846" duration="8000" /> - <workItem from="1489231501854" duration="3000" /> - <workItem from="1489300437102" duration="2786000" /> - <workItem from="1489304518942" duration="16000" /> - <workItem from="1489581322762" duration="4171000" /> - <workItem from="1489628754510" duration="9391000" /> - <workItem from="1489647273393" duration="3740000" /> - <workItem from="1489654640274" duration="1134000" /> -<<<<<<< HEAD - <workItem from="1489658627416" duration="1354000" /> - <workItem from="1489726867862" duration="16000" /> - <workItem from="1490016596218" duration="624000" /> - <workItem from="1490090580129" duration="215000" /> -======= - <workItem from="1489658627416" duration="365000" /> - <workItem from="1491137983322" duration="25000" /> ->>>>>>> refs/remotes/origin/master - </task> - <task id="LOCAL-00001" summary="xuweijay"> - <created>1488937445293</created> - <option name="number" value="00001" /> - <option name="presentableId" value="LOCAL-00001" /> - <option name="project" value="LOCAL" /> - <updated>1488937445293</updated> - </task> - <task id="LOCAL-00002" summary="xuweijay"> - <created>1489156650791</created> - <option name="number" value="00002" /> - <option name="presentableId" value="LOCAL-00002" /> - <option name="project" value="LOCAL" /> - <updated>1489156650791</updated> - </task> - <task id="LOCAL-00003" summary="xuweijay"> - <created>1489206126088</created> - <option name="number" value="00003" /> - <option name="presentableId" value="LOCAL-00003" /> - <option name="project" value="LOCAL" /> - <updated>1489206126088</updated> - </task> - <task id="LOCAL-00004" summary="xuweijay"> - <created>1489209258691</created> - <option name="number" value="00004" /> - <option name="presentableId" value="LOCAL-00004" /> - <option name="project" value="LOCAL" /> - <updated>1489209258691</updated> - </task> - <task id="LOCAL-00005" summary="xuweijay"> - <created>1489211483985</created> - <option name="number" value="00005" /> - <option name="presentableId" value="LOCAL-00005" /> - <option name="project" value="LOCAL" /> - <updated>1489211483985</updated> - </task> - <task id="LOCAL-00006" summary="xuweijay"> - <created>1489303022487</created> - <option name="number" value="00006" /> - <option name="presentableId" value="LOCAL-00006" /> - <option name="project" value="LOCAL" /> - <updated>1489303022487</updated> - </task> - <task id="LOCAL-00007" summary="xuweijay"> - <created>1489646535233</created> - <option name="number" value="00007" /> - <option name="presentableId" value="LOCAL-00007" /> - <option name="project" value="LOCAL" /> - <updated>1489646535233</updated> - </task> - <task id="LOCAL-00008" summary="xuweijay"> - <created>1489650846639</created> - <option name="number" value="00008" /> - <option name="presentableId" value="LOCAL-00008" /> - <option name="project" value="LOCAL" /> - <updated>1489650846639</updated> - </task> - <task id="LOCAL-00009" summary="xuweijay"> - <created>1489658647678</created> - <option name="number" value="00009" /> - <option name="presentableId" value="LOCAL-00009" /> - <option name="project" value="LOCAL" /> - <updated>1489658647678</updated> + <updated>1491741542361</updated> + <workItem from="1491741546482" duration="2875000" /> </task> - <task id="LOCAL-00010" summary="xuweijay"> - <created>1489658675286</created> - <option name="number" value="00010" /> - <option name="presentableId" value="LOCAL-00010" /> - <option name="project" value="LOCAL" /> - <updated>1489658675286</updated> - </task> - <task id="LOCAL-00011" summary="xuweijay"> - <created>1489659000096</created> - <option name="number" value="00011" /> - <option name="presentableId" value="LOCAL-00011" /> - <option name="project" value="LOCAL" /> - <updated>1489659000096</updated> - </task> - <option name="localTasksCounter" value="12" /> <servers /> </component> - <component name="TestHistory"> - <history-entry file="ConnectionTest_testContentLength - 2017.03.16 at 18h 17m 53s.xml"> - <configuration name="ConnectionTest.testContentLength" configurationId="JUnit" /> - </history-entry> - <history-entry file="ConnectionTest_testRead - 2017.03.16 at 18h 17m 57s.xml"> - <configuration name="ConnectionTest.testRead" configurationId="JUnit" /> - </history-entry> - <history-entry file="FileDownloaderTest_testDownload - 2017.03.16 at 15h 43m 32s.xml"> - <configuration name="FileDownloaderTest.testDownload" configurationId="JUnit" /> - </history-entry> - <history-entry file="FileDownloaderTest_testDownload - 2017.03.16 at 15h 53m 43s.xml"> - <configuration name="FileDownloaderTest.testDownload" configurationId="JUnit" /> - </history-entry> - <history-entry file="FileDownloaderTest_testDownload - 2017.03.16 at 18h 18m 44s.xml"> - <configuration name="FileDownloaderTest.testDownload" configurationId="JUnit" /> - </history-entry> - <history-entry file="LinkedListTest_removeRange - 2017.03.10 at 22h 32m 52s.xml"> - <configuration name="LinkedListTest.removeRange" configurationId="JUnit" /> - </history-entry> - <history-entry file="LinkedListTest_removeRange - 2017.03.10 at 22h 33m 15s.xml"> - <configuration name="LinkedListTest.removeRange" configurationId="JUnit" /> - </history-entry> - <history-entry file="ReConstructBSTTest_construct - 2017.03.16 at 14h 40m 52s.xml"> - <configuration name="ReConstructBSTTest.construct" configurationId="JUnit" /> - </history-entry> - <history-entry file="ReConstructBSTTest_construct - 2017.03.16 at 17h 04m 53s.xml"> - <configuration name="ReConstructBSTTest.construct" configurationId="JUnit" /> - </history-entry> - <history-entry file="ReConstructBSTTest_construct - 2017.03.16 at 17h 09m 49s.xml"> - <configuration name="ReConstructBSTTest.construct" configurationId="JUnit" /> - </history-entry> - </component> <component name="TimeTrackingManager"> -<<<<<<< HEAD - <option name="totallyTimeSpent" value="68194000" /> -======= - <option name="totallyTimeSpent" value="66375000" /> ->>>>>>> refs/remotes/origin/master - </component> - <component name="TodoView"> - <todo-panel id="selected-file"> - <is-autoscroll-to-source value="true" /> - </todo-panel> - <todo-panel id="all"> - <are-packages-shown value="true" /> - <is-autoscroll-to-source value="true" /> - </todo-panel> + <option name="totallyTimeSpent" value="2875000" /> </component> <component name="ToolWindowManager"> <frame x="-9" y="-9" width="1938" height="1048" extended-state="6" /> <layout> - <window_info id="Palette" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" /> - <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3295583" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" /> - <window_info id="Nl-Palette" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" /> - <window_info id="Palette&#9;" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" /> - <window_info id="Image Layers" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" /> - <window_info id="Capture Analysis" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" /> - <window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3295583" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" /> - <window_info id="Maven Projects" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> - <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3295583" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" /> - <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3295583" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> - <window_info id="Properties" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="8" side_tool="false" content_ui="tabs" /> - <window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> - <window_info id="Capture Tool" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> - <window_info id="Designer" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" /> -<<<<<<< HEAD - <window_info id="Project" active="true" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.2360515" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" /> -======= - <window_info id="Project" active="true" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.22961374" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" /> ->>>>>>> refs/remotes/origin/master - <window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="9" side_tool="false" content_ui="tabs" /> - <window_info id="Structure" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.23444206" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" /> - <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" /> - <window_info id="UI Designer" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" /> - <window_info id="Theme Preview" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="10" side_tool="false" content_ui="tabs" /> - <window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3997735" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> - <window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="true" content_ui="tabs" /> + <window_info id="Palette" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" /> + <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" /> + <window_info id="Nl-Palette" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" /> + <window_info id="Messages" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3295583" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" /> + <window_info id="Palette&#9;" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" /> + <window_info id="Image Layers" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" /> + <window_info id="Capture Analysis" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" /> + <window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="true" content_ui="tabs" /> + <window_info id="Maven Projects" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" /> + <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3295583" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" /> + <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" /> + <window_info id="Properties" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" /> + <window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" /> + <window_info id="Capture Tool" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" /> + <window_info id="Designer" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> + <window_info id="Project" active="true" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.21030043" sideWeight="0.5" order="6" side_tool="false" content_ui="combo" /> + <window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" /> + <window_info id="Structure" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> + <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="9" side_tool="false" content_ui="tabs" /> + <window_info id="UI Designer" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" /> + <window_info id="Theme Preview" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> + <window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="5" side_tool="true" content_ui="tabs" /> + <window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> <window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" /> + <window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="10" side_tool="false" content_ui="combo" /> <window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" /> - <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" /> - <window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="3" side_tool="false" content_ui="combo" /> - <window_info id="Messages" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3295583" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> - <window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" /> + <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="8" side_tool="false" content_ui="tabs" /> <window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" /> + <window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" /> </layout> </component> <component name="TypeScriptGeneratedFilesManager"> @@ -980,14 +909,8 @@ <component name="VcsContentAnnotationSettings"> <option name="myLimit" value="2678400000" /> </component> - <component name="VcsManagerConfiguration"> - <MESSAGE value="xuweijay" /> - <option name="LAST_COMMIT_MESSAGE" value="xuweijay" /> - </component> <component name="XDebuggerManager"> - <breakpoint-manager> - <option name="time" value="12" /> - </breakpoint-manager> + <breakpoint-manager /> <watches-manager /> </component> <component name="antWorkspaceConfiguration"> @@ -995,357 +918,105 @@ <option name="FILTER_TARGETS" value="false" /> </component> <component name="editorHistoryManager"> - <entry file="file://$PROJECT_DIR$/src/com/coderising/download/impl/ConnectionManagerImpl.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="84"> - <caret line="6" column="13" lean-forward="false" selection-start-line="6" selection-start-column="13" selection-end-line="6" selection-end-column="13" /> - </state> - </provider> - </entry> - <entry file="file://$PROJECT_DIR$/src/com/coderising/download/DownloadThread.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="84"> - <caret line="4" column="13" lean-forward="false" selection-start-line="4" selection-start-column="13" selection-end-line="4" selection-end-column="13" /> - </state> - </provider> - </entry> - <entry file="file://$PROJECT_DIR$/src/com/coderising/download/FileDownloaderTest.java"> + <entry file="file://$PROJECT_DIR$/src/com/coderising/miniJVM/test/EmployeeV1.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="84"> - <caret line="10" column="13" lean-forward="false" selection-start-line="10" selection-start-column="13" selection-end-line="10" selection-end-column="13" /> - </state> - </provider> - </entry> - <entry file="file://$PROJECT_DIR$/.idea/workspace.xml"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="-11890"> + <state relative-caret-position="0"> <caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" /> + <folding /> </state> </provider> </entry> - <entry file="jar://C:/Program Files/Java/jdk1.8.0_111/src.zip!/java/net/URL.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="283"> - <caret line="977" column="25" lean-forward="false" selection-start-line="977" selection-start-column="25" selection-end-line="977" selection-end-column="25" /> - </state> - </provider> - </entry> - <entry file="jar://C:/Program Files/Java/jdk1.8.0_111/src.zip!/java/io/BufferedInputStream.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="186"> - <caret line="337" column="0" lean-forward="false" selection-start-line="337" selection-start-column="0" selection-end-line="337" selection-end-column="0" /> - </state> - </provider> - </entry> - <entry file="jar://C:/Program Files/Java/jdk1.8.0_111/src.zip!/java/io/FilterInputStream.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="438"> - <caret line="132" column="0" lean-forward="false" selection-start-line="132" selection-start-column="0" selection-end-line="132" selection-end-column="0" /> - </state> - </provider> - </entry> - <entry file="jar://C:/Program Files/Java/jdk1.8.0_111/src.zip!/java/lang/Thread.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="323"> - <caret line="725" column="0" lean-forward="false" selection-start-line="725" selection-start-column="0" selection-end-line="725" selection-end-column="0" /> - </state> - </provider> - </entry> - <entry file="jar://C:/Program Files/Java/jdk1.8.0_111/src.zip!/java/net/URLConnection.java"> + <entry file="file://$PROJECT_DIR$/src/com/coderising/miniJVM/test/ClassFileloaderTest.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="186"> - <caret line="271" column="22" lean-forward="false" selection-start-line="271" selection-start-column="22" selection-end-line="271" selection-end-column="22" /> + <state relative-caret-position="572"> + <caret line="26" column="31" lean-forward="false" selection-start-line="26" selection-start-column="31" selection-end-line="26" selection-end-column="31" /> + <folding /> </state> </provider> </entry> - <entry file="jar://C:/Program Files/Java/jdk1.8.0_111/jre/lib/rt.jar!/sun/net/www/protocol/http/HttpURLConnection.class"> + <entry file="file://$PROJECT_DIR$/src/com/coderising/miniJVM/util/Util.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="417"> - <caret line="2253" column="62" lean-forward="false" selection-start-line="2253" selection-start-column="53" selection-end-line="2253" selection-end-column="62" /> - </state> - </provider> - </entry> - <entry file="jar://C:/Program Files/Java/jdk1.8.0_111/src.zip!/java/util/LinkedList.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="273"> - <caret line="970" column="10" lean-forward="false" selection-start-line="970" selection-start-column="10" selection-end-line="970" selection-end-column="10" /> - </state> - </provider> - </entry> - <entry file="jar://C:/Program Files/Java/jdk1.8.0_111/src.zip!/java/util/AbstractList.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="283"> - <caret line="511" column="19" lean-forward="false" selection-start-line="511" selection-start-column="19" selection-end-line="511" selection-end-column="19" /> - </state> - </provider> - </entry> - <entry file="file://$PROJECT_DIR$/src/com/coding/basic/List.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="105"> - <caret line="5" column="23" lean-forward="true" selection-start-line="5" selection-start-column="23" selection-end-line="5" selection-end-column="23" /> - </state> - </provider> - </entry> - <entry file="jar://C:/Program Files/Java/jdk1.8.0_111/src.zip!/java/lang/Object.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="283"> - <caret line="147" column="19" lean-forward="false" selection-start-line="147" selection-start-column="19" selection-end-line="147" selection-end-column="19" /> - </state> - </provider> - </entry> - <entry file="jar://C:/Program Files/Java/jdk1.8.0_111/src.zip!/java/util/ArrayList.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="420"> - <caret line="316" column="44" lean-forward="false" selection-start-line="316" selection-start-column="44" selection-end-line="316" selection-end-column="44" /> - </state> - </provider> - </entry> - <entry file="jar://C:/Program Files/Java/jdk1.8.0_111/src.zip!/java/util/Objects.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="283"> - <caret line="57" column="26" lean-forward="false" selection-start-line="57" selection-start-column="26" selection-end-line="57" selection-end-column="26" /> - </state> - </provider> - </entry> - <entry file="jar://D:/2017编程能力提高群/常用开发包及配置文件/junit-4.8.2.jar!/org/junit/internal/runners/model/ReflectiveCallable.class"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="252"> - <caret line="15" column="0" lean-forward="false" selection-start-line="15" selection-start-column="0" selection-end-line="15" selection-end-column="0" /> - </state> - </provider> - </entry> - <entry file="jar://D:/2017编程能力提高群/常用开发包及配置文件/junit-4.8.2.jar!/org/junit/runners/model/FrameworkMethod.class"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="144"> - <caret line="26" column="0" lean-forward="false" selection-start-line="26" selection-start-column="0" selection-end-line="26" selection-end-column="0" /> - </state> - </provider> - </entry> - <entry file="jar://D:/2017编程能力提高群/常用开发包及配置文件/junit-4.8.2.jar!/org/junit/internal/runners/statements/InvokeMethod.class"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="336"> - <caret line="20" column="0" lean-forward="false" selection-start-line="20" selection-start-column="0" selection-end-line="20" selection-end-column="0" /> - </state> - </provider> - </entry> - <entry file="jar://D:/2017编程能力提高群/常用开发包及配置文件/junit-4.8.2.jar!/org/junit/internal/runners/statements/RunBefores.class"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="330"> - <caret line="32" column="0" lean-forward="false" selection-start-line="32" selection-start-column="0" selection-end-line="32" selection-end-column="0" /> - </state> - </provider> - </entry> - <entry file="jar://D:/2017编程能力提高群/常用开发包及配置文件/junit-4.8.2.jar!/org/junit/internal/runners/statements/RunAfters.class"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="166"> - <caret line="76" column="0" lean-forward="false" selection-start-line="76" selection-start-column="0" selection-end-line="76" selection-end-column="0" /> - </state> - </provider> - </entry> - <entry file="jar://D:/2017编程能力提高群/常用开发包及配置文件/junit-4.8.2.jar!/org/junit/runners/BlockJUnit4ClassRunner.class"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="144"> - <caret line="48" column="0" lean-forward="false" selection-start-line="48" selection-start-column="0" selection-end-line="48" selection-end-column="0" /> - </state> - </provider> - </entry> - <entry file="file://$PROJECT_DIR$/src/com/coderising/litestruts/View.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="84"> - <caret line="4" column="13" lean-forward="false" selection-start-line="4" selection-start-column="13" selection-end-line="4" selection-end-column="13" /> - </state> - </provider> - </entry> - <entry file="file://$PROJECT_DIR$/src/com/coderising/litestruts/StrutsTest.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="84"> - <caret line="8" column="13" lean-forward="false" selection-start-line="8" selection-start-column="13" selection-end-line="8" selection-end-column="13" /> - </state> - </provider> - </entry> - <entry file="file://$PROJECT_DIR$/src/com/coderising/litestruts/struts.xml"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="210"> - <caret line="10" column="9" lean-forward="true" selection-start-line="10" selection-start-column="9" selection-end-line="10" selection-end-column="9" /> - </state> - </provider> - </entry> - <entry file="file://$PROJECT_DIR$/src/com/coding/basic/ArrayList.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="-146"> - <caret line="5" column="13" lean-forward="false" selection-start-line="5" selection-start-column="13" selection-end-line="5" selection-end-column="13" /> - </state> - </provider> - </entry> - <entry file="file://$PROJECT_DIR$/src/com/coderising/array/ArrayUtilTest.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="484"> - <caret line="65" column="16" lean-forward="false" selection-start-line="65" selection-start-column="16" selection-end-line="65" selection-end-column="16" /> - </state> - </provider> - </entry> - <entry file="file://$PROJECT_DIR$/src/com/coderising/array/ArrayUtil.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="273"> - <caret line="146" column="17" lean-forward="false" selection-start-line="146" selection-start-column="17" selection-end-line="146" selection-end-column="17" /> - </state> - </provider> - </entry> - <entry file="file://$PROJECT_DIR$/src/com/coderising/litestruts/LoginAction.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="147"> - <caret line="7" column="13" lean-forward="false" selection-start-line="7" selection-start-column="13" selection-end-line="7" selection-end-column="13" /> - </state> - </provider> - </entry> - <entry file="file://$PROJECT_DIR$/文章地址.md"> - <provider selected="true" editor-type-id="split-provider[text-editor;markdown-preview-editor]"> - <state split_layout="SPLIT"> - <first_editor relative-caret-position="105"> - <caret line="5" column="0" lean-forward="true" selection-start-line="5" selection-start-column="0" selection-end-line="5" selection-end-column="0" /> - </first_editor> - <second_editor /> - </state> - </provider> - </entry> - <entry file="file://$PROJECT_DIR$/src/com/coderising/litestruts/Struts.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="-945"> - <caret line="14" column="81" lean-forward="false" selection-start-line="14" selection-start-column="33" selection-end-line="14" selection-end-column="81" /> - </state> - </provider> - </entry> - <entry file="file://$PROJECT_DIR$/src/com/coderising/download/Demo.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="21"> - <caret line="7" column="13" lean-forward="false" selection-start-line="7" selection-start-column="13" selection-end-line="7" selection-end-column="13" /> - </state> - </provider> - </entry> - <entry file="file://$PROJECT_DIR$/src/com/coding/basic/LinkedList.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="336"> - <caret line="346" column="0" lean-forward="true" selection-start-line="346" selection-start-column="0" selection-end-line="346" selection-end-column="0" /> - </state> - </provider> - </entry> - <entry file="file://$PROJECT_DIR$/src/test/com/coding/basic/LinkedListTest.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="273"> - <caret line="151" column="16" lean-forward="false" selection-start-line="151" selection-start-column="16" selection-end-line="151" selection-end-column="16" /> - </state> - </provider> - </entry> - <entry file="file://$PROJECT_DIR$/src/test/com/coding/basic/BinarySearchTreeTest.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="379"> - <caret line="65" column="5" lean-forward="true" selection-start-line="65" selection-start-column="5" selection-end-line="65" selection-end-column="5" /> - </state> - </provider> - </entry> - <entry file="file://$PROJECT_DIR$/src/com/coding/basic/ReConstructBSTTest.groovy" /> - <entry file="file://$PROJECT_DIR$/src/com/coding/basic/BinarySearchTreeNode.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="105"> - <caret line="5" column="13" lean-forward="false" selection-start-line="5" selection-start-column="13" selection-end-line="5" selection-end-column="13" /> - </state> - </provider> - </entry> - <entry file="file://$PROJECT_DIR$/src/com/coderising/download/api/ConnectionException.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="42"> + <state relative-caret-position="44"> <caret line="2" column="13" lean-forward="false" selection-start-line="2" selection-start-column="13" selection-end-line="2" selection-end-column="13" /> + <folding /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/src/com/coderising/download/api/DownloadListener.java"> + <entry file="file://$PROJECT_DIR$/src/com/coderising/miniJVM/loader/ClassFileLoader.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="63"> - <caret line="3" column="16" lean-forward="false" selection-start-line="3" selection-start-column="16" selection-end-line="3" selection-end-column="16" /> + <state relative-caret-position="230"> + <caret line="71" column="18" lean-forward="true" selection-start-line="71" selection-start-column="18" selection-end-line="71" selection-end-column="18" /> + <folding /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/src/com/coderising/download/api/ConnectionManager.java"> + <entry file="file://$PROJECT_DIR$/src/com/coding/basic/LRUPageFrameTest.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="168"> - <caret line="8" column="22" lean-forward="false" selection-start-line="8" selection-start-column="22" selection-end-line="8" selection-end-column="22" /> + <state relative-caret-position="110"> + <caret line="7" column="4" lean-forward="true" selection-start-line="7" selection-start-column="4" selection-end-line="7" selection-end-column="4" /> + <folding /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/src/com/coderising/download/api/Connection.java"> + <entry file="file://$PROJECT_DIR$/src/com/coding/basic/LRUPageFrame.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="84"> - <caret line="4" column="17" lean-forward="false" selection-start-line="4" selection-start-column="17" selection-end-line="4" selection-end-column="17" /> + <state relative-caret-position="-1510"> + <caret line="48" column="12" lean-forward="true" selection-start-line="48" selection-start-column="12" selection-end-line="48" selection-end-column="12" /> + <folding /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/src/com/coding/basic/ReConstructBSTTest.java"> + <entry file="file://$PROJECT_DIR$/src/com/coderising/jvm/clz/ClassFile.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="147"> - <caret line="11" column="33" lean-forward="true" selection-start-line="11" selection-start-column="33" selection-end-line="11" selection-end-column="33" /> + <state relative-caret-position="88"> + <caret line="4" column="0" lean-forward="true" selection-start-line="4" selection-start-column="0" selection-end-line="4" selection-end-column="0" /> + <folding> + <element signature="imports" expanded="true" /> + </folding> </state> </provider> </entry> - <entry file="jar://C:/Program Files/Java/jdk1.8.0_111/src.zip!/java/io/RandomAccessFile.java"> + <entry file="file://$PROJECT_DIR$/src/com/coderising/jvm/constant/ConstantPool.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="283"> - <caret line="487" column="16" lean-forward="false" selection-start-line="487" selection-start-column="16" selection-end-line="487" selection-end-column="16" /> - </state> - </provider> - </entry> - <entry file="file://$PROJECT_DIR$/src/com/coding/basic/BinarySearchTree.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="358"> - <caret line="340" column="15" lean-forward="false" selection-start-line="340" selection-start-column="15" selection-end-line="340" selection-end-column="15" /> - </state> - </provider> - </entry> - <entry file="file://$PROJECT_DIR$/src/com/coding/basic/ReConstructBST.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="-42"> - <caret line="19" column="5" lean-forward="true" selection-start-line="16" selection-start-column="7" selection-end-line="19" selection-end-column="5" /> - </state> - </provider> - </entry> - <entry file="file://$PROJECT_DIR$/src/com/coderising/download/impl/ConnectionManagerImpl.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="252"> - <caret line="19" column="37" lean-forward="false" selection-start-line="19" selection-start-column="37" selection-end-line="19" selection-end-column="37" /> - </state> - </provider> - </entry> - <entry file="file://$PROJECT_DIR$/src/com/coderising/download/DownloadThread.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="568"> - <caret line="33" column="54" lean-forward="true" selection-start-line="33" selection-start-column="54" selection-end-line="33" selection-end-column="54" /> + <state relative-caret-position="88"> + <caret line="5" column="13" lean-forward="false" selection-start-line="5" selection-start-column="13" selection-end-line="5" selection-end-column="13" /> + <folding /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/src/com/coderising/download/impl/ConnectionImpl.java"> + <entry file="file://$PROJECT_DIR$/src/com/coderising/jvm/test/EmployeeV1.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="1029"> - <caret line="49" column="0" lean-forward="true" selection-start-line="49" selection-start-column="0" selection-end-line="49" selection-end-column="0" /> + <state relative-caret-position="198"> + <caret line="9" column="31" lean-forward="true" selection-start-line="9" selection-start-column="31" selection-end-line="9" selection-end-column="31" /> + <folding /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/src/com/coderising/download/ConnectionTest.java"> + <entry file="file://$PROJECT_DIR$/out/production/1511_714512544/com/coderising/jvm/test/EmployeeV1.class"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="189"> - <caret line="21" column="5" lean-forward="true" selection-start-line="21" selection-start-column="5" selection-end-line="21" selection-end-column="5" /> + <state relative-caret-position="0"> + <caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" /> + <folding> + <element signature="e#0#678#0" expanded="true" /> + </folding> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/src/com/coderising/download/FileDownloader.java"> + <entry file="file://$PROJECT_DIR$/.idea/workspace.xml"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="452"> - <caret line="47" column="56" lean-forward="false" selection-start-line="47" selection-start-column="56" selection-end-line="47" selection-end-column="56" /> + <state relative-caret-position="704"> + <caret line="961" column="6" lean-forward="false" selection-start-line="961" selection-start-column="6" selection-end-line="961" selection-end-column="6" /> + <folding /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/src/com/coderising/download/FileDownloaderTest.java"> + <entry file="file://$PROJECT_DIR$/src/com/coderising/jvm/test/ClassFileloaderTest.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="630"> - <caret line="48" column="36" lean-forward="true" selection-start-line="48" selection-start-column="36" selection-end-line="48" selection-end-column="36" /> + <state relative-caret-position="44"> + <caret line="2" column="7" lean-forward="true" selection-start-line="2" selection-start-column="7" selection-end-line="2" selection-end-column="7" /> + <folding> + <element signature="imports" expanded="true" /> + </folding> </state> </provider> </entry> 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<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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<String> clzPaths = new ArrayList<String>(); + + 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/1511_714512544/src/com/coderising/jvm/loader/ClassFileParser.java b/group15/1511_714512544/src/com/coderising/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..41093c8b78 --- /dev/null +++ b/group15/1511_714512544/src/com/coderising/jvm/loader/ClassFileParser.java @@ -0,0 +1,35 @@ +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.ConstantPool; + +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/group15/1511_714512544/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group15/1511_714512544/src/com/coderising/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..6d9ac5e6c8 --- /dev/null +++ b/group15/1511_714512544/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,198 @@ +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.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; + +public class ClassFileloaderTest { + + + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + + static String path1 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\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 { + } + + @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(); + } + + /** + * ---------------------------------------------------------------------- + */ + + + @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("<init>", 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<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/group15/1511_714512544/src/com/coding/basic/LRUPageFrame.java b/group15/1511_714512544/src/com/coding/basic/LRUPageFrame.java new file mode 100644 index 0000000000..a1c4777af2 --- /dev/null +++ b/group15/1511_714512544/src/com/coding/basic/LRUPageFrame.java @@ -0,0 +1,148 @@ +package com.coding.basic; + +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/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 183/287] 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<String> clzPaths = new ArrayList<String>(); 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<this.clzPaths.size();i++){ + buffer.append(this.clzPaths.get(i)); + if(i<this.clzPaths.size()-1){ + buffer.append(";"); + } + } + return buffer.toString(); } - public String getClassPath(){ - return null; + public String getClassPath(){ + return StringUtils.join(this.clzPaths,";"); } diff --git a/group12/446031103/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group12/446031103/src/com/coderising/jvm/test/ClassFileloaderTest.java index 50eb1be6fa..0a4b132fd2 100644 --- a/group12/446031103/src/com/coderising/jvm/test/ClassFileloaderTest.java +++ b/group12/446031103/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -13,7 +13,7 @@ public class ClassFileloaderTest { - + //E:\\mygit\\coding2017\\group12\\446031103\\bin static String path1 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\mini-jvm\\bin"; static String path2 = "C:\temp"; @@ -45,13 +45,12 @@ 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); + Assert.assertEquals(1024, byteCodes.length); } diff --git a/group12/446031103/src/com/datastructure/linklist/LRUPageFrame.java b/group12/446031103/src/com/datastructure/linklist/LRUPageFrame.java index 5e20d9a49e..cdb42d1fdd 100644 --- a/group12/446031103/src/com/datastructure/linklist/LRUPageFrame.java +++ b/group12/446031103/src/com/datastructure/linklist/LRUPageFrame.java @@ -9,7 +9,163 @@ */ public class LRUPageFrame { - private static class Node { +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 key + * @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(); + } + + /*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 <qinwa.wong@gmail.com> Date: Sun, 9 Apr 2017 22:08:49 +0800 Subject: [PATCH 184/287] =?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<chs.length;i++){ + char temp = chs[i]; + if(temp==')'){ + left.push('('); + }else if (temp=='}'){ + left.push('{'); + }else if(temp==']'){ + left.push('['); + } + if(temp=='('||temp=='['||temp=='{'){ + right.push(temp); + } + } + + reverse(left); + if(right.toString().equals(left.toString())){ + return true; + } + return false; + } +} diff --git a/group15/1513_121469918/mini-jvm/src/coderising/jvm/clz/AccessFlag.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..0719ffaa0b --- /dev/null +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/clz/AccessFlag.java @@ -0,0 +1,25 @@ +package 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/1513_121469918/mini-jvm/src/coderising/jvm/clz/ClassFile.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..33b8d3a519 --- /dev/null +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/clz/ClassFile.java @@ -0,0 +1,75 @@ +package coderising.jvm.clz; + +import coderising.jvm.constant.ClassInfo; +import 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/1513_121469918/mini-jvm/src/coderising/jvm/clz/ClassIndex.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..c58deb35b3 --- /dev/null +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/clz/ClassIndex.java @@ -0,0 +1,19 @@ +package 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/1513_121469918/mini-jvm/src/coderising/jvm/constant/ClassInfo.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..4ed8312fd6 --- /dev/null +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/ClassInfo.java @@ -0,0 +1,24 @@ +package 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/1513_121469918/mini-jvm/src/coderising/jvm/constant/ConstantInfo.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..3dfcb48b74 --- /dev/null +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/ConstantInfo.java @@ -0,0 +1,29 @@ +package 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/1513_121469918/mini-jvm/src/coderising/jvm/constant/ConstantPool.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..59128f899c --- /dev/null +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/constant/ConstantPool.java @@ -0,0 +1,29 @@ +package coderising.jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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<String> clzPaths = new ArrayList<String>(); + + 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/1513_121469918/mini-jvm/src/coderising/jvm/loader/ClassFileParser.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..1d7e712226 --- /dev/null +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/loader/ClassFileParser.java @@ -0,0 +1,105 @@ +package coderising.jvm.loader; + +import coderising.jvm.clz.AccessFlag; +import coderising.jvm.clz.ClassFile; +import coderising.jvm.clz.ClassIndex; +import coderising.jvm.constant.ClassInfo; +import coderising.jvm.constant.ConstantPool; +import coderising.jvm.constant.FieldRefInfo; +import coderising.jvm.constant.MethodRefInfo; +import coderising.jvm.constant.NameAndTypeInfo; +import coderising.jvm.constant.NullConstantInfo; +import coderising.jvm.constant.StringInfo; +import 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(!magicNumber.equals("cafebabe")){ + return null; + } + + clzFile.setMinorVersion(iter.nextU2ToInt()); + clzFile.setMajorVersion(iter.nextU2ToInt()); + + ConstantPool pool = parseConstantPool(iter); + clzFile.setConstPool(pool); + + AccessFlag flag = parseAccessFlag(iter); + clzFile.setAccessFlag(flag); + + ClassIndex clzindex = parseClassInfex(iter); + clzFile.setClassIndex(clzindex); + + return clzFile; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + return new AccessFlag(iter.nextU2ToInt()); + } + + private ClassIndex parseClassInfex(ByteCodeIterator iter) { + ClassIndex clzIndex = new ClassIndex(); + clzIndex.setThisClassIndex(iter.nextU2ToInt()); + clzIndex.setSuperClassIndex(iter.nextU2ToInt()); + return clzIndex; + } + + private ConstantPool parseConstantPool(ByteCodeIterator iter) { + ConstantPool pool = new ConstantPool(); + pool.addConstantInfo(new NullConstantInfo()); + int poolSize = iter.nextU2ToInt(); + + for(int i =1;i<poolSize;i++){ + int tag = iter.nextU1ToInt(); + System.out.println("tag:"+i+":"+tag); + switch (tag){ + case 1: + UTF8Info utf8Info = new UTF8Info(pool); + utf8Info.setLength(iter.nextU2ToInt()); + String value = iter.nextString(utf8Info.getLength()); + utf8Info.setValue(value); + pool.addConstantInfo(utf8Info); + break; + case 4: + break; + case 7: + int utf8Index = iter.nextU2ToInt(); + ClassInfo clzInfo = new ClassInfo(pool); + clzInfo.setUtf8Index(utf8Index); + pool.addConstantInfo(clzInfo); + break; + case 8: + StringInfo stringInfo = new StringInfo(pool); + stringInfo.setIndex(iter.nextU2ToInt()); + pool.addConstantInfo(stringInfo); + break; + case 9: + FieldRefInfo fieldRef = new FieldRefInfo(pool); + fieldRef.setClassInfoIndex(iter.nextU2ToInt()); + fieldRef.setNameAndTypeIndex(iter.nextU2ToInt()); + pool.addConstantInfo(fieldRef); + break; + case 10: + MethodRefInfo methodRef = new MethodRefInfo(pool); + methodRef.setClassInfoIndex(iter.nextU2ToInt()); + methodRef.setNameAndTypeIndex(iter.nextU2ToInt()); + pool.addConstantInfo(methodRef); + break; + case 12: + NameAndTypeInfo nati = new NameAndTypeInfo(pool); + nati.setIndex1(iter.nextU2ToInt()); + nati.setIndex2(iter.nextU2ToInt()); + pool.addConstantInfo(nati); + break; + } + } + return pool; + } + + +} diff --git a/group15/1513_121469918/mini-jvm/src/coderising/jvm/test/ClassFileloaderTest.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..ecf9df9cee --- /dev/null +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,198 @@ +package coderising.jvm.test; + + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import coderising.jvm.clz.ClassFile; +import coderising.jvm.clz.ClassIndex; +import coderising.jvm.constant.ClassInfo; +import coderising.jvm.constant.ConstantPool; +import coderising.jvm.constant.MethodRefInfo; +import coderising.jvm.constant.NameAndTypeInfo; +import coderising.jvm.constant.UTF8Info; +import coderising.jvm.loader.ClassFileLoader; + + +public class ClassFileloaderTest { + private static final String FULL_QUALIFIED_CLASS_NAME = "coderising/jvm/test/EmployeeV1"; + + static String path1 = "D:\\Downloads\\mini-jvm\\bin"; + static String path2 = "C:\temp"; + + static ClassFile clzFile = null; + static { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "coderising.jvm.test.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 = "coderising.jvm.test.EmployeeV1"; + + byte[] byteCodes = loader.readBinaryCode(className); + + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + Assert.assertEquals(1048, byteCodes.length); + + } + + + @Test + public void testMagicNumber(){ + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "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(); + } + + /** + * ---------------------------------------------------------------------- + */ + + + @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("<init>", 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<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 b4c3a4055ce140ff5ee16f6125a769fbfe6d001e Mon Sep 17 00:00:00 2001 From: maishihang <446031103@qq.com> Date: Sun, 9 Apr 2017 22:08:52 +0800 Subject: [PATCH 185/287] =?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<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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<String> clzPaths = new ArrayList<String>(); 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<this.clzPaths.size();i++){ - buffer.append(this.clzPaths.get(i)); - if(i<this.clzPaths.size()-1){ - buffer.append(";"); - } + + + 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(); + } + return buffer.toString(); } - public String getClassPath(){ - return StringUtils.join(this.clzPaths,";"); + 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/group12/446031103/src/com/coderising/jvm/loader/ClassFileParser.java b/group12/446031103/src/com/coderising/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..8e29f14a0c --- /dev/null +++ b/group12/446031103/src/com/coderising/jvm/loader/ClassFileParser.java @@ -0,0 +1,44 @@ +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/group12/446031103/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group12/446031103/src/com/coderising/jvm/test/ClassFileloaderTest.java index 0a4b132fd2..26407abbef 100644 --- a/group12/446031103/src/com/coderising/jvm/test/ClassFileloaderTest.java +++ b/group12/446031103/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -5,6 +5,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; @@ -13,10 +20,21 @@ public class ClassFileloaderTest { - //E:\\mygit\\coding2017\\group12\\446031103\\bin + + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + static String path1 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\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 @@ -45,12 +63,13 @@ 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(1024, byteCodes.length); + Assert.assertEquals(1056, byteCodes.length); } @@ -71,21 +90,113 @@ public void testMagicNumber(){ + 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()); + + } - 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); + @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()); } - return buffer.toString(); - } + { + 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("<init>", 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<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 c3f784201c26f85558eeda23f41fbe1f64b850da Mon Sep 17 00:00:00 2001 From: Korben_CHY <korben.chy@gmail.com> Date: Sun, 9 Apr 2017 23:37:05 +0800 Subject: [PATCH 186/287] 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 <zhouqiang847@gmail.com> Date: Mon, 10 Apr 2017 02:11:00 +0800 Subject: [PATCH 187/287] =?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 <E> void reverse(Stack<E> s) { + if (s.empty()) { + return; + } + E item = s.pop(); + reverse(s); + insertAtBottom(item, s); + } + + /** + * @param item 插入底部的元素 + * @param s 栈对象引用 + */ + private static <E> void insertAtBottom(E item, Stack<E> 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 <E> void remove(Stack<E> 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 <E> Object[] getTop(Stack<E> 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 <E> void getArray(Stack<E> 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<String> 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<Integer> s1; + Stack<Integer> s2; + Stack<Integer> 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 188/287] =?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 VcmZRcJpKB<B)vx~8Nh(i9RNL51ttIh literal 17 UcmZRcJpKB<B)vx~86e;v06q!@+yDRo diff --git a/group13/2931408816/.gradle/3.1/taskArtifacts/fileHashes.bin b/group13/2931408816/.gradle/3.1/taskArtifacts/fileHashes.bin index df74348046ef2a53d89f17296372058a98244eb6..12cab10b96006c620065d2e9d08ab39c598d44b7 100644 GIT binary patch delta 1409 zcmbP#l=1vI#tkMClJgsR1Fo3;^tWdKgVgB%P_Wrlf`d_Diha()-mI0G5ZR=QlT9Tp z1m-@JUtCi&$q^!$_Ih%v<O6}7|7>1vxRZVkBA9%7vaM8rz`>@f?p*dMtPsJ}-p#F2 zI~n<1c5L0Q)Zz^hOi7$<Dq|t=D2VIvmkSz+Q0>f<Q)Ltcp3OIiSbXBX07Nip{^nYl z0!D#9vn3T5<ZW+-8mc+@sjP(nQ&!Ef6UQ8<Lj=>>CyUBi2yiU?-5zj9@d!jPMSrrZ zTz~*i<(GQ}nkL;)!K0gd<pde|6W+ZR_};i2BAA>$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><GTo~#rLTv*b?5J9g}B!s?|@IGxvhn>e2wD(QFkk-mZ0+>lEwFNY4*0 z>d!9%jfhqkV!02|!8!?32ZPmYkt=^o5+<?k*IyhRqYl!c_9+qQLl9uf0TRe|gaQLY zk>&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$9ITq<oXO<H0jjJ( zk&v&G&jv^ZHA%hJ^Pb7bvP;80zdmy>Fhv6W%+1RIF`WG`rgLs9%+PZSS`@nB@~ZpO zwy;$|oWsEk(ZSUYat<rdIUGWhtrMiY4&5-Qzw#h?4oj!imY+B3S3s2WUWF)U_<(7F zbE?8u>4f^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 zcmV-`0Du3_&H<mr0kAX}0f)0q7zhEAZ5c3=wHerxr5Z@H1skyelg=D3lNB8pvqc?f z0h7fZFp~`*Fq2guNVByc2?3MVAa|2xAz_o=AsDj`A|C;hMI%X*rX%l@tt7ycg(Z=b iE+!X~T_zZljV2hAy(Ve`47sr(_!qG-U<<QBNM0Je<}QE$ diff --git a/group13/2931408816/.gradle/3.1/taskArtifacts/fileSnapshots.bin b/group13/2931408816/.gradle/3.1/taskArtifacts/fileSnapshots.bin index d65e698bbc211c9225489f2db9717cbf56f0dfef..09cd2629f84f06f97db101fe53fd4d6fe53f98c5 100644 GIT binary patch literal 114738 zcmeHQ2Ygdi7thTrql{822nY%&8=BFi8K5Xr_K-4K!gxtuXhPeRBrPo<Q&40hG8GkM z35aZD$lgQt5LvQ^Y>>+O?#q2Qt4W*E_mbfEK7Uv6d@t{uckVj(f5vSr5R{F4$^1{? z{9kG3U-`fB8sIg+Yk=1PuK`{Iyasp;@EYJXz-xfl0IvaF1H1-!4e%P^HNb0t*8r~p zUIYIX4RnMbQUrZW**Ze{FD3d41d?L#FSa3<UhbT_=4b)*e=n+!{RhKl41M=pv)xtg zbnq#_^v?!Lnx@rnb_YG*@}h%2YL@BPl$Qq(ee9>0KK#=Ldj~IDl#bq0AqCS%{$9S= zZ_8$Xj-F4eh3TWBTU<J~$hH+duQ-qC<8~@lcW2yef}X$d1*T8<nv5Rs^|LwX`O(WU zePZQ%hO0kq{0=?8Xq<y?lXaS1bJGWip7x1@KC{5`_Nt6XL~r?zgTCfYkp*uJ>cG6G zAEr<4w7TGhgNp5TItYIo)2B+~I~`j+Y5?=R0n?`|9$gqyt7rszeoh>w&wBD<^2#O; zi=*e;9KiHBw~Qq!HTiBBqPHl4>GOZgdU-bdX?sNf!O<^ECR?Igt=?H4y?^ji{QR=M zu>(KeKXW5`{*VyUmwz|=@S6jcyocz`qcDBt=FHCb4whew-lOP=>8pDFw!PN#GoK*( zf<c(R`s;N0ug32iqxUpxfaz;1{L?_X{`Y?9`5Egmef>g3c)`}?n<DyK(;f6fbEiIT zQ~6!y`3{)=+p&Y!P8HORMD(_QV)`c0?Z!=aDH9Q0W_HjA-0E_FUS=aZU66Ge(>GT= zx97r+Q{jl7J_*ye{9U0)i|~%k(R(Ir!u0L4N?a8GUat_Mk12=gJKD}(bhFGv33|`{ zqL{w7YQ&ZwihnZ^JwM_FrXMK1`P9af<%go@7dgh;p(5+UK9~Ia2tD87cl`Vj>(}oU zy1ghKJ%7Q5>BpZIC~+^cVJf1Jtb^$%zO+t^Pa4TQpFSVcFWhM({c!8g%=^=S!1TXT zzAN-e+gh~{-|?Se`lYI6_q?^sauU(!x5f0!FO0V;UFsK&=y8tky}p0uvBz0YY9hMg zA%6bBlV<07$K7GpjrlrEe>7?Txw^ZTsL=D}9sTm?ZpP{gO$JXz^f_zs^G^<*9ra<k z<4FI4(^DPvGaIyf_7};pKQD+cgz5i=o#|7d$Qv^eefbaveYmK^^^6snh~DxoOn(t| z^zBtqkK+*E5nns#OTUTO+o!>CL@&P+(_el(6hzf}R1eV?e1+-4@hxkf?fz+hL=Tr@ zdf3>hRX>uw8)l~q<~GLk@J@Tb23<;^bwIFq8>SbnwB%-kwu_i~oz}}i?^$MvaZ=gg z=>3I%#Po=+CAtkM)?fxB&pb>o@x%M`D<@`LLiAxvF+HkGR8z^2$%l|Ui%&Y}wx;dM zj|$Tx`VkqXzY!&DG;MA)8n>X!SO-1!(wtG|-xs6jsSOVL)sAn}oqlB>;`{bMOfN4z zUvJ$)m3`L{fbb@m{&r!4IGOl%GxVM=pF8O4MqBzd?y(5b)82H@4=0%S?J+U)G_De+ zSAM7L=o+zoTOht2J7RjZn5zE{6@Aqkz30VDOt0A~y<PL_2DI;h83!HoA4GL8^(nzT zpLGY*Ydt!lXkAVGGkVV)$9SmS^O1UQpT%axw_QAbUfiRHOm({R6GWeI6w@Vjhn_r| z_yKwk=+gt!r7I?<4)5HvB6|Or>zFP(u<x_R<DTq5@0nj6(_@=wm`|^7hQ>4K=-6i! z?M)pMzsW3zp5OEieqQzLMbq?Zzu!Xd?|L88>*-F_*j@hmr|9{SyD+_ew{I_=n000_ zqK{8?(3kA#aQv4=ThM#P8Zo`u_~b&{lBs0$eB=U5Z+`R2!sFe$jY0I;Eik>+&dPr_ zXtMqWde7cuOmA1Lf8Ted)zLl+K6mU#ohtp><UmU1RrLH7C4Rnh@fzBB+8yW7`^Rs_ z^n@q1Uo7pmU<9JCnSkkC*EcUz=ga-w5Pd^eOxL_)Zg=Y1w>uGi@KsFjUbp_C@mtR( zAbMek{=46Nai`Srp&RUUfuSybzK16B=N9VD%hB`G+F*Lm@Aj@({>dF?A6(_w2eluK zZajO|83lU2gTs!Zrk~Cz@$1?W4BcUe^g4Q`(T`6{EJ5`7_3-<9oi9*p#KHk(5q-R4 zoivRZ@^0UUtrjrPXW-|1m;T67zr<+fdu@*XP5SuBqz9*UozU|g9sQg9vh~;RzpTg1 z>lNSP_n1FDT=7tNQhoIN!X21y6{@?gO#N|^oi12>3)5{qzA!JiNiz0Te0fYye`nr; zx)aivbt$brruVJT{rv$uglEzF$1lS4LDdJY*&J54GorV;?4TR8)f#<&gqe45n=l>! z2`%7zNGAT@yasp;@EYJXz-xfl0IvaF1H1-!4e%P^HNb0t*8r~pUIV-acn$Cx;5EQ& zfY$)80bT>V26zqd8sIg+Yk=1PuK`{Iyasp;@EZ8<X+Q=)X%}pp=th9OK%8h!ro^en z-lQ%uP2AY5OG~CwY*ulMM5?^He)84%qppk_e|_OpvCgbFru3r8;$9YWTB=kgj#0~` za*0YMRX`G{PonyYw4@CPIe9G+Id0U_h#sF$jxYM-Tehb|yKe{Z8}`#5^bj^W`tcS4 zF0lJS;=UF#HI=e3-xtmNr^rNF;AaMo84<aC{q;pH)t%ovyKvO3<Z}Zy&>x=#KOWFw zxBt?O0M`QZ@u?OwREf<<S)mRB&Xb6&nf6`J)7oW2{~A!F&i94~OQ0%1A$lBaf^7}m z2(Xh~RrG~l%JwUX$i7AYu6ef5*JDo%O`k6L>{cY*r`zcdDGD1wHz7?DL_(VI0BkT+ zShzzd2)itFpSB`2{lq#ri7Bf%*{n}XqO8#|VuR8Cr${O`TY8C1luc_PjVV@9Z?i4Q zm?B1hL|bk8B%?OkWT8}IsYoi4h*fHx+Mp##wN56}sZ~_0TB43s>tiJb9jT^bq*_w1 zR%q3vmp4S)-$2h0B62>p_W5$bl|{DGrH_ujbLTzo1XnVGQwE7lXQ1>_x!hooD=A7J zqa(FagHlV$Wh$vwCsmP(7@0D=;7V7)t3>bL*Ku*>niXd@S~;lllGw1*Txgt;S*;)? zN{L)bN~NSktuw?bRVp=HTVwRfSgDkP|41pBR-yBd*+tKji_OfM_GruQzb9<UjJO^@ zF6=-)#TAn&DP|jKGn!MZVyO&{2(?sgkmwDRR2^f`$|;FLMk)2Aj?`0>(xB49u@IwB z#*k{)Uq;ivL?fYJT+u!aI<&vFs#Jr%#IU$!Flj<~1P<%)UtpV0Hz9~R$=0NWgWhUR zk&3Mroj4f|c(I90C&juH0RH5fg*b(>0dOf0Z1AoPz>Pq%6KhGUQ3t@Iz%vzhu#vjn za73k(MC8&f(i`vm_RFq<b-wLgY((7cpa|4HjY^{!fl{k?n6YWHp~Km+QK#B;oD&6J z1VKX$jVYuhGtNR$ZOnQs+2Nj|^y2qw-yQrYW_a`D+K<7%L6EGKF{L-9Z)LRF7=4Yb zKkVDubB7xhQzA-!S}QgKWCcO01{MpM=_1tpH6Lo;(JH5n2p=+F>W;$~z>^>d)!ar| zNSoQhDC*a?B9&ppnsMez`f?2lwpjxn20^CQa2;jjnOo*awb&60$>n!SQg0VpuqP<; zxb)e_FCT8WTeVf09VdS2e62n8Nr2Zwvn`Rb0Pr-RonmJyZk_2leup%fQoK*Gj2^0p z4i742eH;&-1x2iEligb9jjft~wf8jo<Na$1*UrBO{t1d)t{cegKks&{Rk+E+D)*}0 zypwfo5_lXGk?6IWnOIkk_Nzaw<-PA0yzEqZ^3=1#gQO(aO>KvHq^xAqy_F1Ihj!@| z*KIXCkc6+K&nU3GfPhYoG_!c<#&(-F&6uRe=B_S@v|8y?4P1bL{X8^)KO?=$;f_Be zy{2a*n2{U4mTmz#BM}_~b4Vh(1oo6fXo7J}BJ`nlP9jXfkjQmU@jNIIrjR`;5vGtl zDiNkoJS!2V5IigqrVu+V1xKJ9j!T3ounQwPFA@6CJTMWa5Ir#wrqDYw5vGtkGX+ac zt{a@^p@}d->uo1}YO%qVL^lGQW&5;=PEC3$l}gc5DZ0#PyE_OSnKB{sh$FD=r5geM z;D))|Sxs2(4EJ2@s6K0sSoZ^{>(@X&2-?3MkZ+=SIr05F0q2Q9{+B`GEOz2r_Ff<& zMVqS4%F<VFKU*~pjNLM6GyCW|nm=AT9d`s$ir9h9GLoqxeoi>|L(!6*Hl|No)T`D8 z_K`q;B}3>IBi5U1B0C&cj^6Y3%|#_DjN0@JZ1r#ozH+cfuCv5LVUE76(%fbdG2#tb z6!w0Lmq$B18(6sB%D5_Z+4o8Kt2H~a%}BNM&tqv5SIdgoN=BrHtAA=6JgMvk8zWWt z#ZK49eDwWS-yPms@$li*kHDs2b)^fg%g9!%@1Yy&4i_}{N^B~AwbRR?!5jT(2WG?~ zqg0!9J9Z76_du~Kde`knU`y~-Rz->j|MbH>@9plt`mH1H&TrA|bT28`94zUabJHPQ zxri;_L_Vmy^UFKMM?Y9xB?D{^mT=C|R>khkWcqeOmDL$xQA<Y)?oKcEc|Gf|U|R?X z=(4nx>@$DZmwhj`RGF53fA;$2CBc)=!yC-#&$i^*#AaVsnn*rxIJ@mTg}woMf~7xq z`Koj>T8%b5M+VNjRP{m6Gany_o@Q+LY+Gv(1S^Pf?L7~?6@>kJZj0LA=bD~hH{@CA z@vD-{?X)Z$&AxLl_dOE}W_MdL1L{VXagmq$cX=3Ad&Km2>n;2V1W{pbHqegh4Nfkb zFy>yJFAEH#YS(NKjO`pL%ys?x`M3V+7A?kpqwi>_T4d_bslizNaW^{Fe?0BZtb5)x zeA(Ng86#V?SFb6j55~rcg>$a|Sh_dcPETG_?a!wACO<t0+p%o~^an<q^x+Ql7Dnln zRtz4<=_<Zqguw1!ED2u-s=!u(ZUnf>&Gcu2Fm>kSR2Zh&5`|=1GgEXh*mN&9E3!|P z*x8B#MvW=abc|KB&6rGCZDew)Rirhh5RqRT>@;oXqG{VIt-evXu%TN!s4Y;_hxVgj zz2qn>-GqXQ0RjSuga9G|L_!dt03sm>yC4eqBN9Rv3?LF%_aNoI6WZ01D;hu~u#R*4 zE1KI@=m`f9389S#5DBb%-u%^DPJloV#mWg0AQD0t5(wfHa5JAhF##eWq(K29A(T-8 zA|cda0U{y9ae*KT=zj3V*0m=vKqR~t$UsnxBKsKy5D7s%>bfm%p4b49z`7qh_x%$e z+;Rd3f~qn%lgJYt2+H1$RF)Gw5R`oY_hhd4Ku|VOEM4vZ0g>?9CQEwSzkXzSn$l8? zHZl6QTqKo>VWyr;s?{o_dV@qQQK(5u8>2PA3_gieO)1G(iA+w)DN2HV6HWgH#-hX2 z&2p;9-SxtMTDPyu<=Yo#C)i%!)Xm>LpcFsUNGHoClF2#?L_fs%FVQ-)g@P%YGO;{{ zjEU9jWHC~;JO-vkQn7l8LLyPXG*c<5)5_IagG4GJCGJ0k`K2<X+oVsUN)<U>zedBs z>*~#YLwl6ZE@eNvG-@!!rNUOgwuo**5Y9<<sf`{X+-8@$vfwbg)RPVN;d7K->Wdu? zJmDn1HD{(`yFC>Ldz4AX8Pt91-6us<@3;EV^hx_E{Yr6@pqPtLc8kSDsP*fGW5-$w z>b3ykk>Ov5pJgAPr?aMW5z77e;3D0z&xdJKTW&1!-TlNd;-d$TvhNA<Lpq1e;v!h{ zRdXs0Z2JDSU5O{^M$J6>EBoO?ehB6?S6n2!pnQM&wR(d-whXGZH9=zR2|@L+UujT1 z;2BnQr{|nu#e@3(m&EZqN(vq#c~IY)J;IL%_3a_2cq3+_58Y0%Jg6_u9h5+R8XnZA zE28+TE$2>!u|dx`KOWR~Mrbor)2TGyk$yn|bI=TMm_<(MJVX6>P#@I`Lc#tXE3ZrU z<`C@1gZgx$K9ertp+Wa!L(buTK{1N#xFQegyW1TYY~?|HrmR@*n<!El59-6ppne~N z#CV)J*I8_Pct-v4pgs@kzfuKEjODu{^E{~knv{%0p#BC3kgcR!KtO$t%AwF$8+IJn zQGJfep?LDa78&5E9EvY~46aY;LlM~LsGLU5x<JJ&<DBjWPh_7ku^yi02S)8~qq~Ub z3GEXm)<a+X5YKUlb&<>y+vljBOfKE&G+SIm^91+lN&sP7XmmfAl>iFd69@`iryJ*$ z0BEHFVG)iK0PI~u*Z1W({-5C!kV*h9yc~-**Ew)rcw&bv$HD(TIlFjenQXJ=-FCH_ z^1h)OK|TEKxa#Rmu*)ODgXP3_-=cY0D;XL0Z)&nExx+uzmYtbd_0Xs=4c954zGd`S zmKgbB3UnOW=7@QD;_1XPdnX*4!F6!}-}1RH=!|$fs#KB=TiWIvv9|KYLZ?Q31%fvE zobGo<v?D(+Xa`is3f9np*5|)5{K$3ktZ&U_AAL?>cW%<alY5UIczEMQ>HTk(KamBU z$^{<N+m4s31^lLY&6BIc<jPecz|BD9$;H79#XVQfGr)_b>F=H^=fU>X^W~&@=!F8K zVYhuoHzDA+(46j{@s2WinLB{rLZPdj-$JuHL%j@^Y<@j@6~Le*zlGYXG~2gDSf1Ip z`u;;(=mfZUm$?YrX}SpoHTiQ*4wr)Qi*ioW!WnJKSeE>v%rD9;*{=UTi!#RxFcZtb zIk4msGXX#l>Pm2J6}x;N2D1VLEcxWjmzbn4?)1J#`&L?x;ip`qNWR5#ph$d)$-D%4 zI!`lviAlW}@0z}cnOnxSXE_P>GjVbcG(wS`PK?)y0P-a!;T1x;_o$2NT*I~a5|jRp zJ$DougCm}mB)CS&eNS0;`Ergq4TcqjLQdJwlgqvTaJ-${qUKpff-f=YsKf3EP;|3_ zJc~&1B_{D@@_2kXY%{z#yk;dPU)KT>*+!xtl@GWpAOSd2BggmJ0Z;#;A8HJ60SWMW zT~7`|{(5rgE-!NpV*R`W_UimmSH_LMzHq8oXXYKSQn^Is8#VFm0^_lMnK(u*dsX#0 z4{5vu)+c7?d-VOs9I(O~0)em+-3V}nn~)<~m(j5LQ(BUZap7r=DWoM62#I@v<tR3% z*;3PNsQ&hXiqFqf@4asCA7_Sat^U=rw%~q%g<({Jq`BSYqo_`s_s*0)crfN_^>R}I z>-UPHGpw)9a8ZrOsLvoGOOD<-q<-Z`Ym=wkEZ)6s?PYKm7e>Qfys!qgIJyzwJU1G% zP^o4MGgi=u0m6uDf#QX6E&%p%6AGLC^Ds-8=qrMEm5G=`pU4hKikvG>qAfXzh+MO2 z;hq~Qw>}dZ5?UpHu<$Q%C^Y2s*jSLTAKsmHH*Dh<YorSm+P@;}ZvY2FLs-W-+P(=Q zS<m0IPKo%Si=xZL8rwSk-gIQB3;?IWgXA21?5o`;v%Z=*>$}>``_=en1UMENI(0_} zT@*X=x7|leemHZQNqoJnv2>sFfc49&(c<Q9W?8KO+z#B@VYP~_w#+0-q_e`%z>(I} zW0|HE4=*%ay)<g%zRuu5KqZ0e2Nmrijxko>Vcf;r0@>aLlctsKoxoL)v6p@@!fP}$ zL}>g9(@!poO`Ab{J7!y1Q2hE^;9|hEVuGXL?*MWWBUOk@a4?jbvT^l&S>bx~>uso1 zuAbs0SD^`Bw4X}qdXv2<`0*UwQ;-8s@0%JL34IpN{;|-!t^*>POpK~p{ecY{8HGt2 zDmVfgyj`^byj}GiH{F%Z5CX#RKpVh-w|{NSZ8)KC|8iuwWE+R#xF#LqqP<#zUN+ba z+9K@r&m9REdVAjEQ&q~<>AF$DmEn>XSv{;lyPT^_Ue-_ly3X!xmpgw^sfY0$u#+3Z zB`<P1t!ul8t($zfxy2ustFFBsGe<S)Ol&BK=(PXrB931G)-;>*%e1i->q?|&cB;9$ z-zqO!bT_B%V%CmWvgFUN&n1-__&hB33u*$LHRbDev9P%?lXoWFgn~kx`8HIrHic9q z5v$ZXwLwdgYMo4`Q>&<0wL~4O*2hW=I#Nx=NVTM1t<b7ToR?&^>647wXp@Cf!MfA% z4XE<;d}{6U<$^1VY^O^f9ewA{dtpaBMzbHj4R~Lf$d+hM>y>EhYqs>ZiZZM=3q>Z2 z@t;zWT%;E3<T8VTQfLjNQmu_uP!c(*QmIv>I!30G>0qU7xm>T8D<t@5P)ztUB<3^y zs;mPI(^|bVt;=`%M#TNsxA^#uyz3W^#MHE;Br*Pz?mn4FDvr^rs2G_<A46&tayccZ zbZ|Jx^;)G)PwBNfxkRUu#Oe(s{-M3!;SZ5YC87<_wuzdzo*yO7m_A_u5$0)C`O)(k zsi`tC{jVO$u)-HDms}^7s`YY8Ez!zl5;!PhRj|_~u?mAyEr*5CNx1|{tdM9`3daxa za>;c_tg@#+$(+7!_O&&Ngg2?NJ;V7@=<Jt54_gS$)1uHcExMI%LQv)pcJ0#`F<rR9 z9)g3DCSfZ6S?-yjJbac-U~gYTGs1Dpte?$uV`$f`sJD%X)D^0B!8AeJa_F;xrx({9 zp9Y=;M#uQm#SM~-q_t99n$2u6l1X-%7D%s*9+j?6z4?4F+5VmQKLN{i_Fc5YRh|9p zEYQGW8S?SY2J4pf#MGSGiIa@9v1CcJ!4vjBoDCzU%UtJ=3unCdvwp_+``fVu;s!dK z(VPM|rF4>r{G-M3E_2tl`f!urWQ~e@nycA{Ao4EWCw5;HBOcjE`E#*Tsn?Ebemk4F zQ1=Vl_Xp=)yf`{97U?c|x5*^Wn0+ZFK5mtCifmi(b=Sc@${F!Kj-FU(%BL?5#GX7g zwAR+LYl5%4*05YEBb=(!v#06{CI8U<RwrS?{3Au#zHq|-j_qWm`Z7ZGlnjuj+$=lo z@g#ZG1+88V04(2U>c3EK9cdMmxqkEe$TnS)4-7ih<-Ig;BcO{IX|a%*Aiy1DXNvNc zI@*j$Ob3+~{qf$-xsv!Vn|9xKZ)yAU;1tK2Fed}H-67cqfjOBDIHD{@D@-s3Y@_}; zvlEl{%>b|+`|KB2aVv8#V~X2$WQl4lyAiXo{^8cMZZ3=ds1<}IiXMbEeW9JOZKNB) zcHyfSrcykz=c8ToD1fjy>xL2Xg?V8Hk$3=D_M_+UZA{r}0PeCqg>w2rSL+A>Pskvj zDZ#maEw(_#4bmX4V`*egNvA9}%7VkSFWvjGf6tGU(JKn~`{Q7p$35B3Rmii1Sg@A; zI!$df__K_%C8@rpI{vVq?F6hm2-YsqoI<rpOV&Eo7H^r}V@hJ@dJB?kU74wiFU9_9 z;_sLeH%YNsGO^Y!d>Hrhp)R|L<D+j1B7Qi=!G7+yTn&@Vy|7qiDr{YFE#p$>(ix3v z-hQ-dK@dk-JIZ2(X94@7M?|K+zw>Eofi6|IrBqAY6u&$wh=S3kVoOH>ngfG>O8uh# zx%P)2t!wl1k*xY`<NkRV{&rlT2gU`QB2HX+@?Pa;>c2JdLq`lT%l~EHNb^0`S~rPn z5Z$~@QvkMmfUq2{sF*2}R~^%XM#V&EW9yM@)~6*=M5M4>ouQK}M>Vc~b$YvLePAIu zxP|Y7`?<G5Y`mL+cQep#9Hpxpr%LqxeH|B9u32$rqm_dyFNqEFv>E&X^LaNzGUYIR z{7@L3(_^A+S__=fR%S}OyW1FFomxRkloGj=luAj7T4#t=LdO@3evi>BW2I6G{v)Mi zT7}O2$FBW5x!BCCX^*z-{(Hiv%!uo+NpW_&n<0F#KoFimHzA1P9tmc>ID57un*Ayi zz<P0Z?|krZgvHrez7a5IelCzKAoM{;g9)>zb28sMw!=Z?A0VAG98B~Lx_mj}!9?H9 zY+F2e)n5*Pa0qD64M_AvghN1kIY7chUzRUW@Oxzt=YR<l=FkL%33D(|Vb(9X$fb|` zgM|rG0B~WVBkS0p$I{~t3={Dz7oE<gYBzou87B14*air5`b>tcAJ8z-8`@sO>9Ztv z_e)@0Ku@JoFho8@ml>@ib%_+ZIy#ePo(fwc-B`b00yB3<q#-LonvWB-w^MbYuJFj+ zfo?*;quF`A(;D}Icf6iQv+Z?}b5{<7w_}`<N3)HvVwWFk<I!w$ivLqk%%j=%YdiCx zF&@pfqG--nMzeduy*T_DZ0G4lgg<86T0*eDs}aDsZZU-7HtfNR0Py!iS!`#><1w9+ z9$Z#S@Gt;s@VGkL>EdHQZpe>8;OUkHo7hH1au>q;asq-dCtUr9Y+tG5&sg*tU=R#N zAVHAj1(PU4WO?x784SW8$;Dn^xyXk<!^UL^BO<efF9dZ_BO<fKEwGM+<-WrB6MYgg z3m*}gEh-=gqug}`AR@D!y;#0)&Yw~4b#WvjvqfJ8L0PW*1`(Mp?gZL+e?x;0RDrDm z-3V}%8%qP74q;?ya;h<jYH7A5!9+A`W{M67*-k0NUFMS|KB^j^B-UtSN;K_SinbY( zVJtkEoXRALmweb;)A;n%Z@&|5S@G_H8Jl6O2dL=_srnMaSVQS11Z)?WaKSZU5hrt+ zMF;O}($eu)_RQA_pLC7dcjm2XxAs?GTA<~Xdr(ZlI9kjHu-&8^0siEsPo3h>u`;kD zF9(88F5mvdM;Dcbhnmvo=_V9ZWBKk8JmNg8c|atve5<VwMl^5-nX!EPNDj>KSq(A` z-Sw782*QG!^X^0>1i|KU$rlSscRBeZN2Gn05RpTh-BioROpfR~q2}}c*FKOF39Nf& za<{)+WMh)x;gH@P_>*RKIdC8Yqphc>Z&W;&D!V#t_^Mi$sEVpkk&+2#V5IzrNL&AW z)bRV(L3Lhyv0MBFk-&1%4L{Z-myj4oj-cHw&&YUETJiTXM~gHXe5Xz1q?EC>Lq(HJ zXagf<JEGYy73XDS{gW=wEc2+<#8A<sJv@Ywaow=xFD5qM()>aH22*Np?{kevU_E*z zPcztEgSS8H{m!AXL$aQ<JiNbt#F2+YLTH}vh=fo(m=g)C$FSwzk0>oKC>xY#6b3WA zm-nLDBsUMclKNAVc@b+j!i6FTo3|5%%??-u#lXoKWD1H%IUjO~gb)T$hy>P)ZFrk% zFz+)!#{;*Z8_1NSbUgbMh38=U;7NlDE-9yuNS}l)fw1Ge@pcRMVOEp-t6P`p|L+*n zC$@)MOEhV_ib!C&5T#es2)njmPlPN~P9y{yHy|{888B|kfc@)%4Ed3@!QF*6d{MIh zo1$c)e*+L-H;w(eX{BkWh7bb2LJ0T@&kI38P7<2vGE8D7Ed{U-veR+Jt}N^*FE`~o zJlQz#UG~#{y?qsCCq{?BY}cQ$l0@X|8xd160uSPx<&eyhXQ`_<FRi)x^Bb2-9DPQz zpFN(tDx4K#Tm&mK^X>gh=AW3S*hpPdPAQlLJw8Huzzh1qW~N)9ii*%GMX}=pc&`h- zJTc#c)!PBip3I1+2{h(;uZwH2dM@$UK>==@h<<Ro%gLYjx>y}Zf!jRt<|$yxH!+8H z-s|EPf$fgE<f=>F>yqu}Jg*>)N8qi?%*BPd?YloSCV8)mJxeF2vFJxs9q)C4iGOK~ z!5tKPg7>=MQbSC|z8pt%j)kpwuS;+HX!ahjpFM1q_qycma$xVfmN(A_v~_u}i<tMi z*n?E<&N<(as=U{Q>&sVouZxb<N)1XaC6}qBTAfryDq>_x9RKaSYKO1U#_Cltyw~Ob zv5Xw@y4;3n^cA`V#OuOQ895r*#-1G%T;GM0>NuW!oCvRmlk!Kt_~CP)-gC#uH<;~* zk0V#l3t@Wh5k3$Iu^Q0#1klC$?cfW#BE!@5LYUx4e?a>_f?2eONEQePif)`2?V$${ z5EkS(f5tvc>H6^;r_V5akYknO>=_qcj#&;kj<fZ`6T4VhuY>6Bwerc?!=uSynv<ov z6D?*hzGi6EV0-t%H*avA?C)DVm&J&YZCZhc!WB2<_rgy#-!X9D{EE=sN?3fjJH1t` z@=7ZPmy9sF5du14Pf!xR5Y&N<&cv)juzza?>K^x$$T&Ee-7_&g4Yz!+vwpC})_Bg@ zm|q<1G;QaiY1=BTzEQZap<6qsH6YDHFA#-cw?Rb{0%(`;%NM+wB}O7uihEhiX{l0~ zI9Er7ml?ysy=Q(dA{^X0<|pU>#`0AhPMos4VB17Dp`Z>wA@~U)m#9=yg%6*Em+8;M zO}U%Nuj78s@!&@(3fvpB44;4)vo5@x#%$=uBn7)rk(V+hK}aQY#ub2Il#p_=&oLm0 ztIL*h@~*mwhO@xI>yQK<B0}bz1J2duMtSQ{aclZIA7*><OaTuOJ-X*FduD)#h#u)f zBi5s5C=&Zuvbvk)UbY?A7(RFXdFFqIL={6KGTY^Hp_cv4H7Mn+6PdXGAXpH7Mj-{a z0B82p?_gLoIcI(cLn3-jcV1bSt-4tV=Y4}frF{dAVQn;<-9mvlyMxtz$9Ln2lfJpS zNHllW{^WeKUmDKK{^$rk3YFT)UW%gzJK-C=uKC{Jh(}EWKN6{7c?1!>9yqO6;O=A0 zmci$TnB3)ibJyES=HfugAd%?|lwK;A8w_$KMd@SMh&;-6qqHAtghe4!(~^?J_)n=w zDw46D?+rZthyF;Gnko}#z<>2fhDAGQx#T*rRLy4O5%6?i`5_j4J7gl6tb^4oZDRbF zXr0+YK^bLYc?=m7tJle5q-uGL+907~^%8|dqJUv#Qc|attF;D+R6<JJe+ut}l!;8F zg@{c0G^$jQ)AegK9K5dH+&8pG!Rfru;2>UL2@d2_TrruFVz!YsqdCPYmdZpDG0XYh z&=Xj8KXhpD9=`kqb$fyMc@G~(I$pN`1=_<WtN~jkx)I<C+W}O_@TA8~G+a2-l5AE~ zt3Yc^AuX9eNZbo7N3l80mYQZ0LH<PKv+YaXJ>TwtU|v}1rGuY!I0x<rSQthnNSeKG zC2u*@t<w3q?{8moF+Ht0S9gi{>I@gvh>ZFSBJyNgZ6E6Q%Dq?4zH)EP;2)CU3M!0- z1EyeS*xJ&K0Oz^Un1xC;TbQweMhp-Zy%s25V&)hJz(J2)jio@B?4O5O!b@&Muu8Lt zsS+Tv<4z)X=V_uXIf;n89oG4qsuNajJ$K)-;;+a37K8nvA*)Md6cV(swy&IeR-j7N zKku!!L};tBUz!9hGTxMGwE}QEaKpxG6<ckYNt8%uwGxpdt*OT{O)DN=Xt;W5)X06E z!GnNGq9v_Vw2L^#Sbc|a7jFw>dlyWaR=RfrSHWXm`oRcqk<1XG;jnpb|IyQ*_DQcg zuKA{fou41#3heMAh6#>_zXR3>CaW09ATq(hP-@D?)%RtE>&>sXp;EbeikDmgZeBh+ zmDKendr|P?Jx^oYEoYdg_w@{ogdrPNCJY$ezj(9W-3Mju?z0r`F9kKUg?<LMV{{|H zIc~Zu+a3sml>=@20N(VmF?VQ$zUi}zo6R-bI26Y<=@1v~)d+CeSnW4@9H_jt{mI7H zzItPxPPw*X)-A5?N6Cwf?uLq8%$sNGeGpf_M6<W2H*9^RTh<gf%Zb0>EcX`gEL;pt z%sF%u3c}6^8`sr9Y(&$`Lh6$!jr|H@t0vj3PowW+iP4});24oq;|=)Gpde<r1L~8E z+Gvx7QfX)~Nvere%2isKN^8(lF=VVvCsoS~F%qR(NyQix2CXF4AXm#23YnKTK)i<j z$Bx)k?K5#o)Qf2|4j!*wB>mp4$6<f6EwGXin38EJrAjMT$P}?El8Pl&I{065g;ph% zDwI;STBTD<4YAqfMfr-1ye;2cyEwwQCBF2N#w$Mh_}ZATBW%jch^kgma+RD?C=F_< zj8e<wv9W4{(hwVKkm%HMEd~EmMuVUpvbw1Chbcd|IC?vx8#vT8?(D7Bv%+?~qL>;N zL`g#<N*aF=CD&g@)4xO=-Y>3bp9US;-&$3wL0@86+%g!LFI+|+pijeggl<AmXb*s+ z7G^WSk(*9xthO|LrbcJhGjXGEEZYOAHO@e44IIo?bBf&lBic=dehJZd0FJTuGFk}A zVzfd*064|Tdo`wXDD!#F-mOV8lkgh=JQ%a4V;8m1;xjBXjgm;KwJE&!sg<22?EiF< zh>Vo2uC=wuo&u-ho8N6*{pum;o#jjrdex=RE}SyZG)YcPGG|g$Cwh&bKT%M3MyaFE zZ9OLz*eIUeRa2cl^Pi_z>z=T6p&J1Xzp_yFgBqUt%pqGtk9kxbkm9$6ULq4^(^{ZP ztRl35VRbq8F@9TkJ+_6v;N1CxZY*yLL{pCT1)>Fq8w1gi`<;P^50$Nf=*jioK*R@q zb0E6I(S4O(w7bF9k!}R|J)gUSo=T-4T$G~AjJ8|+Xlu|yE<_vHn$nE`d-KV~ZSxTp z%CFF_uY)E9G=u(NQ9$~QE`|!ohuwj8U{7&fUXF~o%iKxtVrBstYx}D9jb9()%bc@+ zKM`3u?CP8a=aPFCmo>jWY-~mq2t{%$4l?Q<27rsJWygGN>n`(WzH#!z{>!&dw#XQm zFn~UYckp3xc{`kYrFlzG7CeS40j%#KxJ`hQ`TSPK27(j7c^|BXxexXkSMSCqSDsUi z1y6nGvrr#_ppcPnLP2rX7aO7_m#d9%9Mrzc#W}COvH3M;f$%GLeqwko3($HboSvPv z7@aypYo!wY;!{v@BagGIefkGvWfM;IA{D*ng~*C0T;M}KvCBEwuCCV(d%RDth5mu1 z_5ex^`nOypje%H{Ql^*2N^}yvPHLbG6a*9vDw$j*mFN{JLyS^Ik+CWYLRx7lMq4!f z8w7~S9>foyQQ=~uR`OV`u3>BP+99Aj^9C*As6P$<i#_}gBA+sizu|xGKlL5{$Ahy9 z8Ku;dI*9mDN`p$PRg*CaWelnIADk_e4tHbl47P`K6M_Qy183=#j5To9?PV_ZcYeWH zU+-lDoXzRo4sbT>m8~)wHTQ#s6P!gma~$jz2E82m)=g2%X&`KEjStO(j2mXt=p~>{ zvYxPUgI>}C=Zs$Rwjb@?;B7zXx}?23&;)Ur?k=Zc=eTB^4$QgD^OVZle%O&^SDt;v z@U-8ENYB$QZ~M`Xa^CiHc)xku@4xJrx7&U~xc`GJy0L8g<<|q_%gO=y^}zUgvEBO1 zuLmZlmt*sfhz}+EkAQZcupn&!2E;)j)I)X}y0Pb=pp_1U1=zw2?R^MM5cV7t_>C?` z4SNm>FE2+28MXjH9}Mtth6Rw=@d)J1$7%Yx9BCNy?{uZ9qNbnB>iEl%pUzEQQ80r( z(-?ig%w8e-qHy@zOIp&)p+FEx|JEyP{{sFWG<5%%fR~i!@3Y-u`#3m;TbgZ2(E4Sd z`%N_P@=8%s=p2#b`(GKp2Sgt9Dtr@mL<HU7=E6@;SDPGw|L^Hp9uA|z2VmPlH=!Vk zA0GVhU{-Ioh62VC*xShQ8#&p?y}X>=job$V$3`An{=5IPNQ2kSody$uL%^K|UbBP( zSb5NIt+`gyaQBIE;!cD0aPlNt&Ox}G<vPGZF0Ur0t5b}VTnBh`D0~E(HN4epMLw$R zFg|bfLZodUY}@EYfD`#VL()fPTr>jd+)*^*FOFWVajg!q<)mcL(et`*!ba9zk#%y= zd{`U<PR@KBT77+x3s+Qlp%GQ-QTd*OzHKaOxpr-f`d#yFE%@Z@R)FGztV$zi&fQ(& zi~Y6UtvGq-G8#QS1m}F%X4rnE8vzdGQwL0Xvb{giOaj6puO4-d(17eO)!4xkI^}s^ zK9L6B@1{L@B4<{W2!^SN5PTzQghQ}g;2f0mT;aWAT^cSN^!K;|dj_1^TX$4GQoMYB zJ6-kQ66+nMfkh28xfT^T#|>YXItJOwD&!Ze^3uhw1q+mQFQzR#F-q95=!5B1)(wdV zN7?^Gx-vn2<0`#;hRLcyRPQAS@*6ekg(J@U2jJEH06qscet8Zv56!Yt-?Tk-w*Sey zrg7cE3f!$b7OrGrJ80`=Eo{r^Mu3C)?8R(rDn#iy+wuUv<N2FLi$+hj-q9fA0nP_| z6)IG6Dcg=`Kf$oN#iM-wJna<rwE6a{%goyUsAlDu<I|)6{^05)ID~~8;SkOS@&6AB C2a|FD delta 140 zcmdng!2Y|DZG(vfW58rni35{)B_~YYD(Nv<RLWy=sg%Uzr9gaDDq(V}w8Z48(i0|! z${0+ZD<d)atW4r$H(Bw?rLq;9W#u>-C)>%pPo67pF!`yx#AHzgiOI1F29uWp>8n6& ss^~F!t)jtXRV9PTtx6t~pDI}~u}|En_(Oc7L5D!IqsMkf55`><0I07qDgXcg 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;PUr7rAtG8<x%C{RNK?EnaOs<tw z;E!R<<<WQ<v=SoNJ$Z_xqDu9~i#@X50lE;eX&x~9VKf5+ljTOmAL1Jg9*Ays^zd~K zGiG35ECu3R5M~7GW9mxINh~fdNG!=XXBX<<%n;MtUYuWAl$`2!|IN%LdVgmC6*2aw zq!yQC<|US7=I6O&7BNa*HkqbaKXYx^)|qDQLXwjOeUtnzF}hgA6c;7OWF?j*#uS&7 zrc}lx=ci=mr5hO-n#ZIU<(C#18pjw}8XKAzSXdaE#pI+G7w6}h#3Yqw=A^`A=a=MU z=IMf+lUf`z`KE7~Nfpq&Z23T(4#H^eU8=rr!p`Zf7Et##@W1@q!TdCS^1KRhbyLGj zyfM>b4A30@{@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<y{%(roP)g% zq9A2f%5nVGs<wIZ*#=2xvyC2;TdbA#0*z(vOUld(N-ZwUDFJ2E2N6sY+7Gj;&MZnT z$S*1>*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 @@ <module name="lesson2_test" target="1.8" /> <module name="lesson3_main" target="1.8" /> <module name="lesson3_test" target="1.8" /> + <module name="lesson4_main" target="1.8" /> + <module name="lesson4_test" target="1.8" /> + <module name="lesson5_main" target="1.8" /> + <module name="lesson5_test" target="1.8" /> </bytecodeTargetLevel> </component> </project> \ 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 @@ <option value="$PROJECT_DIR$/lesson1" /> <option value="$PROJECT_DIR$/lesson2" /> <option value="$PROJECT_DIR$/lesson3" /> + <option value="$PROJECT_DIR$/lesson4" /> + <option value="$PROJECT_DIR$/lesson5" /> </set> </option> </GradleProjectSettings> 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 @@ <component name="ProjectModuleManager"> <modules> <module fileurl="file://$PROJECT_DIR$/.idea/modules/2931408816.iml" filepath="$PROJECT_DIR$/.idea/modules/2931408816.iml" /> - <module fileurl="file://$PROJECT_DIR$/.idea/modules/lesson3/2931408816-lesson3.iml" filepath="$PROJECT_DIR$/.idea/modules/lesson3/2931408816-lesson3.iml" group="lesson3" /> + <module fileurl="file://D:\src\java\study\coding2017\group13\2931408816\.idea\modules\lesson3\2931408816-lesson3.iml" filepath="D:\src\java\study\coding2017\group13\2931408816\.idea\modules\lesson3\2931408816-lesson3.iml" group="lesson3" /> <module fileurl="file://$PROJECT_DIR$/.idea/modules/2931408816_main.iml" filepath="$PROJECT_DIR$/.idea/modules/2931408816_main.iml" group="2931408816" /> <module fileurl="file://$PROJECT_DIR$/.idea/modules/2931408816_test.iml" filepath="$PROJECT_DIR$/.idea/modules/2931408816_test.iml" group="2931408816" /> <module fileurl="file://$PROJECT_DIR$/.idea/modules/lesson1/lesson1.iml" filepath="$PROJECT_DIR$/.idea/modules/lesson1/lesson1.iml" group="lesson1" /> @@ -12,9 +12,16 @@ <module fileurl="file://$PROJECT_DIR$/.idea/modules/lesson2/lesson2.iml" filepath="$PROJECT_DIR$/.idea/modules/lesson2/lesson2.iml" group="lesson2" /> <module fileurl="file://$PROJECT_DIR$/.idea/modules/lesson2/lesson2_main.iml" filepath="$PROJECT_DIR$/.idea/modules/lesson2/lesson2_main.iml" group="lesson2" /> <module fileurl="file://$PROJECT_DIR$/.idea/modules/lesson2/lesson2_test.iml" filepath="$PROJECT_DIR$/.idea/modules/lesson2/lesson2_test.iml" group="lesson2" /> - <module fileurl="file://$PROJECT_DIR$/.idea/modules/lesson3.iml" filepath="$PROJECT_DIR$/.idea/modules/lesson3.iml" /> + <module fileurl="file://$PROJECT_DIR$/.idea/modules/lesson3/lesson3.iml" filepath="$PROJECT_DIR$/.idea/modules/lesson3/lesson3.iml" group="lesson3" /> + <module fileurl="file://D:\src\java\study\coding2017\group13\2931408816\.idea\modules\lesson3.iml" filepath="D:\src\java\study\coding2017\group13\2931408816\.idea\modules\lesson3.iml" /> <module fileurl="file://$PROJECT_DIR$/.idea/modules/lesson3/lesson3_main.iml" filepath="$PROJECT_DIR$/.idea/modules/lesson3/lesson3_main.iml" group="lesson3" /> <module fileurl="file://$PROJECT_DIR$/.idea/modules/lesson3/lesson3_test.iml" filepath="$PROJECT_DIR$/.idea/modules/lesson3/lesson3_test.iml" group="lesson3" /> + <module fileurl="file://$PROJECT_DIR$/.idea/modules/lesson4.iml" filepath="$PROJECT_DIR$/.idea/modules/lesson4.iml" group="lesson4" /> + <module fileurl="file://$PROJECT_DIR$/.idea/modules/lesson4/lesson4_main.iml" filepath="$PROJECT_DIR$/.idea/modules/lesson4/lesson4_main.iml" group="lesson4" /> + <module fileurl="file://$PROJECT_DIR$/.idea/modules/lesson4/lesson4_test.iml" filepath="$PROJECT_DIR$/.idea/modules/lesson4/lesson4_test.iml" group="lesson4" /> + <module fileurl="file://$PROJECT_DIR$/.idea/modules/lesson5.iml" filepath="$PROJECT_DIR$/.idea/modules/lesson5.iml" group="lesson5" /> + <module fileurl="file://$PROJECT_DIR$/.idea/modules/lesson5/lesson5_main.iml" filepath="$PROJECT_DIR$/.idea/modules/lesson5/lesson5_main.iml" group="lesson5" /> + <module fileurl="file://$PROJECT_DIR$/.idea/modules/lesson5/lesson5_test.iml" filepath="$PROJECT_DIR$/.idea/modules/lesson5/lesson5_test.iml" group="lesson5" /> </modules> </component> </project> \ 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 @@ <ignored path="$PROJECT_DIR$/lesson2/build/" /> <ignored path="$PROJECT_DIR$/lesson3/.gradle/" /> <ignored path="$PROJECT_DIR$/lesson3/build/" /> + <ignored path="$PROJECT_DIR$/lesson4/.gradle/" /> + <ignored path="$PROJECT_DIR$/lesson4/build/" /> + <ignored path="$PROJECT_DIR$/lesson5/.gradle/" /> + <ignored path="$PROJECT_DIR$/lesson5/build/" /> <option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" /> <option name="TRACKING_ENABLED" value="true" /> <option name="SHOW_DIALOG" value="false" /> @@ -39,6 +43,9 @@ <task path="$PROJECT_DIR$/lesson2"> <activation /> </task> + <task path="$PROJECT_DIR$/lesson4"> + <activation /> + </task> <projects_view> <tree_state> <PATH> @@ -51,69 +58,75 @@ <option name="myItemType" value="com.intellij.openapi.externalSystem.view.ProjectNode" /> </PATH_ELEMENT> </PATH> + <PATH> + <PATH_ELEMENT> + <option name="myItemId" value="" /> + <option name="myItemType" value="com.intellij.openapi.externalSystem.view.ExternalProjectsStructure$RootNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="2931408816" /> + <option name="myItemType" value="com.intellij.openapi.externalSystem.view.ProjectNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="2931408816" /> + <option name="myItemType" value="com.intellij.openapi.externalSystem.view.ModuleNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="Tasks" /> + <option name="myItemType" value="com.intellij.openapi.externalSystem.view.TasksNode" /> + </PATH_ELEMENT> + </PATH> + <PATH> + <PATH_ELEMENT> + <option name="myItemId" value="" /> + <option name="myItemType" value="com.intellij.openapi.externalSystem.view.ExternalProjectsStructure$RootNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="2931408816" /> + <option name="myItemType" value="com.intellij.openapi.externalSystem.view.ProjectNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="2931408816" /> + <option name="myItemType" value="com.intellij.openapi.externalSystem.view.ModuleNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="Tasks" /> + <option name="myItemType" value="com.intellij.openapi.externalSystem.view.TasksNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="build" /> + <option name="myItemType" value="com.intellij.openapi.externalSystem.view.TasksNode$1" /> + </PATH_ELEMENT> + </PATH> + <PATH> + <PATH_ELEMENT> + <option name="myItemId" value="" /> + <option name="myItemType" value="com.intellij.openapi.externalSystem.view.ExternalProjectsStructure$RootNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="2931408816" /> + <option name="myItemType" value="com.intellij.openapi.externalSystem.view.ProjectNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="2931408816" /> + <option name="myItemType" value="com.intellij.openapi.externalSystem.view.ModuleNode" /> + </PATH_ELEMENT> + </PATH> </tree_state> </projects_view> </state> </system> </component> <component name="FileEditorManager"> - <leaf SIDE_TABS_SIZE_LIMIT_KEY="300"> - <file leaf-file-name="FileDownloader.java" pinned="false" current-in-tab="false"> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/FileDownloader.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="253"> - <caret line="55" column="38" lean-forward="false" selection-start-line="55" selection-start-column="38" selection-end-line="55" selection-end-column="38" /> - <folding /> - </state> - </provider> - </entry> - </file> - <file leaf-file-name="ConnectionManagerImpl.java" pinned="false" current-in-tab="false"> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/impl/ConnectionManagerImpl.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="184"> - <caret line="23" column="67" lean-forward="false" selection-start-line="23" selection-start-column="67" selection-end-line="23" selection-end-column="67" /> - <folding /> - </state> - </provider> - </entry> - </file> - <file leaf-file-name="ConnectionImpl.java" pinned="false" current-in-tab="false"> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/impl/ConnectionImpl.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="-416"> - <caret line="58" column="26" lean-forward="true" selection-start-line="58" selection-start-column="26" selection-end-line="58" selection-end-column="26" /> - <folding /> - </state> - </provider> - </entry> - </file> - <file leaf-file-name="FileUtil.java" pinned="false" current-in-tab="false"> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/FileUtil.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="299"> - <caret line="25" column="26" lean-forward="false" selection-start-line="25" selection-start-column="26" selection-end-line="25" selection-end-column="26" /> - <folding /> - </state> - </provider> - </entry> - </file> - <file leaf-file-name="FileDownloaderTest.java" pinned="false" current-in-tab="true"> - <entry file="file://$PROJECT_DIR$/lesson3/src/test/java/cn/net/pikachu/download/FileDownloaderTest.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="460"> - <caret line="34" column="41" lean-forward="false" selection-start-line="34" selection-start-column="41" selection-end-line="34" selection-end-column="41" /> - <folding /> - </state> - </provider> - </entry> - </file> - <file leaf-file-name="DownloadThread.java" pinned="false" current-in-tab="false"> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/DownloadThread.java"> + <leaf SIDE_TABS_SIZE_LIMIT_KEY="375"> + <file leaf-file-name="main.kt" pinned="false" current-in-tab="true"> + <entry file="file://$PROJECT_DIR$/src/main/kotlin/main.kt"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="483"> - <caret line="27" column="31" lean-forward="true" selection-start-line="27" selection-start-column="31" selection-end-line="27" selection-end-column="31" /> - <folding /> + <state relative-caret-position="161"> + <caret line="9" column="32" lean-forward="false" selection-start-line="9" selection-start-column="32" selection-end-line="9" selection-end-column="32" /> + <folding> + <element signature="n#!!doc;n#main#0" expanded="false" /> + </folding> </state> </provider> </entry> @@ -123,8 +136,8 @@ <component name="FileTemplateManagerImpl"> <option name="RECENT_TEMPLATES"> <list> - <option value="Kotlin File" /> <option value="Class" /> + <option value="Kotlin File" /> </list> </option> </component> @@ -357,6 +370,116 @@ <conf name="classpath" scriptClasspath="true" /> </extensions> </project> + <project path="$PROJECT_DIR$/lesson4"> + <extensions parent="$PROJECT_DIR$"> + <ext name="ext" type="org.gradle.api.internal.plugins.DefaultExtraPropertiesExtension" /> + <ext name="defaultArtifacts" type="org.gradle.api.internal.plugins.DefaultArtifactPublicationSet" /> + <ext name="reporting" type="org.gradle.api.reporting.ReportingExtension" /> + <ext name="kotlin" type="org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension" /> + <ext name="kapt" type="org.jetbrains.kotlin.gradle.plugin.KaptExtension" /> + <prop name="kotlin_version" /> + <task name="components" type="org.gradle.api.reporting.components.ComponentReport">Displays the components produced by project ':lesson4'. [incubating]&lt;p&gt;&lt;i&gt;Task group: help&lt;i&gt;</task> + <task name="buildDependents">Assembles and tests this project and all projects that depend on it.&lt;p&gt;&lt;i&gt;Task group: build&lt;i&gt;</task> + <task name="projects" type="org.gradle.api.tasks.diagnostics.ProjectReportTask">Displays the sub-projects of project ':lesson4'.&lt;p&gt;&lt;i&gt;Task group: help&lt;i&gt;</task> + <task name="idea">Generates IDEA project files (IML, IPR, IWS)&lt;p&gt;&lt;i&gt;Task group: IDE&lt;i&gt;</task> + <task name="classes">Assembles main classes.&lt;p&gt;&lt;i&gt;Task group: build&lt;i&gt;</task> + <task name="buildEnvironment" type="org.gradle.api.tasks.diagnostics.BuildEnvironmentReportTask">Displays all buildscript dependencies declared in project ':lesson4'.&lt;p&gt;&lt;i&gt;Task group: help&lt;i&gt;</task> + <task name="cleanIdeaModule" type="org.gradle.api.tasks.Delete">&lt;i&gt;Task group: other&lt;i&gt;</task> + <task name="testClasses">Assembles test classes.&lt;p&gt;&lt;i&gt;Task group: build&lt;i&gt;</task> + <task name="javadoc" type="org.gradle.api.tasks.javadoc.Javadoc">Generates Javadoc API documentation for the main source code.&lt;p&gt;&lt;i&gt;Task group: documentation&lt;i&gt;</task> + <task name="jar" type="org.gradle.api.tasks.bundling.Jar">Assembles a jar archive containing the main classes.&lt;p&gt;&lt;i&gt;Task group: build&lt;i&gt;</task> + <task name="model" type="org.gradle.api.reporting.model.ModelReport">Displays the configuration model of project ':lesson4'. [incubating]&lt;p&gt;&lt;i&gt;Task group: help&lt;i&gt;</task> + <task name="copyMainKotlinClasses" type="org.jetbrains.kotlin.gradle.tasks.SyncOutputTask">&lt;i&gt;Task group: other&lt;i&gt;</task> + <task name="ideaModule" type="org.gradle.plugins.ide.idea.GenerateIdeaModule">Generates IDEA module files (IML)&lt;p&gt;&lt;i&gt;Task group: other&lt;i&gt;</task> + <task name="processResources" type="org.gradle.language.jvm.tasks.ProcessResources">Processes main resources.&lt;p&gt;&lt;i&gt;Task group: other&lt;i&gt;</task> + <task name="tasks" type="org.gradle.api.tasks.diagnostics.TaskReportTask">Displays the tasks runnable from project ':lesson4'.&lt;p&gt;&lt;i&gt;Task group: help&lt;i&gt;</task> + <task name="cleanIdea">Cleans IDEA project files (IML, IPR)&lt;p&gt;&lt;i&gt;Task group: IDE&lt;i&gt;</task> + <task name="copyTestKotlinClasses" type="org.jetbrains.kotlin.gradle.tasks.SyncOutputTask">&lt;i&gt;Task group: other&lt;i&gt;</task> + <task name="test" type="org.gradle.api.tasks.testing.Test">Runs the unit tests.&lt;p&gt;&lt;i&gt;Task group: verification&lt;i&gt;</task> + <task name="compileJava" type="org.gradle.api.tasks.compile.JavaCompile">Compiles main Java source.&lt;p&gt;&lt;i&gt;Task group: other&lt;i&gt;</task> + <task name="compileTestKotlin" type="org.jetbrains.kotlin.gradle.tasks.KotlinCompile">Compiles the source set 'test'.kotlin.&lt;p&gt;&lt;i&gt;Task group: other&lt;i&gt;</task> + <task name="dependencyInsight" type="org.gradle.api.tasks.diagnostics.DependencyInsightReportTask">Displays the insight into a specific dependency in project ':lesson4'.&lt;p&gt;&lt;i&gt;Task group: help&lt;i&gt;</task> + <task name="check">Runs all checks.&lt;p&gt;&lt;i&gt;Task group: verification&lt;i&gt;</task> + <task name="assemble">Assembles the outputs of this project.&lt;p&gt;&lt;i&gt;Task group: build&lt;i&gt;</task> + <task name="clean" type="org.gradle.api.tasks.Delete">Deletes the build directory.&lt;p&gt;&lt;i&gt;Task group: build&lt;i&gt;</task> + <task name="compileTestJava" type="org.gradle.api.tasks.compile.JavaCompile">Compiles test Java source.&lt;p&gt;&lt;i&gt;Task group: other&lt;i&gt;</task> + <task name="dependencies" type="org.gradle.api.tasks.diagnostics.DependencyReportTask">Displays all dependencies declared in project ':lesson4'.&lt;p&gt;&lt;i&gt;Task group: help&lt;i&gt;</task> + <task name="processTestResources" type="org.gradle.language.jvm.tasks.ProcessResources">Processes test resources.&lt;p&gt;&lt;i&gt;Task group: other&lt;i&gt;</task> + <task name="help" type="org.gradle.configuration.Help">Displays a help message.&lt;p&gt;&lt;i&gt;Task group: help&lt;i&gt;</task> + <task name="compileKotlin" type="org.jetbrains.kotlin.gradle.tasks.KotlinCompile">Compiles the source set 'main'.kotlin.&lt;p&gt;&lt;i&gt;Task group: other&lt;i&gt;</task> + <task name="build">Assembles and tests this project.&lt;p&gt;&lt;i&gt;Task group: build&lt;i&gt;</task> + <task name="buildNeeded">Assembles and tests this project and all projects it depends on.&lt;p&gt;&lt;i&gt;Task group: build&lt;i&gt;</task> + <task name="properties" type="org.gradle.api.tasks.diagnostics.PropertyReportTask">Displays the properties of project ':lesson4'.&lt;p&gt;&lt;i&gt;Task group: help&lt;i&gt;</task> + <conf name="archives">Configuration for archive artifacts.</conf> + <conf name="compile" visible="false">Dependencies for source set 'main'.</conf> + <conf name="compileClasspath" visible="false">Compile classpath for source set 'main'.</conf> + <conf name="compileOnly" visible="false">Compile dependencies for source set 'main'.</conf> + <conf name="default">Configuration for default artifacts.</conf> + <conf name="kapt" /> + <conf name="kaptTest" /> + <conf name="runtime" visible="false">Runtime dependencies for source set 'main'.</conf> + <conf name="testCompile" visible="false">Dependencies for source set 'test'.</conf> + <conf name="testCompileClasspath" visible="false">Compile classpath for source set 'test'.</conf> + <conf name="testCompileOnly" visible="false">Compile dependencies for source set 'test'.</conf> + <conf name="testRuntime" visible="false">Runtime dependencies for source set 'test'.</conf> + <conf name="classpath" scriptClasspath="true" /> + </extensions> + </project> + <project path="$PROJECT_DIR$/lesson5"> + <extensions parent="$PROJECT_DIR$"> + <ext name="ext" type="org.gradle.api.internal.plugins.DefaultExtraPropertiesExtension" /> + <ext name="defaultArtifacts" type="org.gradle.api.internal.plugins.DefaultArtifactPublicationSet" /> + <ext name="reporting" type="org.gradle.api.reporting.ReportingExtension" /> + <ext name="kotlin" type="org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension" /> + <ext name="kapt" type="org.jetbrains.kotlin.gradle.plugin.KaptExtension" /> + <prop name="kotlin_version" /> + <task name="components" type="org.gradle.api.reporting.components.ComponentReport">Displays the components produced by project ':lesson5'. [incubating]&lt;p&gt;&lt;i&gt;Task group: help&lt;i&gt;</task> + <task name="buildDependents">Assembles and tests this project and all projects that depend on it.&lt;p&gt;&lt;i&gt;Task group: build&lt;i&gt;</task> + <task name="projects" type="org.gradle.api.tasks.diagnostics.ProjectReportTask">Displays the sub-projects of project ':lesson5'.&lt;p&gt;&lt;i&gt;Task group: help&lt;i&gt;</task> + <task name="idea">Generates IDEA project files (IML, IPR, IWS)&lt;p&gt;&lt;i&gt;Task group: IDE&lt;i&gt;</task> + <task name="classes">Assembles main classes.&lt;p&gt;&lt;i&gt;Task group: build&lt;i&gt;</task> + <task name="buildEnvironment" type="org.gradle.api.tasks.diagnostics.BuildEnvironmentReportTask">Displays all buildscript dependencies declared in project ':lesson5'.&lt;p&gt;&lt;i&gt;Task group: help&lt;i&gt;</task> + <task name="cleanIdeaModule" type="org.gradle.api.tasks.Delete">&lt;i&gt;Task group: other&lt;i&gt;</task> + <task name="testClasses">Assembles test classes.&lt;p&gt;&lt;i&gt;Task group: build&lt;i&gt;</task> + <task name="javadoc" type="org.gradle.api.tasks.javadoc.Javadoc">Generates Javadoc API documentation for the main source code.&lt;p&gt;&lt;i&gt;Task group: documentation&lt;i&gt;</task> + <task name="jar" type="org.gradle.api.tasks.bundling.Jar">Assembles a jar archive containing the main classes.&lt;p&gt;&lt;i&gt;Task group: build&lt;i&gt;</task> + <task name="model" type="org.gradle.api.reporting.model.ModelReport">Displays the configuration model of project ':lesson5'. [incubating]&lt;p&gt;&lt;i&gt;Task group: help&lt;i&gt;</task> + <task name="copyMainKotlinClasses" type="org.jetbrains.kotlin.gradle.tasks.SyncOutputTask">&lt;i&gt;Task group: other&lt;i&gt;</task> + <task name="ideaModule" type="org.gradle.plugins.ide.idea.GenerateIdeaModule">Generates IDEA module files (IML)&lt;p&gt;&lt;i&gt;Task group: other&lt;i&gt;</task> + <task name="processResources" type="org.gradle.language.jvm.tasks.ProcessResources">Processes main resources.&lt;p&gt;&lt;i&gt;Task group: other&lt;i&gt;</task> + <task name="tasks" type="org.gradle.api.tasks.diagnostics.TaskReportTask">Displays the tasks runnable from project ':lesson5'.&lt;p&gt;&lt;i&gt;Task group: help&lt;i&gt;</task> + <task name="cleanIdea">Cleans IDEA project files (IML, IPR)&lt;p&gt;&lt;i&gt;Task group: IDE&lt;i&gt;</task> + <task name="copyTestKotlinClasses" type="org.jetbrains.kotlin.gradle.tasks.SyncOutputTask">&lt;i&gt;Task group: other&lt;i&gt;</task> + <task name="test" type="org.gradle.api.tasks.testing.Test">Runs the unit tests.&lt;p&gt;&lt;i&gt;Task group: verification&lt;i&gt;</task> + <task name="compileJava" type="org.gradle.api.tasks.compile.JavaCompile">Compiles main Java source.&lt;p&gt;&lt;i&gt;Task group: other&lt;i&gt;</task> + <task name="compileTestKotlin" type="org.jetbrains.kotlin.gradle.tasks.KotlinCompile">Compiles the source set 'test'.kotlin.&lt;p&gt;&lt;i&gt;Task group: other&lt;i&gt;</task> + <task name="dependencyInsight" type="org.gradle.api.tasks.diagnostics.DependencyInsightReportTask">Displays the insight into a specific dependency in project ':lesson5'.&lt;p&gt;&lt;i&gt;Task group: help&lt;i&gt;</task> + <task name="check">Runs all checks.&lt;p&gt;&lt;i&gt;Task group: verification&lt;i&gt;</task> + <task name="assemble">Assembles the outputs of this project.&lt;p&gt;&lt;i&gt;Task group: build&lt;i&gt;</task> + <task name="clean" type="org.gradle.api.tasks.Delete">Deletes the build directory.&lt;p&gt;&lt;i&gt;Task group: build&lt;i&gt;</task> + <task name="compileTestJava" type="org.gradle.api.tasks.compile.JavaCompile">Compiles test Java source.&lt;p&gt;&lt;i&gt;Task group: other&lt;i&gt;</task> + <task name="dependencies" type="org.gradle.api.tasks.diagnostics.DependencyReportTask">Displays all dependencies declared in project ':lesson5'.&lt;p&gt;&lt;i&gt;Task group: help&lt;i&gt;</task> + <task name="processTestResources" type="org.gradle.language.jvm.tasks.ProcessResources">Processes test resources.&lt;p&gt;&lt;i&gt;Task group: other&lt;i&gt;</task> + <task name="help" type="org.gradle.configuration.Help">Displays a help message.&lt;p&gt;&lt;i&gt;Task group: help&lt;i&gt;</task> + <task name="compileKotlin" type="org.jetbrains.kotlin.gradle.tasks.KotlinCompile">Compiles the source set 'main'.kotlin.&lt;p&gt;&lt;i&gt;Task group: other&lt;i&gt;</task> + <task name="build">Assembles and tests this project.&lt;p&gt;&lt;i&gt;Task group: build&lt;i&gt;</task> + <task name="buildNeeded">Assembles and tests this project and all projects it depends on.&lt;p&gt;&lt;i&gt;Task group: build&lt;i&gt;</task> + <task name="properties" type="org.gradle.api.tasks.diagnostics.PropertyReportTask">Displays the properties of project ':lesson5'.&lt;p&gt;&lt;i&gt;Task group: help&lt;i&gt;</task> + <conf name="archives">Configuration for archive artifacts.</conf> + <conf name="compile" visible="false">Dependencies for source set 'main'.</conf> + <conf name="compileClasspath" visible="false">Compile classpath for source set 'main'.</conf> + <conf name="compileOnly" visible="false">Compile dependencies for source set 'main'.</conf> + <conf name="default">Configuration for default artifacts.</conf> + <conf name="kapt" /> + <conf name="kaptTest" /> + <conf name="runtime" visible="false">Runtime dependencies for source set 'main'.</conf> + <conf name="testCompile" visible="false">Dependencies for source set 'test'.</conf> + <conf name="testCompileClasspath" visible="false">Compile classpath for source set 'test'.</conf> + <conf name="testCompileOnly" visible="false">Compile dependencies for source set 'test'.</conf> + <conf name="testRuntime" visible="false">Runtime dependencies for source set 'test'.</conf> + <conf name="classpath" scriptClasspath="true" /> + </extensions> + </project> </sub-project> </project> </component> @@ -382,6 +505,14 @@ </key> <value> <list> + <ExternalProjectPojo> + <option name="name" value=":lesson4" /> + <option name="path" value="$PROJECT_DIR$/lesson4" /> + </ExternalProjectPojo> + <ExternalProjectPojo> + <option name="name" value=":lesson5" /> + <option name="path" value="$PROJECT_DIR$/lesson5" /> + </ExternalProjectPojo> <ExternalProjectPojo> <option name="name" value="2931408816" /> <option name="path" value="$PROJECT_DIR$" /> @@ -991,95 +1122,385 @@ </list> </value> </entry> - </map> - </option> - <option name="modificationStamps"> - <map> - <entry key="$PROJECT_DIR$" value="8935821309455" /> - <entry key="$PROJECT_DIR$/lesson3/build.gradle" value="2522245911" /> - <entry key="$PROJECT_DIR$/settings.gradle" value="3306979944" /> - <entry key="$PROJECT_DIR$/../../../../src/gradle/study/basic" value="2976922707460" /> - </map> - </option> - <option name="projectBuildClasspath"> - <map> - <entry key="$PROJECT_DIR$"> + <entry key="$PROJECT_DIR$/lesson4"> <value> - <ExternalProjectBuildClasspathPojo> - <option name="modulesBuildClasspath"> - <map> - <entry key="$PROJECT_DIR$"> - <value> - <ExternalModuleBuildClasspathPojo> - <option name="entries"> - <list> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin/1.1.0/446b2c92de7fc40adc0f0e46a6168b0274b8ab90/kotlin-gradle-plugin-1.1.0-sources.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin/1.1.0/19c8cb57a76c3469bff20662ab6dd6b0018da380/kotlin-gradle-plugin-1.1.0.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-io/commons-io/2.4/f2d8698c46d1167ff24b06a840a87d91a02db891/commons-io-2.4-sources.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-io/commons-io/2.4/b1b6ea3b7e4aa4f492509a4952029cd8e48019ad/commons-io-2.4.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-lang/commons-lang/2.6/67313d715fbf0ea4fd0bdb69217fb77f807a8ce5/commons-lang-2.6-sources.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-lang/commons-lang/2.6/ce1edb914c94ebc388f086c6827e8bdeec71ac2/commons-lang-2.6.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.1.0/3303374103edd7cee62bf3539c40aa193d1c4767/kotlin-stdlib-1.1.0-sources.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.1.0/96a07041a11a09cf578892932d7511e1e11e3b6c/kotlin-stdlib-1.1.0.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-android-extensions/1.1.0/55a44cd7418e572dbc92263e019f1c168ea2b94c/kotlin-android-extensions-1.1.0-sources.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-android-extensions/1.1.0/8db6949a924ad553fb7f6f103b66780c4d3e59c5/kotlin-android-extensions-1.1.0.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin-api/1.1.0/38258f24943796a4b3f046e74f9ee40ce7196aff/kotlin-gradle-plugin-api-1.1.0-sources.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin-api/1.1.0/9b524344b9fb22dbe45e5047fa98b22d54301c2d/kotlin-gradle-plugin-api-1.1.0.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-embeddable/1.1.0/dc31610e8195ca75891325591c8b1a2f4d9ac54a/kotlin-compiler-embeddable-1.1.0-sources.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-embeddable/1.1.0/782efe747ea43b08fa3d2c3184e83173934a7acb/kotlin-compiler-embeddable-1.1.0.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-runner/1.1.0/d9c3aec59194fa1a969139dc794da6329935fc00/kotlin-compiler-runner-1.1.0-sources.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-runner/1.1.0/5798574aa3d0895427389d57fbb1996a23e74036/kotlin-compiler-runner-1.1.0.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-annotation-processing/1.1.0/94be1d871c8cf8b118df0958232676605ffb3840/kotlin-annotation-processing-1.1.0-sources.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-annotation-processing/1.1.0/a53b076cf2e66c838189ddd69a0eccdaa05e43a5/kotlin-annotation-processing-1.1.0.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/5991ca87ef1fb5544943d9abc5a9a37583fabe03/annotations-13.0-sources.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar" /> - </list> - </option> - <option name="path" value="$PROJECT_DIR$" /> - </ExternalModuleBuildClasspathPojo> - </value> - </entry> - <entry key="$PROJECT_DIR$/lesson1"> - <value> - <ExternalModuleBuildClasspathPojo> - <option name="entries"> - <list> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin/1.1.0/446b2c92de7fc40adc0f0e46a6168b0274b8ab90/kotlin-gradle-plugin-1.1.0-sources.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin/1.1.0/19c8cb57a76c3469bff20662ab6dd6b0018da380/kotlin-gradle-plugin-1.1.0.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-io/commons-io/2.4/f2d8698c46d1167ff24b06a840a87d91a02db891/commons-io-2.4-sources.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-io/commons-io/2.4/b1b6ea3b7e4aa4f492509a4952029cd8e48019ad/commons-io-2.4.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-lang/commons-lang/2.6/67313d715fbf0ea4fd0bdb69217fb77f807a8ce5/commons-lang-2.6-sources.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-lang/commons-lang/2.6/ce1edb914c94ebc388f086c6827e8bdeec71ac2/commons-lang-2.6.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.1.0/3303374103edd7cee62bf3539c40aa193d1c4767/kotlin-stdlib-1.1.0-sources.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.1.0/96a07041a11a09cf578892932d7511e1e11e3b6c/kotlin-stdlib-1.1.0.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-android-extensions/1.1.0/55a44cd7418e572dbc92263e019f1c168ea2b94c/kotlin-android-extensions-1.1.0-sources.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-android-extensions/1.1.0/8db6949a924ad553fb7f6f103b66780c4d3e59c5/kotlin-android-extensions-1.1.0.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin-api/1.1.0/38258f24943796a4b3f046e74f9ee40ce7196aff/kotlin-gradle-plugin-api-1.1.0-sources.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin-api/1.1.0/9b524344b9fb22dbe45e5047fa98b22d54301c2d/kotlin-gradle-plugin-api-1.1.0.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-embeddable/1.1.0/dc31610e8195ca75891325591c8b1a2f4d9ac54a/kotlin-compiler-embeddable-1.1.0-sources.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-embeddable/1.1.0/782efe747ea43b08fa3d2c3184e83173934a7acb/kotlin-compiler-embeddable-1.1.0.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-runner/1.1.0/d9c3aec59194fa1a969139dc794da6329935fc00/kotlin-compiler-runner-1.1.0-sources.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-runner/1.1.0/5798574aa3d0895427389d57fbb1996a23e74036/kotlin-compiler-runner-1.1.0.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-annotation-processing/1.1.0/94be1d871c8cf8b118df0958232676605ffb3840/kotlin-annotation-processing-1.1.0-sources.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-annotation-processing/1.1.0/a53b076cf2e66c838189ddd69a0eccdaa05e43a5/kotlin-annotation-processing-1.1.0.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/5991ca87ef1fb5544943d9abc5a9a37583fabe03/annotations-13.0-sources.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar" /> - </list> - </option> - <option name="path" value="$PROJECT_DIR$/lesson1" /> - </ExternalModuleBuildClasspathPojo> - </value> - </entry> - <entry key="$PROJECT_DIR$/lesson2"> - <value> - <ExternalModuleBuildClasspathPojo> - <option name="entries"> - <list> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin/1.1.0/446b2c92de7fc40adc0f0e46a6168b0274b8ab90/kotlin-gradle-plugin-1.1.0-sources.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin/1.1.0/19c8cb57a76c3469bff20662ab6dd6b0018da380/kotlin-gradle-plugin-1.1.0.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-io/commons-io/2.4/f2d8698c46d1167ff24b06a840a87d91a02db891/commons-io-2.4-sources.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-io/commons-io/2.4/b1b6ea3b7e4aa4f492509a4952029cd8e48019ad/commons-io-2.4.jar" /> - <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-lang/commons-lang/2.6/67313d715fbf0ea4fd0bdb69217fb77f807a8ce5/commons-lang-2.6-sources.jar" /> + <list> + <ExternalTaskPojo> + <option name="description" value="Displays the components produced by project ':lesson4'. [incubating]" /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="components" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Assembles and tests this project and all projects that depend on it." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="buildDependents" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Displays the sub-projects of project ':lesson4'." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="projects" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Assembles main classes." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="classes" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Displays all buildscript dependencies declared in project ':lesson4'." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="buildEnvironment" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Assembles test classes." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="testClasses" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Generates Javadoc API documentation for the main source code." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="javadoc" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Assembles a jar archive containing the main classes." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="jar" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Displays the configuration model of project ':lesson4'. [incubating]" /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="model" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="copyMainKotlinClasses" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Processes main resources." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="processResources" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Displays the tasks runnable from project ':lesson4'." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="tasks" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="copyTestKotlinClasses" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Runs the unit tests." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="test" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Compiles main Java source." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="compileJava" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Compiles the source set 'test'.kotlin." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="compileTestKotlin" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Displays the insight into a specific dependency in project ':lesson4'." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="dependencyInsight" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Runs all checks." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="check" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Assembles the outputs of this project." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="assemble" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Deletes the build directory." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="clean" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Compiles test Java source." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="compileTestJava" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Displays all dependencies declared in project ':lesson4'." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="dependencies" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Processes test resources." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="processTestResources" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Displays a help message." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="help" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Compiles the source set 'main'.kotlin." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="compileKotlin" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Assembles and tests this project." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="build" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Assembles and tests this project and all projects it depends on." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="buildNeeded" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Displays the properties of project ':lesson4'." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson4" /> + <option name="name" value="properties" /> + </ExternalTaskPojo> + </list> + </value> + </entry> + <entry key="$PROJECT_DIR$/lesson5"> + <value> + <list> + <ExternalTaskPojo> + <option name="description" value="Displays the components produced by project ':lesson5'. [incubating]" /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="components" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Assembles and tests this project and all projects that depend on it." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="buildDependents" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Displays the sub-projects of project ':lesson5'." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="projects" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Assembles main classes." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="classes" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Displays all buildscript dependencies declared in project ':lesson5'." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="buildEnvironment" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Assembles test classes." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="testClasses" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Generates Javadoc API documentation for the main source code." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="javadoc" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Assembles a jar archive containing the main classes." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="jar" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Displays the configuration model of project ':lesson5'. [incubating]" /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="model" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="copyMainKotlinClasses" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Processes main resources." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="processResources" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Displays the tasks runnable from project ':lesson5'." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="tasks" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="copyTestKotlinClasses" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Runs the unit tests." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="test" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Compiles main Java source." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="compileJava" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Compiles the source set 'test'.kotlin." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="compileTestKotlin" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Displays the insight into a specific dependency in project ':lesson5'." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="dependencyInsight" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Runs all checks." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="check" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Assembles the outputs of this project." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="assemble" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Deletes the build directory." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="clean" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Compiles test Java source." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="compileTestJava" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Displays all dependencies declared in project ':lesson5'." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="dependencies" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Processes test resources." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="processTestResources" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Displays a help message." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="help" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Compiles the source set 'main'.kotlin." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="compileKotlin" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Assembles and tests this project." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="build" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Assembles and tests this project and all projects it depends on." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="buildNeeded" /> + </ExternalTaskPojo> + <ExternalTaskPojo> + <option name="description" value="Displays the properties of project ':lesson5'." /> + <option name="linkedExternalProjectPath" value="$PROJECT_DIR$/lesson5" /> + <option name="name" value="properties" /> + </ExternalTaskPojo> + </list> + </value> + </entry> + </map> + </option> + <option name="modificationStamps"> + <map> + <entry key="$PROJECT_DIR$/../../../../src/gradle/study/basic" value="2976922707460" /> + <entry key="$PROJECT_DIR$" value="11929251576666" /> + <entry key="$PROJECT_DIR$/lesson3/build.gradle" value="2522245911" /> + <entry key="$PROJECT_DIR$/lesson4/build.gradle" value="2051916822" /> + <entry key="$PROJECT_DIR$/lesson5/build.gradle" value="775741262" /> + <entry key="$PROJECT_DIR$/settings.gradle" value="4236108516" /> + </map> + </option> + <option name="projectBuildClasspath"> + <map> + <entry key="$PROJECT_DIR$"> + <value> + <ExternalProjectBuildClasspathPojo> + <option name="modulesBuildClasspath"> + <map> + <entry key="$PROJECT_DIR$"> + <value> + <ExternalModuleBuildClasspathPojo> + <option name="entries"> + <list> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin/1.1.0/446b2c92de7fc40adc0f0e46a6168b0274b8ab90/kotlin-gradle-plugin-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin/1.1.0/19c8cb57a76c3469bff20662ab6dd6b0018da380/kotlin-gradle-plugin-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-io/commons-io/2.4/f2d8698c46d1167ff24b06a840a87d91a02db891/commons-io-2.4-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-io/commons-io/2.4/b1b6ea3b7e4aa4f492509a4952029cd8e48019ad/commons-io-2.4.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-lang/commons-lang/2.6/67313d715fbf0ea4fd0bdb69217fb77f807a8ce5/commons-lang-2.6-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-lang/commons-lang/2.6/ce1edb914c94ebc388f086c6827e8bdeec71ac2/commons-lang-2.6.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.1.0/3303374103edd7cee62bf3539c40aa193d1c4767/kotlin-stdlib-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.1.0/96a07041a11a09cf578892932d7511e1e11e3b6c/kotlin-stdlib-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-android-extensions/1.1.0/55a44cd7418e572dbc92263e019f1c168ea2b94c/kotlin-android-extensions-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-android-extensions/1.1.0/8db6949a924ad553fb7f6f103b66780c4d3e59c5/kotlin-android-extensions-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin-api/1.1.0/38258f24943796a4b3f046e74f9ee40ce7196aff/kotlin-gradle-plugin-api-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin-api/1.1.0/9b524344b9fb22dbe45e5047fa98b22d54301c2d/kotlin-gradle-plugin-api-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-embeddable/1.1.0/dc31610e8195ca75891325591c8b1a2f4d9ac54a/kotlin-compiler-embeddable-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-embeddable/1.1.0/782efe747ea43b08fa3d2c3184e83173934a7acb/kotlin-compiler-embeddable-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-runner/1.1.0/d9c3aec59194fa1a969139dc794da6329935fc00/kotlin-compiler-runner-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-runner/1.1.0/5798574aa3d0895427389d57fbb1996a23e74036/kotlin-compiler-runner-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-annotation-processing/1.1.0/94be1d871c8cf8b118df0958232676605ffb3840/kotlin-annotation-processing-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-annotation-processing/1.1.0/a53b076cf2e66c838189ddd69a0eccdaa05e43a5/kotlin-annotation-processing-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/5991ca87ef1fb5544943d9abc5a9a37583fabe03/annotations-13.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar" /> + </list> + </option> + <option name="path" value="$PROJECT_DIR$" /> + </ExternalModuleBuildClasspathPojo> + </value> + </entry> + <entry key="$PROJECT_DIR$/lesson1"> + <value> + <ExternalModuleBuildClasspathPojo> + <option name="entries"> + <list> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin/1.1.0/446b2c92de7fc40adc0f0e46a6168b0274b8ab90/kotlin-gradle-plugin-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin/1.1.0/19c8cb57a76c3469bff20662ab6dd6b0018da380/kotlin-gradle-plugin-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-io/commons-io/2.4/f2d8698c46d1167ff24b06a840a87d91a02db891/commons-io-2.4-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-io/commons-io/2.4/b1b6ea3b7e4aa4f492509a4952029cd8e48019ad/commons-io-2.4.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-lang/commons-lang/2.6/67313d715fbf0ea4fd0bdb69217fb77f807a8ce5/commons-lang-2.6-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-lang/commons-lang/2.6/ce1edb914c94ebc388f086c6827e8bdeec71ac2/commons-lang-2.6.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.1.0/3303374103edd7cee62bf3539c40aa193d1c4767/kotlin-stdlib-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.1.0/96a07041a11a09cf578892932d7511e1e11e3b6c/kotlin-stdlib-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-android-extensions/1.1.0/55a44cd7418e572dbc92263e019f1c168ea2b94c/kotlin-android-extensions-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-android-extensions/1.1.0/8db6949a924ad553fb7f6f103b66780c4d3e59c5/kotlin-android-extensions-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin-api/1.1.0/38258f24943796a4b3f046e74f9ee40ce7196aff/kotlin-gradle-plugin-api-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin-api/1.1.0/9b524344b9fb22dbe45e5047fa98b22d54301c2d/kotlin-gradle-plugin-api-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-embeddable/1.1.0/dc31610e8195ca75891325591c8b1a2f4d9ac54a/kotlin-compiler-embeddable-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-embeddable/1.1.0/782efe747ea43b08fa3d2c3184e83173934a7acb/kotlin-compiler-embeddable-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-runner/1.1.0/d9c3aec59194fa1a969139dc794da6329935fc00/kotlin-compiler-runner-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-runner/1.1.0/5798574aa3d0895427389d57fbb1996a23e74036/kotlin-compiler-runner-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-annotation-processing/1.1.0/94be1d871c8cf8b118df0958232676605ffb3840/kotlin-annotation-processing-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-annotation-processing/1.1.0/a53b076cf2e66c838189ddd69a0eccdaa05e43a5/kotlin-annotation-processing-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/5991ca87ef1fb5544943d9abc5a9a37583fabe03/annotations-13.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar" /> + </list> + </option> + <option name="path" value="$PROJECT_DIR$/lesson1" /> + </ExternalModuleBuildClasspathPojo> + </value> + </entry> + <entry key="$PROJECT_DIR$/lesson2"> + <value> + <ExternalModuleBuildClasspathPojo> + <option name="entries"> + <list> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin/1.1.0/446b2c92de7fc40adc0f0e46a6168b0274b8ab90/kotlin-gradle-plugin-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin/1.1.0/19c8cb57a76c3469bff20662ab6dd6b0018da380/kotlin-gradle-plugin-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-io/commons-io/2.4/f2d8698c46d1167ff24b06a840a87d91a02db891/commons-io-2.4-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-io/commons-io/2.4/b1b6ea3b7e4aa4f492509a4952029cd8e48019ad/commons-io-2.4.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-lang/commons-lang/2.6/67313d715fbf0ea4fd0bdb69217fb77f807a8ce5/commons-lang-2.6-sources.jar" /> <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-lang/commons-lang/2.6/ce1edb914c94ebc388f086c6827e8bdeec71ac2/commons-lang-2.6.jar" /> <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.1.0/3303374103edd7cee62bf3539c40aa193d1c4767/kotlin-stdlib-1.1.0-sources.jar" /> <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.1.0/96a07041a11a09cf578892932d7511e1e11e3b6c/kotlin-stdlib-1.1.0.jar" /> @@ -1132,6 +1553,96 @@ </ExternalModuleBuildClasspathPojo> </value> </entry> + <entry key="$PROJECT_DIR$/lesson4"> + <value> + <ExternalModuleBuildClasspathPojo> + <option name="entries"> + <list> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin/1.1.0/446b2c92de7fc40adc0f0e46a6168b0274b8ab90/kotlin-gradle-plugin-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin/1.1.0/19c8cb57a76c3469bff20662ab6dd6b0018da380/kotlin-gradle-plugin-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-io/commons-io/2.4/f2d8698c46d1167ff24b06a840a87d91a02db891/commons-io-2.4-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-io/commons-io/2.4/b1b6ea3b7e4aa4f492509a4952029cd8e48019ad/commons-io-2.4.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-lang/commons-lang/2.6/67313d715fbf0ea4fd0bdb69217fb77f807a8ce5/commons-lang-2.6-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-lang/commons-lang/2.6/ce1edb914c94ebc388f086c6827e8bdeec71ac2/commons-lang-2.6.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.1.0/3303374103edd7cee62bf3539c40aa193d1c4767/kotlin-stdlib-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.1.0/96a07041a11a09cf578892932d7511e1e11e3b6c/kotlin-stdlib-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-android-extensions/1.1.0/55a44cd7418e572dbc92263e019f1c168ea2b94c/kotlin-android-extensions-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-android-extensions/1.1.0/8db6949a924ad553fb7f6f103b66780c4d3e59c5/kotlin-android-extensions-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin-api/1.1.0/38258f24943796a4b3f046e74f9ee40ce7196aff/kotlin-gradle-plugin-api-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin-api/1.1.0/9b524344b9fb22dbe45e5047fa98b22d54301c2d/kotlin-gradle-plugin-api-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-embeddable/1.1.0/dc31610e8195ca75891325591c8b1a2f4d9ac54a/kotlin-compiler-embeddable-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-embeddable/1.1.0/782efe747ea43b08fa3d2c3184e83173934a7acb/kotlin-compiler-embeddable-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-runner/1.1.0/d9c3aec59194fa1a969139dc794da6329935fc00/kotlin-compiler-runner-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-runner/1.1.0/5798574aa3d0895427389d57fbb1996a23e74036/kotlin-compiler-runner-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-annotation-processing/1.1.0/94be1d871c8cf8b118df0958232676605ffb3840/kotlin-annotation-processing-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-annotation-processing/1.1.0/a53b076cf2e66c838189ddd69a0eccdaa05e43a5/kotlin-annotation-processing-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/5991ca87ef1fb5544943d9abc5a9a37583fabe03/annotations-13.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin/1.1.1/e742de8adf25f631b39f74e2d6fd00cd9cdd609e/kotlin-gradle-plugin-1.1.1-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin/1.1.1/5e3d99580c70b67a07cd70481943362e4b29d8d3/kotlin-gradle-plugin-1.1.1.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.1.1/a287944d92875a1f3c2161e5cddaede7720913d1/kotlin-stdlib-1.1.1-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.1.1/98e484e67f913e934559f7f55f0c94be5593f03c/kotlin-stdlib-1.1.1.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-android-extensions/1.1.1/2c0ad82587d187f78c4063fa7867ed3c4dfa54ca/kotlin-android-extensions-1.1.1-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-android-extensions/1.1.1/56cfcc61bc91638ea52d13ce90b565f50be3d6f5/kotlin-android-extensions-1.1.1.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin-api/1.1.1/e48aafb092d4c3ddd6927f38f9f17f7117e1ef47/kotlin-gradle-plugin-api-1.1.1-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin-api/1.1.1/9083de2c98801f1fe058b6280234265269c1cad0/kotlin-gradle-plugin-api-1.1.1.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-embeddable/1.1.1/b84662e33f8f44d33265e964f1329ce5644af35c/kotlin-compiler-embeddable-1.1.1-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-embeddable/1.1.1/d975091bb224a04b3717505a55875608642cc8d3/kotlin-compiler-embeddable-1.1.1.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-runner/1.1.1/764b45d92a761810b29580aeae2fac3d614f9bf/kotlin-compiler-runner-1.1.1-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-runner/1.1.1/cad5c437ac58f7245673a6c4fd73a656dd259b26/kotlin-compiler-runner-1.1.1.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-annotation-processing/1.1.1/2756d002e8d1d1aa0d5a49e7c895b87514083fab/kotlin-annotation-processing-1.1.1-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-annotation-processing/1.1.1/9f7312cea58b39ce82368261cd227758df78eb32/kotlin-annotation-processing-1.1.1.jar" /> + </list> + </option> + <option name="path" value="$PROJECT_DIR$/lesson4" /> + </ExternalModuleBuildClasspathPojo> + </value> + </entry> + <entry key="$PROJECT_DIR$/lesson5"> + <value> + <ExternalModuleBuildClasspathPojo> + <option name="entries"> + <list> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin/1.1.0/446b2c92de7fc40adc0f0e46a6168b0274b8ab90/kotlin-gradle-plugin-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin/1.1.0/19c8cb57a76c3469bff20662ab6dd6b0018da380/kotlin-gradle-plugin-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-io/commons-io/2.4/f2d8698c46d1167ff24b06a840a87d91a02db891/commons-io-2.4-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-io/commons-io/2.4/b1b6ea3b7e4aa4f492509a4952029cd8e48019ad/commons-io-2.4.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-lang/commons-lang/2.6/67313d715fbf0ea4fd0bdb69217fb77f807a8ce5/commons-lang-2.6-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/commons-lang/commons-lang/2.6/ce1edb914c94ebc388f086c6827e8bdeec71ac2/commons-lang-2.6.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.1.0/3303374103edd7cee62bf3539c40aa193d1c4767/kotlin-stdlib-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.1.0/96a07041a11a09cf578892932d7511e1e11e3b6c/kotlin-stdlib-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-android-extensions/1.1.0/55a44cd7418e572dbc92263e019f1c168ea2b94c/kotlin-android-extensions-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-android-extensions/1.1.0/8db6949a924ad553fb7f6f103b66780c4d3e59c5/kotlin-android-extensions-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin-api/1.1.0/38258f24943796a4b3f046e74f9ee40ce7196aff/kotlin-gradle-plugin-api-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin-api/1.1.0/9b524344b9fb22dbe45e5047fa98b22d54301c2d/kotlin-gradle-plugin-api-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-embeddable/1.1.0/dc31610e8195ca75891325591c8b1a2f4d9ac54a/kotlin-compiler-embeddable-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-embeddable/1.1.0/782efe747ea43b08fa3d2c3184e83173934a7acb/kotlin-compiler-embeddable-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-runner/1.1.0/d9c3aec59194fa1a969139dc794da6329935fc00/kotlin-compiler-runner-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-runner/1.1.0/5798574aa3d0895427389d57fbb1996a23e74036/kotlin-compiler-runner-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-annotation-processing/1.1.0/94be1d871c8cf8b118df0958232676605ffb3840/kotlin-annotation-processing-1.1.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-annotation-processing/1.1.0/a53b076cf2e66c838189ddd69a0eccdaa05e43a5/kotlin-annotation-processing-1.1.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/5991ca87ef1fb5544943d9abc5a9a37583fabe03/annotations-13.0-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin/1.1.1/e742de8adf25f631b39f74e2d6fd00cd9cdd609e/kotlin-gradle-plugin-1.1.1-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin/1.1.1/5e3d99580c70b67a07cd70481943362e4b29d8d3/kotlin-gradle-plugin-1.1.1.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.1.1/a287944d92875a1f3c2161e5cddaede7720913d1/kotlin-stdlib-1.1.1-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.1.1/98e484e67f913e934559f7f55f0c94be5593f03c/kotlin-stdlib-1.1.1.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-android-extensions/1.1.1/2c0ad82587d187f78c4063fa7867ed3c4dfa54ca/kotlin-android-extensions-1.1.1-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-android-extensions/1.1.1/56cfcc61bc91638ea52d13ce90b565f50be3d6f5/kotlin-android-extensions-1.1.1.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin-api/1.1.1/e48aafb092d4c3ddd6927f38f9f17f7117e1ef47/kotlin-gradle-plugin-api-1.1.1-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-gradle-plugin-api/1.1.1/9083de2c98801f1fe058b6280234265269c1cad0/kotlin-gradle-plugin-api-1.1.1.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-embeddable/1.1.1/b84662e33f8f44d33265e964f1329ce5644af35c/kotlin-compiler-embeddable-1.1.1-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-embeddable/1.1.1/d975091bb224a04b3717505a55875608642cc8d3/kotlin-compiler-embeddable-1.1.1.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-runner/1.1.1/764b45d92a761810b29580aeae2fac3d614f9bf/kotlin-compiler-runner-1.1.1-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-runner/1.1.1/cad5c437ac58f7245673a6c4fd73a656dd259b26/kotlin-compiler-runner-1.1.1.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-annotation-processing/1.1.1/2756d002e8d1d1aa0d5a49e7c895b87514083fab/kotlin-annotation-processing-1.1.1-sources.jar" /> + <option value="D:/jar/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-annotation-processing/1.1.1/9f7312cea58b39ce82368261cd227758df78eb32/kotlin-annotation-processing-1.1.1.jar" /> + </list> + </option> + <option name="path" value="$PROJECT_DIR$/lesson5" /> + </ExternalModuleBuildClasspathPojo> + </value> + </entry> </map> </option> <option name="name" value="2931408816" /> @@ -1311,189 +1822,73 @@ <option value="$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/impl/ConnectionImpl.java" /> <option value="$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/FileUtil.java" /> <option value="$PROJECT_DIR$/lesson3/src/test/java/cn/net/pikachu/download/FileDownloaderTest.java" /> + <option value="$PROJECT_DIR$/lesson4/src/test/java/com/coderising/jvm/loader/ClassFileloaderTest.java" /> + <option value="$PROJECT_DIR$/lesson4/src/main/java/com/coderising/jvm/loader/ClassFileLoader.java" /> + <option value="$PROJECT_DIR$/lesson4/src/main/java/com/coderising/download/FileDownloaderTest.java" /> + <option value="$PROJECT_DIR$/lesson4/src/main/java/com/coding/basic/linklist/LRUPageFrame.java" /> + <option value="$PROJECT_DIR$/lesson5/src/main/java/java/lang/String.java" /> + <option value="$PROJECT_DIR$/lesson5/src/main/java/com/coderising/jvm/loader/ClassFileLoader.java" /> + <option value="$PROJECT_DIR$/lesson5/src/main/java/com/coderising/jvm/test/ClassFileloaderTest.java" /> + <option value="$PROJECT_DIR$/lesson5/src/test/java/com/coderising/jvm/loader/ClassFileLoader.java" /> + <option value="$PROJECT_DIR$/lesson5/build.gradle" /> + <option value="$PROJECT_DIR$/lesson5/src/main/java/com/coding/basic/stack/Stack.java" /> + <option value="$PROJECT_DIR$/lesson5/src/test/java/com/coding/basic/stack/StackUtilTest.java" /> + <option value="$PROJECT_DIR$/lesson5/src/main/java/com/coding/basic/stack/StackUtil.java" /> + <option value="$PROJECT_DIR$/lesson5/src/main/java/com/coderising/jvm/loader/ByteCodeIterator.java" /> + <option value="$PROJECT_DIR$/lesson5/build/classes/main/com/coderising/jvm/test/EmployeeV1.class" /> + <option value="$PROJECT_DIR$/lesson5/src/main/java/com/coderising/jvm/loader/ClassFileParser.java" /> + <option value="$PROJECT_DIR$/lesson5/src/test/java/com/coderising/jvm/loader/test/ClassFileloaderTest.java" /> + <option value="$PROJECT_DIR$/src/main/kotlin/main.kt" /> </list> </option> - </component> - <component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" /> - <component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER" /> - <component name="JsGulpfileManager"> - <detection-done>true</detection-done> - <sorting>DEFINITION_ORDER</sorting> - </component> - <component name="ProjectFrameBounds"> - <option name="x" value="-9" /> - <option name="y" value="-9" /> - <option name="width" value="1938" /> - <option name="height" value="1048" /> - </component> - <component name="ProjectInspectionProfilesVisibleTreeState"> - <entry key="Project Default"> - <profile-state> - <expanded-state> - <State> - <id /> - </State> - <State> - <id>Android &gt; Lint &gt; Internationalization</id> - </State> - <State> - <id>Internationalization issues</id> - </State> - </expanded-state> - </profile-state> - </entry> - </component> - <component name="ProjectView"> - <navigator currentView="ProjectPane" proportions="" version="1"> - <flattenPackages /> - <showMembers /> - <showModules /> - <showLibraryContents /> - <hideEmptyPackages /> - <abbreviatePackageNames /> - <autoscrollToSource /> - <autoscrollFromSource /> - <sortByType /> - <manualOrder /> - <foldersAlwaysOnTop value="true" /> - </navigator> - <panes> - <pane id="Scratches" /> - <pane id="Scope" /> - <pane id="ProjectPane"> - <subPane> - <PATH> - <PATH_ELEMENT> - <option name="myItemId" value="2931408816" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="2931408816" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - </PATH> - <PATH> - <PATH_ELEMENT> - <option name="myItemId" value="2931408816" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="2931408816" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="lesson3" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - </PATH> - <PATH> - <PATH_ELEMENT> - <option name="myItemId" value="2931408816" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="2931408816" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="lesson3" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="src" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="test" /> - <option name="myItemType" value="org.jetbrains.plugins.gradle.projectView.GradleTreeStructureProvider$GradleSourceSetDirectoryNode" /> - </PATH_ELEMENT> - </PATH> - <PATH> - <PATH_ELEMENT> - <option name="myItemId" value="2931408816" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="2931408816" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="lesson3" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="src" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="test" /> - <option name="myItemType" value="org.jetbrains.plugins.gradle.projectView.GradleTreeStructureProvider$GradleSourceSetDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="java" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="pikachu" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="download" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - </PATH> - <PATH> - <PATH_ELEMENT> - <option name="myItemId" value="2931408816" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="2931408816" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="lesson3" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="src" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="test" /> - <option name="myItemType" value="org.jetbrains.plugins.gradle.projectView.GradleTreeStructureProvider$GradleSourceSetDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="java" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="pikachu" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - </PATH> - <PATH> - <PATH_ELEMENT> - <option name="myItemId" value="2931408816" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="2931408816" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="lesson3" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="src" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="main" /> - <option name="myItemType" value="org.jetbrains.plugins.gradle.projectView.GradleTreeStructureProvider$GradleSourceSetDirectoryNode" /> - </PATH_ELEMENT> - </PATH> + </component> + <component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" /> + <component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER" /> + <component name="JsGulpfileManager"> + <detection-done>true</detection-done> + <sorting>DEFINITION_ORDER</sorting> + </component> + <component name="ProjectFrameBounds"> + <option name="x" value="-9" /> + <option name="y" value="-9" /> + <option name="width" value="1938" /> + <option name="height" value="1048" /> + </component> + <component name="ProjectInspectionProfilesVisibleTreeState"> + <entry key="Project Default"> + <profile-state> + <expanded-state> + <State> + <id /> + </State> + <State> + <id>Android &gt; Lint &gt; Internationalization</id> + </State> + <State> + <id>Internationalization issues</id> + </State> + </expanded-state> + </profile-state> + </entry> + </component> + <component name="ProjectView"> + <navigator currentView="ProjectPane" proportions="" version="1"> + <flattenPackages /> + <showMembers /> + <showModules /> + <showLibraryContents /> + <hideEmptyPackages /> + <abbreviatePackageNames /> + <autoscrollToSource /> + <autoscrollFromSource /> + <sortByType /> + <manualOrder /> + <foldersAlwaysOnTop value="true" /> + </navigator> + <panes> + <pane id="PackagesPane" /> + <pane id="ProjectPane"> + <subPane> <PATH> <PATH_ELEMENT> <option name="myItemId" value="2931408816" /> @@ -1503,30 +1898,6 @@ <option name="myItemId" value="2931408816" /> <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="lesson3" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="src" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="main" /> - <option name="myItemType" value="org.jetbrains.plugins.gradle.projectView.GradleTreeStructureProvider$GradleSourceSetDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="java" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="pikachu" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="download" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> </PATH> <PATH> <PATH_ELEMENT> @@ -1537,34 +1908,10 @@ <option name="myItemId" value="2931408816" /> <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="lesson3" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> <PATH_ELEMENT> <option name="myItemId" value="src" /> <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="main" /> - <option name="myItemType" value="org.jetbrains.plugins.gradle.projectView.GradleTreeStructureProvider$GradleSourceSetDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="java" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="pikachu" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="download" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="impl" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> </PATH> <PATH> <PATH_ELEMENT> @@ -1575,10 +1922,6 @@ <option name="myItemId" value="2931408816" /> <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="lesson3" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> <PATH_ELEMENT> <option name="myItemId" value="src" /> <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> @@ -1587,26 +1930,19 @@ <option name="myItemId" value="main" /> <option name="myItemType" value="org.jetbrains.plugins.gradle.projectView.GradleTreeStructureProvider$GradleSourceSetDirectoryNode" /> </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="java" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> - <PATH_ELEMENT> - <option name="myItemId" value="pikachu" /> - <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> - </PATH_ELEMENT> </PATH> </subPane> </pane> - <pane id="PackagesPane" /> + <pane id="Scratches" /> + <pane id="Scope" /> </panes> </component> <component name="PropertiesComponent"> - <property name="settings.editor.selected.configurable" value="copyright" /> + <property name="settings.editor.selected.configurable" value="preferences.externalTools" /> <property name="WebServerToolWindowFactoryState" value="false" /> <property name="aspect.path.notification.shown" value="true" /> <property name="js.eslint.eslintPackage" value="" /> - <property name="last_opened_file_path" value="$PROJECT_DIR$" /> + <property name="last_opened_file_path" value="$PROJECT_DIR$/../../../../../kotlin/study/mypetstore" /> <property name="node.js.path.for.package.jscs" value="project" /> <property name="nodejs_interpreter_path" value="E:/dev-tools/nvm/v7.2.0/node" /> <property name="node.js.selected.package.jscs" value="" /> @@ -1631,44 +1967,24 @@ </list> </option> </component> - <component name="RunManager" selected="JUnit.FileDownloaderTest.testDownload"> - <configuration default="false" name="Main (1)" type="Application" factoryName="Application" temporary="true" nameIsGenerated="true"> - <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea"> - <pattern> - <option name="PATTERN" value="cn.net.pikachu.download.impl.test.*" /> - <option name="ENABLED" value="true" /> - </pattern> - </extension> - <option name="MAIN_CLASS_NAME" value="cn.net.pikachu.download.impl.test.Main" /> - <option name="VM_PARAMETERS" /> - <option name="PROGRAM_PARAMETERS" /> - <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" /> - <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> - <option name="ALTERNATIVE_JRE_PATH" /> - <option name="ENABLE_SWING_INSPECTOR" value="false" /> - <option name="ENV_VARIABLES" /> - <option name="PASS_PARENT_ENVS" value="true" /> - <module name="lesson3_main" /> - <envs /> - <method /> - </configuration> - <configuration default="false" name="FileDownloaderTest.testDownload" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true"> + <component name="RunManager" selected="Kotlin.MainKt"> + <configuration default="false" name="ClassFileloaderTest" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true"> <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea"> <pattern> - <option name="PATTERN" value="cn.net.pikachu.download.*" /> + <option name="PATTERN" value="com.coderising.jvm.loader.test.*" /> <option name="ENABLED" value="true" /> </pattern> </extension> - <module name="lesson3_test" /> + <module name="lesson5_test" /> <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> <option name="ALTERNATIVE_JRE_PATH" /> - <option name="PACKAGE_NAME" value="cn.net.pikachu.download" /> - <option name="MAIN_CLASS_NAME" value="cn.net.pikachu.download.FileDownloaderTest" /> - <option name="METHOD_NAME" value="testDownload" /> - <option name="TEST_OBJECT" value="method" /> + <option name="PACKAGE_NAME" value="com.coderising.jvm.loader.test" /> + <option name="MAIN_CLASS_NAME" value="com.coderising.jvm.loader.test.ClassFileloaderTest" /> + <option name="METHOD_NAME" /> + <option name="TEST_OBJECT" value="class" /> <option name="VM_PARAMETERS" value="-ea" /> <option name="PARAMETERS" /> - <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/lesson3" /> + <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/lesson5" /> <option name="ENV_VARIABLES" /> <option name="PASS_PARENT_ENVS" value="true" /> <option name="TEST_SEARCH_SCOPE"> @@ -1678,23 +1994,23 @@ <patterns /> <method /> </configuration> - <configuration default="false" name="FileDownloaderTest" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true"> + <configuration default="false" name="ClassFileloaderTest.testClassPath" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true"> <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea"> <pattern> - <option name="PATTERN" value="cn.net.pikachu.download.*" /> + <option name="PATTERN" value="com.coderising.jvm.loader.test.*" /> <option name="ENABLED" value="true" /> </pattern> </extension> - <module name="lesson3_test" /> + <module name="lesson5_test" /> <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> <option name="ALTERNATIVE_JRE_PATH" /> - <option name="PACKAGE_NAME" value="cn.net.pikachu.download" /> - <option name="MAIN_CLASS_NAME" value="cn.net.pikachu.download.FileDownloaderTest" /> - <option name="METHOD_NAME" /> - <option name="TEST_OBJECT" value="class" /> + <option name="PACKAGE_NAME" value="com.coderising.jvm.loader.test" /> + <option name="MAIN_CLASS_NAME" value="com.coderising.jvm.loader.test.ClassFileloaderTest" /> + <option name="METHOD_NAME" value="testClassPath" /> + <option name="TEST_OBJECT" value="method" /> <option name="VM_PARAMETERS" value="-ea" /> <option name="PARAMETERS" /> - <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/lesson3" /> + <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/lesson5" /> <option name="ENV_VARIABLES" /> <option name="PASS_PARENT_ENVS" value="true" /> <option name="TEST_SEARCH_SCOPE"> @@ -1704,14 +2020,14 @@ <patterns /> <method /> </configuration> - <configuration default="false" name="DownloadFileWithThreadPool" type="Application" factoryName="Application" temporary="true" nameIsGenerated="true"> + <configuration default="false" name="ClassFileParser" type="Application" factoryName="Application" temporary="true" nameIsGenerated="true"> <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea"> <pattern> - <option name="PATTERN" value="cn.net.pikachu.download.impl.test.*" /> + <option name="PATTERN" value="com.coderising.jvm.loader.*" /> <option name="ENABLED" value="true" /> </pattern> </extension> - <option name="MAIN_CLASS_NAME" value="cn.net.pikachu.download.impl.test.DownloadFileWithThreadPool" /> + <option name="MAIN_CLASS_NAME" value="com.coderising.jvm.loader.ClassFileParser" /> <option name="VM_PARAMETERS" /> <option name="PROGRAM_PARAMETERS" /> <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" /> @@ -1720,10 +2036,28 @@ <option name="ENABLE_SWING_INSPECTOR" value="false" /> <option name="ENV_VARIABLES" /> <option name="PASS_PARENT_ENVS" value="true" /> - <module name="lesson3_main" /> + <module name="lesson5_main" /> <envs /> <method /> </configuration> + <configuration default="false" name="2931408816 [clean]" type="GradleRunConfiguration" factoryName="Gradle" temporary="true"> + <ExternalSystemSettings> + <option name="executionName" /> + <option name="externalProjectPath" value="$PROJECT_DIR$" /> + <option name="externalSystemIdString" value="GRADLE" /> + <option name="scriptParameters" /> + <option name="taskDescriptions"> + <list /> + </option> + <option name="taskNames"> + <list> + <option value="clean" /> + </list> + </option> + <option name="vmOptions" /> + </ExternalSystemSettings> + <method /> + </configuration> <configuration default="false" name="MainKt" type="JetRunConfigurationType" factoryName="Kotlin" temporary="true" nameIsGenerated="true"> <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" /> <option name="MAIN_CLASS_NAME" value="MainKt" /> @@ -1733,7 +2067,7 @@ <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> <option name="ALTERNATIVE_JRE_PATH" /> <option name="PASS_PARENT_ENVS" value="true" /> - <module name="lesson3_main" /> + <module name="2931408816_main" /> <envs /> <method /> </configuration> @@ -2150,19 +2484,19 @@ <method /> </configuration> <list size="5"> - <item index="0" class="java.lang.String" itemvalue="Application.Main (1)" /> - <item index="1" class="java.lang.String" itemvalue="JUnit.FileDownloaderTest.testDownload" /> - <item index="2" class="java.lang.String" itemvalue="JUnit.FileDownloaderTest" /> - <item index="3" class="java.lang.String" itemvalue="Application.DownloadFileWithThreadPool" /> + <item index="0" class="java.lang.String" itemvalue="JUnit.ClassFileloaderTest" /> + <item index="1" class="java.lang.String" itemvalue="JUnit.ClassFileloaderTest.testClassPath" /> + <item index="2" class="java.lang.String" itemvalue="Application.ClassFileParser" /> + <item index="3" class="java.lang.String" itemvalue="Gradle.2931408816 [clean]" /> <item index="4" class="java.lang.String" itemvalue="Kotlin.MainKt" /> </list> <recent_temporary> <list size="5"> - <item index="0" class="java.lang.String" itemvalue="JUnit.FileDownloaderTest.testDownload" /> - <item index="1" class="java.lang.String" itemvalue="Kotlin.MainKt" /> - <item index="2" class="java.lang.String" itemvalue="Application.DownloadFileWithThreadPool" /> - <item index="3" class="java.lang.String" itemvalue="JUnit.FileDownloaderTest" /> - <item index="4" class="java.lang.String" itemvalue="Application.Main (1)" /> + <item index="0" class="java.lang.String" itemvalue="Kotlin.MainKt" /> + <item index="1" class="java.lang.String" itemvalue="JUnit.ClassFileloaderTest" /> + <item index="2" class="java.lang.String" itemvalue="Application.ClassFileParser" /> + <item index="3" class="java.lang.String" itemvalue="Gradle.2931408816 [clean]" /> + <item index="4" class="java.lang.String" itemvalue="JUnit.ClassFileloaderTest.testClassPath" /> </list> </recent_temporary> </component> @@ -2185,43 +2519,52 @@ <workItem from="1489368000173" duration="1580000" /> <workItem from="1489391209444" duration="8133000" /> <workItem from="1489460871957" duration="1255000" /> + <workItem from="1491007286971" duration="4927000" /> + <workItem from="1491572097285" duration="1755000" /> + <workItem from="1491575467049" duration="2654000" /> + <workItem from="1491637655203" duration="5776000" /> + <workItem from="1491650536561" duration="1535000" /> + <workItem from="1491701452638" duration="8089000" /> + <workItem from="1491719529088" duration="2220000" /> + <workItem from="1491743704287" duration="602000" /> + <workItem from="1491764494419" duration="380000" /> </task> <servers /> </component> <component name="TestHistory"> - <history-entry file="FileDownloaderTest_testDownload - 2017.03.14 at 11h 20m 36s.xml"> - <configuration name="FileDownloaderTest.testDownload" configurationId="JUnit" /> + <history-entry file="ClassFileloaderTest - 2017.04.09 at 10h 31m 27s.xml"> + <configuration name="ClassFileloaderTest" configurationId="JUnit" /> </history-entry> - <history-entry file="FileDownloaderTest_testDownload - 2017.03.14 at 11h 22m 35s.xml"> - <configuration name="FileDownloaderTest.testDownload" configurationId="JUnit" /> + <history-entry file="ClassFileloaderTest - 2017.04.09 at 10h 32m 16s.xml"> + <configuration name="ClassFileloaderTest" configurationId="JUnit" /> </history-entry> - <history-entry file="FileDownloaderTest_testDownload - 2017.03.14 at 11h 22m 53s.xml"> - <configuration name="FileDownloaderTest.testDownload" configurationId="JUnit" /> + <history-entry file="ClassFileloaderTest - 2017.04.09 at 10h 38m 01s.xml"> + <configuration name="ClassFileloaderTest" configurationId="JUnit" /> </history-entry> - <history-entry file="FileDownloaderTest_testDownload - 2017.03.14 at 11h 24m 41s.xml"> - <configuration name="FileDownloaderTest.testDownload" configurationId="JUnit" /> + <history-entry file="ClassFileloaderTest - 2017.04.09 at 10h 39m 59s.xml"> + <configuration name="ClassFileloaderTest" configurationId="JUnit" /> </history-entry> - <history-entry file="FileDownloaderTest_testDownload - 2017.03.14 at 11h 25m 51s.xml"> - <configuration name="FileDownloaderTest.testDownload" configurationId="JUnit" /> + <history-entry file="ClassFileloaderTest - 2017.04.09 at 10h 40m 32s.xml"> + <configuration name="ClassFileloaderTest" configurationId="JUnit" /> </history-entry> - <history-entry file="FileDownloaderTest_testDownload - 2017.03.14 at 11h 26m 35s.xml"> - <configuration name="FileDownloaderTest.testDownload" configurationId="JUnit" /> + <history-entry file="ClassFileloaderTest - 2017.04.09 at 11h 39m 29s.xml"> + <configuration name="ClassFileloaderTest" configurationId="JUnit" /> </history-entry> - <history-entry file="FileDownloaderTest_testDownload - 2017.03.14 at 11h 27m 48s.xml"> - <configuration name="FileDownloaderTest.testDownload" configurationId="JUnit" /> + <history-entry file="ClassFileloaderTest_testClassPath - 2017.04.09 at 10h 31m 22s.xml"> + <configuration name="ClassFileloaderTest.testClassPath" configurationId="JUnit" /> </history-entry> - <history-entry file="FileDownloaderTest_testDownload - 2017.03.14 at 11h 27m 54s.xml"> - <configuration name="FileDownloaderTest.testDownload" configurationId="JUnit" /> + <history-entry file="ClassFileloaderTest_testClassPath - 2017.04.09 at 10h 40m 38s.xml"> + <configuration name="ClassFileloaderTest.testClassPath" configurationId="JUnit" /> </history-entry> - <history-entry file="FileDownloaderTest_testDownload - 2017.03.14 at 11h 28m 57s.xml"> - <configuration name="FileDownloaderTest.testDownload" configurationId="JUnit" /> + <history-entry file="ClassFileloaderTest_testMagicNumber - 2017.04.09 at 10h 25m 09s.xml"> + <configuration name="ClassFileloaderTest.testMagicNumber" configurationId="JUnit" /> </history-entry> - <history-entry file="FileDownloaderTest_testDownload - 2017.03.14 at 11h 29m 05s.xml"> - <configuration name="FileDownloaderTest.testDownload" configurationId="JUnit" /> + <history-entry file="ClassFileloaderTest_testMagicNumber - 2017.04.09 at 10h 30m 11s.xml"> + <configuration name="ClassFileloaderTest.testMagicNumber" configurationId="JUnit" /> </history-entry> </component> <component name="TimeTrackingManager"> - <option name="totallyTimeSpent" value="32115000" /> + <option name="totallyTimeSpent" value="60053000" /> </component> <component name="TodoView"> <todo-panel id="selected-file"> @@ -2234,32 +2577,31 @@ </component> <component name="ToolWindowManager"> <frame x="-9" y="-9" width="1938" height="1048" extended-state="6" /> - <editor active="true" /> <layout> <window_info id="Palette" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32993197" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" /> <window_info id="Nl-Palette" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" /> - <window_info id="Messages" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32879817" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> + <window_info id="Messages" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32842582" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> <window_info id="Palette&#9;" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> <window_info id="Image Layers" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" /> <window_info id="Capture Analysis" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> - <window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" /> + <window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3295583" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" /> <window_info id="Maven Projects" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> - <window_info id="Run" active="true" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.32879817" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" /> + <window_info id="Run" active="true" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.3204983" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" /> <window_info id="Properties" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> <window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32993197" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> <window_info id="Capture Tool" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" /> <window_info id="Designer" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" /> - <window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.27736053" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" /> + <window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.32027897" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" /> <window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> - <window_info id="Gradle" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3299356" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> + <window_info id="Gradle" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32886267" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> <window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" /> <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" /> <window_info id="UI Designer" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" /> <window_info id="Theme Preview" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> <window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" /> - <window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.39909297" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> + <window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.398641" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> <window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" /> <window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" /> <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" /> @@ -2289,10 +2631,32 @@ <properties /> <option name="timeStamp" value="3" /> </line-breakpoint> + <line-breakpoint enabled="true" type="java-line"> + <url>file://$PROJECT_DIR$/lesson5/src/main/java/com/coding/basic/stack/StackUtil.java</url> + <line>131</line> + <properties /> + <option name="timeStamp" value="7" /> + </line-breakpoint> + <line-breakpoint enabled="true" type="java-line"> + <url>file://$PROJECT_DIR$/lesson5/build/classes/main/com/coderising/jvm/clz/AccessFlag.class</url> + <line>1</line> + <properties /> + <option name="timeStamp" value="11" /> + </line-breakpoint> + <line-breakpoint enabled="true" type="java-line"> + <url>file://$PROJECT_DIR$/lesson5/src/main/java/com/coderising/jvm/loader/ClassFileParser.java</url> + <line>49</line> + <properties /> + <option name="timeStamp" value="12" /> + </line-breakpoint> </breakpoints> - <option name="time" value="4" /> + <option name="time" value="13" /> </breakpoint-manager> - <watches-manager /> + <watches-manager> + <configuration name="Application"> + <watch expression="classFile" /> + </configuration> + </watches-manager> </component> <component name="antWorkspaceConfiguration"> <option name="IS_AUTOSCROLL_TO_SOURCE" value="false" /> @@ -2301,393 +2665,354 @@ <component name="editorHistoryManager"> <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/FileDownloader.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="1449"> - <caret line="63" column="35" lean-forward="false" selection-start-line="63" selection-start-column="35" selection-end-line="63" selection-end-column="35" /> - <folding /> + <state relative-caret-position="1012"> + <caret line="55" column="38" lean-forward="false" selection-start-line="55" selection-start-column="38" selection-end-line="55" selection-end-column="38" /> </state> </provider> </entry> <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/DownloadThread.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="644"> - <caret line="33" column="21" lean-forward="false" selection-start-line="33" selection-start-column="21" selection-end-line="33" selection-end-column="21" /> - <folding /> + <state relative-caret-position="483"> + <caret line="27" column="31" lean-forward="false" selection-start-line="27" selection-start-column="31" selection-end-line="27" selection-end-column="31" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/impl/ConnectionManagerImpl.java"> + <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/impl/ConnectionImpl.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="322"> - <caret line="14" column="20" lean-forward="true" selection-start-line="14" selection-start-column="20" selection-end-line="14" selection-end-column="20" /> - <folding /> + <state relative-caret-position="1127"> + <caret line="58" column="26" lean-forward="false" selection-start-line="58" selection-start-column="26" selection-end-line="58" selection-end-column="26" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/basic/LinkedList.java"> + <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/FileUtil.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="4370"> - <caret line="190" column="5" lean-forward="false" selection-start-line="190" selection-start-column="5" selection-end-line="190" selection-end-column="5" /> - <folding> - <element signature="imports" expanded="true" /> - <element signature="class#Itr#0;class#LinkedList#0" expanded="false" /> - <element signature="method#next#0;class#Itr#0;class#LinkedList#0" expanded="false" /> - <element signature="method#add#0;class#LinkedList#0" expanded="false" /> - <element signature="method#add#1;class#LinkedList#0" expanded="false" /> - <element signature="method#addFirst#0;class#LinkedList#0" expanded="false" /> - <element signature="method#removeFirst#0;class#LinkedList#0" expanded="false" /> - <element signature="method#removeLast#0;class#LinkedList#0" expanded="false" /> - <element signature="method#toString#0;class#LinkedList#0" expanded="false" /> - </folding> + <state relative-caret-position="437"> + <caret line="25" column="26" lean-forward="false" selection-start-line="25" selection-start-column="26" selection-end-line="25" selection-end-column="26" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/settings.gradle"> + <entry file="file://$PROJECT_DIR$/lesson3/src/test/java/cn/net/pikachu/download/FileDownloaderTest.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="391"> - <caret line="17" column="31" lean-forward="false" selection-start-line="17" selection-start-column="31" selection-end-line="17" selection-end-column="31" /> - <folding /> + <state relative-caret-position="460"> + <caret line="34" column="41" lean-forward="false" selection-start-line="34" selection-start-column="41" selection-end-line="34" selection-end-column="41" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/build.gradle"> + <entry file="file://$PROJECT_DIR$/lesson4/build.gradle"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="391"> - <caret line="17" column="25" lean-forward="false" selection-start-line="17" selection-start-column="25" selection-end-line="17" selection-end-column="25" /> - <folding /> + <state relative-caret-position="414"> + <caret line="18" column="0" lean-forward="false" selection-start-line="18" selection-start-column="0" selection-end-line="18" selection-end-column="0" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/basic/LinkedList.java"> + <entry file="file://$PROJECT_DIR$/lesson4/src/main/java/com/coderising/jvm/test/EmployeeV1.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="0"> - <caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" /> - <folding> - <element signature="imports" expanded="true" /> - <element signature="class#Itr#0;class#LinkedList#0" expanded="false" /> - <element signature="method#next#0;class#Itr#0;class#LinkedList#0" expanded="false" /> - <element signature="method#add#0;class#LinkedList#0" expanded="false" /> - <element signature="method#add#1;class#LinkedList#0" expanded="false" /> - <element signature="method#addFirst#0;class#LinkedList#0" expanded="false" /> - <element signature="method#removeFirst#0;class#LinkedList#0" expanded="false" /> - <element signature="method#removeLast#0;class#LinkedList#0" expanded="false" /> - <element signature="method#toString#0;class#LinkedList#0" expanded="false" /> - </folding> + <state relative-caret-position="46"> + <caret line="2" column="13" lean-forward="false" selection-start-line="2" selection-start-column="13" selection-end-line="2" selection-end-column="13" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson2/build.gradle"> + <entry file="file://$PROJECT_DIR$/lesson4/src/main/java/com/coderising/jvm/loader/ClassFileLoader.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="621"> - <caret line="27" column="80" lean-forward="false" selection-start-line="27" selection-start-column="80" selection-end-line="27" selection-end-column="80" /> + <state relative-caret-position="176"> + <caret line="20" column="18" lean-forward="false" selection-start-line="20" selection-start-column="18" selection-end-line="20" selection-end-column="18" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/build.gradle"> + <entry file="file://$PROJECT_DIR$/lesson4/src/test/java/com/coderising/jvm/loader/ClassFileloaderTest.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="391"> - <caret line="17" column="25" lean-forward="false" selection-start-line="17" selection-start-column="25" selection-end-line="17" selection-end-column="25" /> - <folding /> + <state relative-caret-position="345"> + <caret line="26" column="45" lean-forward="false" selection-start-line="26" selection-start-column="45" selection-end-line="26" selection-end-column="45" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson2/src/test/java/cn/net/pikachu/array/StrutsTest.java"> + <entry file="file://$PROJECT_DIR$/lesson4/src/main/java/com/coding/basic/linklist/LinkedList.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="115"> - <caret line="11" column="0" lean-forward="false" selection-start-line="11" selection-start-column="0" selection-end-line="11" selection-end-column="0" /> + <state relative-caret-position="92"> + <caret line="5" column="13" lean-forward="false" selection-start-line="5" selection-start-column="13" selection-end-line="5" selection-end-column="13" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson2/src/main/java/cn/net/pikachu/array/ArrayUtil.java"> + <entry file="file://$PROJECT_DIR$/lesson4/src/main/java/com/coderising/download/FileDownloaderTest.java" /> + <entry file="file://$PROJECT_DIR$/lesson4/src/main/java/com/coderising/litestruts/StrutsTest.java" /> + <entry file="file://$PROJECT_DIR$/lesson4/src/test/java/com/coding/basic/linklist/LRUPageFrameTest.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="368"> - <caret line="18" column="42" lean-forward="true" selection-start-line="18" selection-start-column="42" selection-end-line="18" selection-end-column="42" /> + <state relative-caret-position="437"> + <caret line="19" column="39" lean-forward="false" selection-start-line="19" selection-start-column="39" selection-end-line="19" selection-end-column="39" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson2/src/main/java/cn/net/pikachu/litestruts/Struts.java"> + <entry file="file://$PROJECT_DIR$/lesson4/src/main/java/com/coding/basic/linklist/LRUPageFrame.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="460"> - <caret line="28" column="8" lean-forward="true" selection-start-line="28" selection-start-column="8" selection-end-line="28" selection-end-column="8" /> + <state relative-caret-position="459"> + <caret line="88" column="29" lean-forward="false" selection-start-line="88" selection-start-column="29" selection-end-line="88" selection-end-column="29" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson2/build.gradle"> + <entry file="file://$PROJECT_DIR$/lesson5/src/main/java/com/coderising/litestruts/StrutsTest.java" /> + <entry file="file://$PROJECT_DIR$/lesson5/src/main/java/java/lang/String.java" /> + <entry file="file://$PROJECT_DIR$/lesson5/src/main/java/com/coderising/jvm/constant/NameAndTypeInfo.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="567"> - <caret line="27" column="80" lean-forward="false" selection-start-line="27" selection-start-column="80" selection-end-line="27" selection-end-column="80" /> + <state relative-caret-position="-308"> + <caret line="2" column="13" lean-forward="false" selection-start-line="2" selection-start-column="13" selection-end-line="2" selection-end-column="13" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/build.gradle"> + <entry file="file://$PROJECT_DIR$/lesson5/src/main/java/com/coderising/jvm/constant/NullConstantInfo.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="357"> - <caret line="17" column="25" lean-forward="false" selection-start-line="17" selection-start-column="25" selection-end-line="17" selection-end-column="25" /> - <folding /> + <state relative-caret-position="46"> + <caret line="2" column="13" lean-forward="false" selection-start-line="2" selection-start-column="13" selection-end-line="2" selection-end-column="13" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson2/src/test/java/cn/net/pikachu/array/StrutsTest.java"> + <entry file="file://$PROJECT_DIR$/lesson1/src/main/java/cn/net/pikachu/basic/Stack.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="0"> - <caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" /> + <state relative-caret-position="69"> + <caret line="3" column="0" lean-forward="true" selection-start-line="3" selection-start-column="0" selection-end-line="3" selection-end-column="0" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson2/build.gradle"> + <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/basic/Stack.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="0"> - <caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" /> + <state relative-caret-position="46"> + <caret line="2" column="13" lean-forward="false" selection-start-line="2" selection-start-column="13" selection-end-line="2" selection-end-column="13" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson1/build.gradle"> + <entry file="file://$PROJECT_DIR$/lesson5/src/main/java/com/coding/basic/linklist/LRUPageFrameTest.java" /> + <entry file="file://$PROJECT_DIR$/build.gradle"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="105"> - <caret line="5" column="0" lean-forward="false" selection-start-line="5" selection-start-column="0" selection-end-line="5" selection-end-column="0" /> + <state relative-caret-position="0"> + <caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" /> + <folding /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson2/build.gradle"> + <entry file="file://$PROJECT_DIR$/lesson5/src/main/java/com/coding/basic/array/ArrayList.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="621"> - <caret line="27" column="80" lean-forward="false" selection-start-line="27" selection-start-column="80" selection-end-line="27" selection-end-column="80" /> + <state relative-caret-position="276"> + <caret line="13" column="0" lean-forward="false" selection-start-line="13" selection-start-column="0" selection-end-line="13" selection-end-column="0" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson2/src/test/java/cn/net/pikachu/array/StrutsTest.java"> + <entry file="file://$PROJECT_DIR$/lesson5/src/main/java/com/coding/basic/stack/Stack.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="115"> - <caret line="11" column="0" lean-forward="false" selection-start-line="11" selection-start-column="0" selection-end-line="11" selection-end-column="0" /> + <state relative-caret-position="391"> + <caret line="17" column="34" lean-forward="true" selection-start-line="17" selection-start-column="34" selection-end-line="17" selection-end-column="34" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson2/src/main/java/cn/net/pikachu/array/ArrayUtil.java"> + <entry file="file://$PROJECT_DIR$/lesson5/src/test/java/com/coding/basic/stack/StackUtilTest.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="368"> - <caret line="18" column="42" lean-forward="false" selection-start-line="18" selection-start-column="42" selection-end-line="18" selection-end-column="42" /> + <state relative-caret-position="276"> + <caret line="15" column="37" lean-forward="false" selection-start-line="15" selection-start-column="37" selection-end-line="15" selection-end-column="37" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson2/src/main/java/cn/net/pikachu/litestruts/Struts.java"> + <entry file="file://$PROJECT_DIR$/lesson5/src/main/java/com/coding/basic/stack/StackUtil.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="-1260"> - <caret line="28" column="8" lean-forward="false" selection-start-line="28" selection-start-column="8" selection-end-line="28" selection-end-column="8" /> + <state relative-caret-position="253"> + <caret line="16" column="25" lean-forward="false" selection-start-line="16" selection-start-column="25" selection-end-line="16" selection-end-column="25" /> + <folding> + <element signature="method#isValidPairs#0;class#StackUtil#0" expanded="false" /> + </folding> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/basic/ArrayList.java"> + <entry file="file://$PROJECT_DIR$/lesson5/src/main/java/com/coderising/jvm/test/EmployeeV1.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="0"> - <caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" /> + <state relative-caret-position="-50"> + <caret line="2" column="13" lean-forward="false" selection-start-line="2" selection-start-column="13" selection-end-line="2" selection-end-column="13" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson1/src/main/java/cn/net/pikachu/basic/LinkedList.java"> + <entry file="file://$PROJECT_DIR$/lesson5/src/main/java/com/coderising/jvm/constant/ClassInfo.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="115"> - <caret line="5" column="0" lean-forward="true" selection-start-line="5" selection-start-column="0" selection-end-line="159" selection-end-column="5" /> + <state relative-caret-position="46"> + <caret line="2" column="13" lean-forward="false" selection-start-line="2" selection-start-column="13" selection-end-line="2" selection-end-column="13" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson3/src/test/cn/net/pikachu/basic/LinkedListTest.java" /> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/FileDownloaderTest.java" /> - <entry file="file://$PROJECT_DIR$/build.gradle"> + <entry file="file://$PROJECT_DIR$/lesson5/src/main/java/com/coderising/jvm/constant/UTF8Info.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="90"> - <caret line="14" column="20" lean-forward="false" selection-start-line="14" selection-start-column="20" selection-end-line="14" selection-end-column="20" /> - <folding /> + <state relative-caret-position="46"> + <caret line="2" column="13" lean-forward="false" selection-start-line="2" selection-start-column="13" selection-end-line="2" selection-end-column="13" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/gradlew.bat"> + <entry file="file://$PROJECT_DIR$/lesson5/src/main/java/com/coderising/jvm/constant/FieldRefInfo.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="0"> - <caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" /> + <state relative-caret-position="23"> + <caret line="2" column="13" lean-forward="false" selection-start-line="2" selection-start-column="13" selection-end-line="2" selection-end-column="13" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/settings.gradle"> + <entry file="file://$PROJECT_DIR$/lesson5/build/classes/main/com/coderising/jvm/test/EmployeeV1.class"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="207"> - <caret line="17" column="31" lean-forward="false" selection-start-line="17" selection-start-column="31" selection-end-line="17" selection-end-column="31" /> - <folding /> + <state relative-caret-position="-188"> + <caret line="6" column="0" lean-forward="true" selection-start-line="6" selection-start-column="0" selection-end-line="6" selection-end-column="0" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/basic/test/main.kt"> + <entry file="file://$PROJECT_DIR$/lesson5/src/main/java/com/coderising/jvm/util/Util.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="460"> - <caret line="20" column="14" lean-forward="false" selection-start-line="20" selection-start-column="14" selection-end-line="20" selection-end-column="14" /> + <state relative-caret-position="92"> + <caret line="4" column="0" lean-forward="false" selection-start-line="4" selection-start-column="0" selection-end-line="4" selection-end-column="0" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson3/src/test/java/cn/net/pikachu/basic/LinkedListTest.java"> + <entry file="file://$PROJECT_DIR$/lesson5/src/main/java/com/coderising/jvm/constant/StringInfo.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="221"> - <caret line="242" column="0" lean-forward="true" selection-start-line="242" selection-start-column="0" selection-end-line="246" selection-end-column="21" /> + <state relative-caret-position="368"> + <caret line="26" column="0" lean-forward="false" selection-start-line="26" selection-start-column="0" selection-end-line="26" selection-end-column="0" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/basic/LinkedList.java"> + <entry file="file://$PROJECT_DIR$/lesson5/src/main/java/com/coderising/jvm/constant/ConstantPool.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="1655"> - <caret line="300" column="27" lean-forward="false" selection-start-line="300" selection-start-column="27" selection-end-line="300" selection-end-column="27" /> - <folding> - <element signature="imports" expanded="true" /> - <element signature="class#Itr#0;class#LinkedList#0" expanded="false" /> - <element signature="method#next#0;class#Itr#0;class#LinkedList#0" expanded="false" /> - <element signature="method#add#0;class#LinkedList#0" expanded="false" /> - <element signature="method#add#1;class#LinkedList#0" expanded="false" /> - <element signature="method#addFirst#0;class#LinkedList#0" expanded="false" /> - <element signature="method#removeFirst#0;class#LinkedList#0" expanded="false" /> - <element signature="method#removeLast#0;class#LinkedList#0" expanded="false" /> - <element signature="method#toString#0;class#LinkedList#0" expanded="false" /> - </folding> + <state relative-caret-position="292"> + <caret line="19" column="49" lean-forward="false" selection-start-line="19" selection-start-column="49" selection-end-line="19" selection-end-column="49" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/api/ConnectionException.java"> + <entry file="file://$PROJECT_DIR$/lesson5/src/main/java/com/coderising/jvm/clz/ClassIndex.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="46"> - <caret line="2" column="13" lean-forward="false" selection-start-line="2" selection-start-column="13" selection-end-line="2" selection-end-column="13" /> + <state relative-caret-position="69"> + <caret line="3" column="26" lean-forward="true" selection-start-line="3" selection-start-column="26" selection-end-line="3" selection-end-column="26" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson3/build.gradle"> + <entry file="file://$PROJECT_DIR$/lesson5/build/classes/main/com/coderising/jvm/clz/ClassFile.class"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="633"> - <caret line="30" column="0" lean-forward="true" selection-start-line="30" selection-start-column="0" selection-end-line="30" selection-end-column="0" /> - <folding /> + <state relative-caret-position="-1080"> + <caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/okhttp/Main.java" /> - <entry file="jar://E:/Program Files/Java/jdk1.8.0_111/src.zip!/java/io/InputStream.java"> + <entry file="file://$PROJECT_DIR$/lesson5/build/classes/main/com/coderising/jvm/clz/AccessFlag.class"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="1083"> - <caret line="160" column="15" lean-forward="false" selection-start-line="160" selection-start-column="15" selection-end-line="160" selection-end-column="15" /> - <folding /> + <state relative-caret-position="92"> + <caret line="4" column="0" lean-forward="true" selection-start-line="4" selection-start-column="0" selection-end-line="4" selection-end-column="0" /> + <folding> + <element signature="e#0#589#0" expanded="true" /> + </folding> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/api/DownloadListener.java"> + <entry file="file://$PROJECT_DIR$/lesson5/src/main/java/com/coderising/jvm/test/Main.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="46"> - <caret line="2" column="17" lean-forward="false" selection-start-line="2" selection-start-column="17" selection-end-line="2" selection-end-column="17" /> + <state relative-caret-position="115"> + <caret line="5" column="19" lean-forward="true" selection-start-line="5" selection-start-column="19" selection-end-line="5" selection-end-column="19" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/example/Downloader.java" /> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/api/ConnectionManager.java"> + <entry file="file://$PROJECT_DIR$/lesson5/src/main/java/com/coderising/jvm/constant/ConstantInfo.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="184"> - <caret line="8" column="22" lean-forward="false" selection-start-line="8" selection-start-column="22" selection-end-line="8" selection-end-column="22" /> + <state relative-caret-position="368"> + <caret line="16" column="0" lean-forward="false" selection-start-line="16" selection-start-column="0" selection-end-line="16" selection-end-column="0" /> </state> </provider> </entry> - <entry file="jar://E:/Program Files/Java/jdk1.8.0_111/src.zip!/java/io/RandomAccessFile.java"> + <entry file="file://$PROJECT_DIR$/lesson5/src/main/java/com/coderising/jvm/constant/MethodRefInfo.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="-366"> - <caret line="151" column="43" lean-forward="true" selection-start-line="151" selection-start-column="43" selection-end-line="151" selection-end-column="43" /> - <folding /> + <state relative-caret-position="230"> + <caret line="10" column="0" lean-forward="false" selection-start-line="10" selection-start-column="0" selection-end-line="10" selection-end-column="0" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/api/Connection.java"> + <entry file="file://$PROJECT_DIR$/lesson5/src/main/java/com/coderising/jvm/loader/ByteCodeIterator.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="184"> - <caret line="11" column="18" lean-forward="false" selection-start-line="11" selection-start-column="18" selection-end-line="11" selection-end-column="18" /> + <state relative-caret-position="368"> + <caret line="18" column="0" lean-forward="false" selection-start-line="18" selection-start-column="0" selection-end-line="18" selection-end-column="0" /> + <folding /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/impl/test/Main.java"> + <entry file="file://$PROJECT_DIR$/lesson5/src/main/java/com/coderising/jvm/clz/AccessFlag.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="299"> - <caret line="15" column="1" lean-forward="true" selection-start-line="15" selection-start-column="1" selection-end-line="15" selection-end-column="1" /> + <state relative-caret-position="276"> + <caret line="18" column="0" lean-forward="false" selection-start-line="18" selection-start-column="0" selection-end-line="18" selection-end-column="0" /> + <folding> + <element signature="e#342#343#0" expanded="true" /> + </folding> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/impl/test/DownloadWithRange.java"> + <entry file="jar://E:/Program Files/Java/jdk1.8.0_111/src.zip!/java/lang/Object.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="416"> - <caret line="48" column="60" lean-forward="false" selection-start-line="48" selection-start-column="60" selection-end-line="48" selection-end-column="60" /> + <state relative-caret-position="299"> + <caret line="36" column="0" lean-forward="false" selection-start-line="36" selection-start-column="0" selection-end-line="36" selection-end-column="0" /> + <folding /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/impl/test/DownloadFileWithThreadPool.java"> + <entry file="jar://E:/Program Files/Java/jdk1.8.0_111/src.zip!/java/lang/AbstractStringBuilder.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="215"> - <caret line="36" column="43" lean-forward="true" selection-start-line="36" selection-start-column="43" selection-end-line="36" selection-end-column="43" /> + <state relative-caret-position="989"> + <caret line="67" column="0" lean-forward="false" selection-start-line="67" selection-start-column="0" selection-end-line="67" selection-end-column="0" /> <folding> - <element signature="imports" expanded="true" /> + <element signature="e#1369#1370#0" expanded="true" /> </folding> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/kotlin/main.kt"> + <entry file="jar://E:/Program Files/Java/jdk1.8.0_111/src.zip!/java/lang/StringBuilder.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="449"> - <caret line="29" column="49" lean-forward="false" selection-start-line="29" selection-start-column="49" selection-end-line="29" selection-end-column="49" /> + <state relative-caret-position="1495"> + <caret line="88" column="0" lean-forward="false" selection-start-line="88" selection-start-column="0" selection-end-line="88" selection-end-column="0" /> <folding> - <element signature="e#0#100#0" expanded="true" /> - <element signature="n#!!doc;n#main#0" expanded="false" /> + <element signature="e#2896#2897#0" expanded="true" /> </folding> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/LogUtil.java"> + <entry file="file://$PROJECT_DIR$/lesson5/src/main/java/com/coderising/jvm/clz/ClassFile.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="161"> - <caret line="7" column="102" lean-forward="false" selection-start-line="7" selection-start-column="102" selection-end-line="7" selection-end-column="102" /> - <folding /> - </state> - </provider> - </entry> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/impl/ConnectionManagerImpl.java"> - <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="184"> - <caret line="23" column="67" lean-forward="false" selection-start-line="23" selection-start-column="67" selection-end-line="23" selection-end-column="67" /> + <state relative-caret-position="1081"> + <caret line="66" column="63" lean-forward="false" selection-start-line="66" selection-start-column="63" selection-end-line="66" selection-end-column="63" /> <folding /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/FileDownloader.java"> + <entry file="file://$PROJECT_DIR$/lesson5/src/main/java/com/coderising/jvm/loader/ClassFileLoader.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="253"> - <caret line="55" column="38" lean-forward="false" selection-start-line="55" selection-start-column="38" selection-end-line="55" selection-end-column="38" /> + <state relative-caret-position="1449"> + <caret line="76" column="0" lean-forward="false" selection-start-line="76" selection-start-column="0" selection-end-line="76" selection-end-column="0" /> <folding /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/DownloadThread.java"> + <entry file="file://$PROJECT_DIR$/lesson5/src/main/java/com/coderising/jvm/loader/ClassFileParser.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="483"> - <caret line="27" column="31" lean-forward="true" selection-start-line="27" selection-start-column="31" selection-end-line="27" selection-end-column="31" /> + <state relative-caret-position="851"> + <caret line="51" column="24" lean-forward="false" selection-start-line="51" selection-start-column="24" selection-end-line="51" selection-end-column="24" /> <folding /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/impl/ConnectionImpl.java"> + <entry file="file://$PROJECT_DIR$/lesson5/src/test/java/com/coderising/jvm/loader/test/ClassFileloaderTest.java"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="-416"> - <caret line="58" column="26" lean-forward="true" selection-start-line="58" selection-start-column="26" selection-end-line="58" selection-end-column="26" /> + <state relative-caret-position="2553"> + <caret line="123" column="48" lean-forward="false" selection-start-line="123" selection-start-column="48" selection-end-line="123" selection-end-column="48" /> <folding /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson3/src/main/java/cn/net/pikachu/download/FileUtil.java"> + <entry file="file://$PROJECT_DIR$/lesson5/build.gradle"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="299"> - <caret line="25" column="26" lean-forward="false" selection-start-line="25" selection-start-column="26" selection-end-line="25" selection-end-column="26" /> + <state relative-caret-position="680"> + <caret line="31" column="0" lean-forward="false" selection-start-line="31" selection-start-column="0" selection-end-line="31" selection-end-column="0" /> <folding /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lesson3/src/test/java/cn/net/pikachu/download/FileDownloaderTest.java"> + <entry file="file://$PROJECT_DIR$/src/main/kotlin/main.kt"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="460"> - <caret line="34" column="41" lean-forward="false" selection-start-line="34" selection-start-column="41" selection-end-line="34" selection-end-column="41" /> - <folding /> + <state relative-caret-position="161"> + <caret line="9" column="32" lean-forward="false" selection-start-line="9" selection-start-column="32" selection-end-line="9" selection-end-column="32" /> + <folding> + <element signature="n#!!doc;n#main#0" expanded="false" /> + </folding> </state> </provider> </entry> diff --git a/group13/2931408816/lesson4/src/main/java/com/coding/basic/BinaryTreeNode.java b/group13/2931408816/lesson4/src/main/java/com/coding/basic/BinaryTreeNode.java~CoderXLoong_master similarity index 100% rename from group13/2931408816/lesson4/src/main/java/com/coding/basic/BinaryTreeNode.java rename to group13/2931408816/lesson4/src/main/java/com/coding/basic/BinaryTreeNode.java~CoderXLoong_master diff --git a/group13/2931408816/lesson4/src/main/java/com/coding/basic/BinaryTreeNode.java~HEAD b/group13/2931408816/lesson4/src/main/java/com/coding/basic/BinaryTreeNode.java~HEAD new file mode 100644 index 0000000000..d7ac820192 --- /dev/null +++ b/group13/2931408816/lesson4/src/main/java/com/coding/basic/BinaryTreeNode.java~HEAD @@ -0,0 +1,32 @@ +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; + } + + public BinaryTreeNode insert(Object o){ + return null; + } + +} diff --git a/group13/2931408816/lesson4/src/main/java/com/coding/basic/Iterator.java b/group13/2931408816/lesson4/src/main/java/com/coding/basic/Iterator.java~CoderXLoong_master similarity index 100% rename from group13/2931408816/lesson4/src/main/java/com/coding/basic/Iterator.java rename to group13/2931408816/lesson4/src/main/java/com/coding/basic/Iterator.java~CoderXLoong_master diff --git a/group13/2931408816/lesson4/src/main/java/com/coding/basic/Iterator.java~HEAD b/group13/2931408816/lesson4/src/main/java/com/coding/basic/Iterator.java~HEAD new file mode 100644 index 0000000000..06ef6311b2 --- /dev/null +++ b/group13/2931408816/lesson4/src/main/java/com/coding/basic/Iterator.java~HEAD @@ -0,0 +1,7 @@ +package com.coding.basic; + +public interface Iterator { + public boolean hasNext(); + public Object next(); + +} diff --git a/group13/2931408816/lesson4/src/main/java/com/coding/basic/List.java b/group13/2931408816/lesson4/src/main/java/com/coding/basic/List.java~CoderXLoong_master similarity index 100% rename from group13/2931408816/lesson4/src/main/java/com/coding/basic/List.java rename to group13/2931408816/lesson4/src/main/java/com/coding/basic/List.java~CoderXLoong_master diff --git a/group13/2931408816/lesson4/src/main/java/com/coding/basic/List.java~HEAD b/group13/2931408816/lesson4/src/main/java/com/coding/basic/List.java~HEAD new file mode 100644 index 0000000000..10d13b5832 --- /dev/null +++ b/group13/2931408816/lesson4/src/main/java/com/coding/basic/List.java~HEAD @@ -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/group13/2931408816/lesson4/src/main/java/com/coding/basic/Stack.java b/group13/2931408816/lesson4/src/main/java/com/coding/basic/Stack.java~CoderXLoong_master similarity index 100% rename from group13/2931408816/lesson4/src/main/java/com/coding/basic/Stack.java rename to group13/2931408816/lesson4/src/main/java/com/coding/basic/Stack.java~CoderXLoong_master diff --git a/group13/2931408816/lesson4/src/main/java/com/coding/basic/Stack.java~HEAD b/group13/2931408816/lesson4/src/main/java/com/coding/basic/Stack.java~HEAD new file mode 100644 index 0000000000..459ec560b4 --- /dev/null +++ b/group13/2931408816/lesson4/src/main/java/com/coding/basic/Stack.java~HEAD @@ -0,0 +1,24 @@ +package com.coding.basic; + +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/group13/2931408816/lesson5/build.gradle b/group13/2931408816/lesson5/build.gradle new file mode 100644 index 0000000000..3d1b2e47df --- /dev/null +++ b/group13/2931408816/lesson5/build.gradle @@ -0,0 +1,31 @@ + +buildscript { + ext.kotlin_version = '1.1.1' + + repositories { + mavenCentral() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +apply plugin: 'java' +apply plugin: 'kotlin' + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +dependencies { + compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version" + // https://mvnrepository.com/artifact/commons-io/commons-io + compile group: 'commons-io', name: 'commons-io', version: '2.5' + + // https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 + compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.5' + + testCompile group: 'junit', name: 'junit', version: '4.12' +} diff --git a/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/clz/AccessFlag.java b/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..faae056835 --- /dev/null +++ b/group13/2931408816/lesson5/src/main/java/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/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/clz/ClassFile.java b/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..650ca8375d --- /dev/null +++ b/group13/2931408816/lesson5/src/main/java/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/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/clz/ClassIndex.java b/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..e424f284b3 --- /dev/null +++ b/group13/2931408816/lesson5/src/main/java/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/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/ClassInfo.java b/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..aea9048ea4 --- /dev/null +++ b/group13/2931408816/lesson5/src/main/java/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/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/ConstantInfo.java b/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..466b072244 --- /dev/null +++ b/group13/2931408816/lesson5/src/main/java/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/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/ConstantPool.java b/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..86c0445695 --- /dev/null +++ b/group13/2931408816/lesson5/src/main/java/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<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/FieldRefInfo.java b/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..65475e194c --- /dev/null +++ b/group13/2931408816/lesson5/src/main/java/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/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/MethodRefInfo.java b/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..7f05870020 --- /dev/null +++ b/group13/2931408816/lesson5/src/main/java/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/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/NameAndTypeInfo.java b/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..402f9dec86 --- /dev/null +++ b/group13/2931408816/lesson5/src/main/java/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/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/NullConstantInfo.java b/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..936736016f --- /dev/null +++ b/group13/2931408816/lesson5/src/main/java/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/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/StringInfo.java b/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..f1f8eb4ed4 --- /dev/null +++ b/group13/2931408816/lesson5/src/main/java/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/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/UTF8Info.java b/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..5cac9f04f7 --- /dev/null +++ b/group13/2931408816/lesson5/src/main/java/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/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/loader/ByteCodeIterator.java b/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..cb50f5fa55 --- /dev/null +++ b/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,37 @@ +package com.coderising.jvm.loader; + +import com.coderising.jvm.util.Util; + +public class ByteCodeIterator { + private int pos = 0; + private byte[] code; + + public ByteCodeIterator(byte[] code) { + this.code = code; + } + + public String nextU4ToHexString(){ + byte[] bytes=nextByte(4); + return Util.byteToHexString(bytes); + } + public int nextU2ToInt(){ + byte[] bytes = nextByte(2); + return Util.byteToInt(bytes); + } + public int nextU1ToInt(){ + byte[] bytes = nextByte(1); + return Util.byteToInt(bytes); + } + public String nextToString(int len){ + byte[] bytes = nextByte(len); + return new String(bytes); + } + private byte[] nextByte(int len){ + byte[] bytes = new byte[len]; + for (int i = 0; i < bytes.length; i++) { + bytes[i]=code[pos+i]; + } + pos+=len; + return bytes; + } +} diff --git a/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/loader/ClassFileLoader.java b/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..497e88e188 --- /dev/null +++ b/group13/2931408816/lesson5/src/main/java/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<String> clzPaths = new ArrayList<String>(); + + 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; + + } + + + + +} diff --git a/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/loader/ClassFileParser.java b/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..ee00216e0a --- /dev/null +++ b/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/loader/ClassFileParser.java @@ -0,0 +1,177 @@ +package com.coderising.jvm.loader; + +import java.io.UnsupportedEncodingException; +import java.util.Objects; + +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 { + private final int CONSTANT_CLASS = 7; + private final int CONSTANT_FIELD_REF = 9; + private final int CONSTANT_METHOD_REF = 10; // 0A + private final int CONSTANT_INTERFACE_METHOD_REF = 11; + private final int CONSTANT_STRING = 8; + private final int CONSTANT_INTEGER = 3; + private final int CONSTANT_FLOAT = 4; + private final int CONSTANT_LONG = 5; + private final int CONSTANT_DOUBLE = 6; + private final int CONSTANT_NAME_AND_TYPE = 12; // 0C + private final int CONSTANT_UTF8 = 1; + private final int CONSTANT_METHOD_HANDLE = 15; + private final int CONSTANT_METHOD_TYPE = 16; + private final int CONSTANT_INVOKE_DYNAMIC = 18; + + public ClassFile parse(byte[] codes) { + + // 读 Magic Number + ByteCodeIterator it = new ByteCodeIterator(codes); + String magicNumber = it.nextU4ToHexString(); + if (!Objects.equals("cafebabe", magicNumber)) { + throw new RuntimeException("这不是一个Java字节码文件"); + } + + ClassFile classFile = new ClassFile(); + // 读 次版本号 + int minorVersion = it.nextU2ToInt(); + classFile.setMinorVersion(minorVersion); + // 读 主版本号 + int majorVersion = it.nextU2ToInt(); + classFile.setMajorVersion(majorVersion); + classFile.setConstPool(parseConstantPool(it)); + classFile.setAccessFlag(parseAccessFlag(it)); + classFile.setClassIndex(parseClassInfex(it)); + return classFile; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + + return new AccessFlag(iter.nextU2ToInt()); + } + + private ClassIndex parseClassInfex(ByteCodeIterator iter) { + ClassIndex classIndex = new ClassIndex(); + classIndex.setThisClassIndex(iter.nextU2ToInt()); + classIndex.setSuperClassIndex(iter.nextU2ToInt()); + return classIndex; + + } + + private ConstantPool parseConstantPool(ByteCodeIterator it) { + + // 读 常量池个数 + int count = it.nextU2ToInt(); + ConstantPool constantPool = new ConstantPool(); + constantPool.addConstantInfo(new NullConstantInfo()); + for (int i = 0; i < count; i++) { + int tag = it.nextU1ToInt(); + switch (tag) { + case CONSTANT_CLASS: + ClassInfo classInfo = new ClassInfo(constantPool); + classInfo.setUtf8Index(it.nextU2ToInt()); + constantPool.addConstantInfo(classInfo); + System.out.println("classInfo "+classInfo.getUtf8Index()); + break; + case CONSTANT_UTF8: + UTF8Info utf8Info = new UTF8Info(constantPool); + utf8Info.setLength(it.nextU2ToInt()); + utf8Info.setValue(it.nextToString(utf8Info.getLength())); + constantPool.addConstantInfo(utf8Info); + System.out.println("utf-8 "+utf8Info.getValue()); + break; + case CONSTANT_METHOD_REF: + MethodRefInfo methodRefInfo = new MethodRefInfo(constantPool); + methodRefInfo.setClassInfoIndex(it.nextU2ToInt()); + methodRefInfo.setNameAndTypeIndex(it.nextU2ToInt()); + constantPool.addConstantInfo(methodRefInfo); + System.out.println("method ref "+methodRefInfo.getClassInfoIndex()+" "+methodRefInfo.getNameAndTypeIndex()); + break; + case CONSTANT_NAME_AND_TYPE: + NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(constantPool); + nameAndTypeInfo.setIndex1(it.nextU2ToInt()); + nameAndTypeInfo.setIndex2(it.nextU2ToInt()); + constantPool.addConstantInfo(nameAndTypeInfo); + System.out.println("name and type "+nameAndTypeInfo.getIndex1()+" "+nameAndTypeInfo.getIndex2()); + break; + case CONSTANT_FIELD_REF: + FieldRefInfo fieldRefInfo = new FieldRefInfo(constantPool); + fieldRefInfo.setClassInfoIndex(it.nextU2ToInt()); + fieldRefInfo.setNameAndTypeIndex(it.nextU2ToInt()); + constantPool.addConstantInfo(fieldRefInfo); + System.out.println("field ref "+fieldRefInfo.getClassInfoIndex()+" "+fieldRefInfo.getNameAndTypeIndex()); + break; + case CONSTANT_STRING: + StringInfo stringInfo = new StringInfo(constantPool); + stringInfo.setIndex(it.nextU2ToInt()); + constantPool.addConstantInfo(stringInfo); + System.out.println("string "+stringInfo.getIndex()); + break; + default: +// throw new RuntimeException("还不支持的tag " + tag); + } + } + return constantPool; + } + + public static void main(String[] args) { + String path1 = "D:\\src\\java\\study\\coding2017\\group13\\2931408816\\lesson5\\build\\classes\\main"; + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "com.coderising.jvm.test.Main"; + ClassFile clzFile = null; + clzFile = loader.loadClass(className); + clzFile.print(); + } +} +/* +Classfile /D:/src/java/study/coding2017/group13/2931408816/lesson5/build/classes/main/com/coderising/jvm/test/Main.class + Last modified 2017-4-9; size 285 bytes + MD5 checksum a159f82f5c9fecafdde2333579a3db3b + Compiled from "Main.java" +public class com.coderising.jvm.test.Main + minor version: 0 + major version: 52 + flags: ACC_PUBLIC, ACC_SUPER +Constant pool: + #1 = Methodref #3.#13 // java/lang/Object."<init>":()V + #2 = Class #14 // com/coderising/jvm/test/Main + #3 = Class #15 // java/lang/Object + #4 = Utf8 <init> + #5 = Utf8 ()V + #6 = Utf8 Code + #7 = Utf8 LineNumberTable + #8 = Utf8 LocalVariableTable + #9 = Utf8 this + #10 = Utf8 Lcom/coderising/jvm/test/Main; + #11 = Utf8 SourceFile + #12 = Utf8 Main.java + #13 = NameAndType #4:#5 // "<init>":()V + #14 = Utf8 com/coderising/jvm/test/Main + #15 = Utf8 java/lang/Object +{ + public com.coderising.jvm.test.Main(); + descriptor: ()V + flags: ACC_PUBLIC + Code: + stack=1, locals=1, args_size=1 + 0: aload_0 + 1: invokespecial #1 // Method java/lang/Object."<init>":()V + 4: return + LineNumberTable: + line 6: 0 + LocalVariableTable: + Start Length Slot Name Signature + 0 5 0 this Lcom/coderising/jvm/test/Main; +} +SourceFile: "Main.java" + */ \ No newline at end of file diff --git a/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/test/EmployeeV1.java b/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..12e3d7efdd --- /dev/null +++ b/group13/2931408816/lesson5/src/main/java/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/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/test/Main.java b/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/test/Main.java new file mode 100644 index 0000000000..45601d76ff --- /dev/null +++ b/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/test/Main.java @@ -0,0 +1,7 @@ +package com.coderising.jvm.test; + +/** + * Created by pikachu on 2017/4/9. + */ +public class Main { +} diff --git a/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/util/Util.java b/group13/2931408816/lesson5/src/main/java/com/coderising/jvm/util/Util.java new file mode 100644 index 0000000000..0c4cc8c57c --- /dev/null +++ b/group13/2931408816/lesson5/src/main/java/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<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/group13/2931408816/lesson5/src/main/java/com/coding/basic/BinaryTreeNode.java b/group13/2931408816/lesson5/src/main/java/com/coding/basic/BinaryTreeNode.java new file mode 100644 index 0000000000..d7ac820192 --- /dev/null +++ b/group13/2931408816/lesson5/src/main/java/com/coding/basic/BinaryTreeNode.java @@ -0,0 +1,32 @@ +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; + } + + public BinaryTreeNode insert(Object o){ + return null; + } + +} diff --git a/group13/2931408816/lesson5/src/main/java/com/coding/basic/Iterator.java b/group13/2931408816/lesson5/src/main/java/com/coding/basic/Iterator.java new file mode 100644 index 0000000000..06ef6311b2 --- /dev/null +++ b/group13/2931408816/lesson5/src/main/java/com/coding/basic/Iterator.java @@ -0,0 +1,7 @@ +package com.coding.basic; + +public interface Iterator { + public boolean hasNext(); + public Object next(); + +} diff --git a/group13/2931408816/lesson5/src/main/java/com/coding/basic/List.java b/group13/2931408816/lesson5/src/main/java/com/coding/basic/List.java new file mode 100644 index 0000000000..10d13b5832 --- /dev/null +++ b/group13/2931408816/lesson5/src/main/java/com/coding/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/group13/2931408816/lesson5/src/main/java/com/coding/basic/Queue.java b/group13/2931408816/lesson5/src/main/java/com/coding/basic/Queue.java new file mode 100644 index 0000000000..36e516e266 --- /dev/null +++ b/group13/2931408816/lesson5/src/main/java/com/coding/basic/Queue.java @@ -0,0 +1,19 @@ +package com.coding.basic; + +public class Queue { + + public void enQueue(Object o){ + } + + public Object deQueue(){ + return null; + } + + public boolean isEmpty(){ + return false; + } + + public int size(){ + return -1; + } +} diff --git a/group13/2931408816/lesson5/src/main/java/com/coding/basic/array/ArrayList.java b/group13/2931408816/lesson5/src/main/java/com/coding/basic/array/ArrayList.java new file mode 100644 index 0000000000..4576c016af --- /dev/null +++ b/group13/2931408816/lesson5/src/main/java/com/coding/basic/array/ArrayList.java @@ -0,0 +1,35 @@ +package com.coding.basic.array; + +import com.coding.basic.Iterator; +import com.coding.basic.List; + +public class ArrayList implements List { + + private int size = 0; + + private Object[] elementData = new Object[100]; + + 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 Iterator iterator(){ + return null; + } + +} diff --git a/group13/2931408816/lesson5/src/main/java/com/coding/basic/array/ArrayUtil.java b/group13/2931408816/lesson5/src/main/java/com/coding/basic/array/ArrayUtil.java new file mode 100644 index 0000000000..45740e6d57 --- /dev/null +++ b/group13/2931408816/lesson5/src/main/java/com/coding/basic/array/ArrayUtil.java @@ -0,0 +1,96 @@ +package com.coding.basic.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 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){ + return null; + } + + /** + * 给定两个已经排序好的整形数组, 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){ + return null; + } + /** + * 把一个已经存满数据的数组 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){ + return null; + } + + /** + * 斐波那契数列为: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){ + return null; + } + + /** + * 返回小于给定最大值max的所有素数数组 + * 例如max = 23, 返回的数组为[2,3,5,7,11,13,17,19] + * @param max + * @return + */ + public int[] getPrimes(int max){ + return null; + } + + /** + * 所谓“完数”, 是指这个数恰好等于它的因子之和,例如6=1+2+3 + * 给定一个最大值max, 返回一个数组, 数组中是小于max 的所有完数 + * @param max + * @return + */ + public int[] getPerfectNumbers(int max){ + return null; + } + + /** + * 用seperator 把数组 array给连接起来 + * 例如array= [3,8,9], seperator = "-" + * 则返回值为"3-8-9" + * @param array + * @param s + * @return + */ + public String join(int[] array, String seperator){ + return null; + } + + +} diff --git a/group13/2931408816/lesson5/src/main/java/com/coding/basic/stack/Stack.java b/group13/2931408816/lesson5/src/main/java/com/coding/basic/stack/Stack.java new file mode 100644 index 0000000000..12a71d0282 --- /dev/null +++ b/group13/2931408816/lesson5/src/main/java/com/coding/basic/stack/Stack.java @@ -0,0 +1,35 @@ +package com.coding.basic.stack; + + +import java.util.ArrayList; +import java.util.NoSuchElementException; + +public class Stack { + private ArrayList elementData = new ArrayList(); + + public void push(Object o){ + elementData.add(o); + } + + public Object pop(){ + if (isEmpty()){ + throw new NoSuchElementException(); + } + return elementData.remove(elementData.size()-1); + } + + public Object peek(){ + return elementData.get(elementData.size()-1); + } + public boolean isEmpty(){ + return elementData.size()==0; + } + public int size(){ + return elementData.size(); + } + + @Override + public String toString() { + return elementData.toString(); + } +} diff --git a/group13/2931408816/lesson5/src/main/java/com/coding/basic/stack/StackUtil.java b/group13/2931408816/lesson5/src/main/java/com/coding/basic/stack/StackUtil.java new file mode 100644 index 0000000000..cb36f289b9 --- /dev/null +++ b/group13/2931408816/lesson5/src/main/java/com/coding/basic/stack/StackUtil.java @@ -0,0 +1,134 @@ +package com.coding.basic.stack; + +import java.util.NoSuchElementException; + +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 a = new Stack(); + + while (!s.isEmpty()){ + Object o = s.pop(); + int count =0; + while (!a.isEmpty()){ + s.push(a.pop()); + count++; + } + a.push(o); + for (int i = 0; i < count; i++) { + a.push(s.pop()); + } + } + while (!a.isEmpty()){ + s.push(a.pop()); + } + } + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s,Object o) { + Stack stack = new Stack(); + boolean flag = false; + while (!s.isEmpty()){ + Object t = s.pop(); + if (t.equals(o)){ + flag=true; + break; + } + stack.push(t); + } + while (!stack.isEmpty()){ + s.push(stack.pop()); + } + if (!flag){ + throw new NoSuchElementException(o.toString()); + } + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * @param len + * @return + */ + public static Object[] getTop(Stack s,int len) { + if (s.size()<len){ + throw new IndexOutOfBoundsException(len+""); + } + Object[] objects = new Object[len]; + Stack stack = new Stack(); + for (int i = 0; i < len; i++) { + Object t = s.pop(); + stack.push(t); + objects[i]=t; + } + while (!stack.isEmpty()){ + s.push(stack.pop()); + } + return objects; + } + /** + * 字符串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 stack = new Stack(); + String string = "([{}])"; + String stringLeft = "([{"; + for (int i = 0; i < s.length(); i++) { + char ch = s.charAt(i); + if (string.indexOf(ch)>=0){ + if(stringLeft.indexOf(ch)>=0){ + stack.push(Character.valueOf(ch)); + }else { + Character top = (Character) stack.peek(); + switch (top){ + case '{': + if (ch == '}'){ + stack.pop(); + }else { + return false; + } + break; + case '[': + if (ch==']'){ + stack.pop(); + }else { + return false; + } + break; + case '(': + if (ch==')'){ + stack.pop(); + }else { + return false; + } + break; + } + } + } + } + return true; + } + + public static void main(String[] args) { + + Stack stack = new Stack(); + for (int i = 0; i < 5; i++) { + stack.push(i+1); + } + StackUtil.reverse(stack); + } +} diff --git a/group13/2931408816/lesson5/src/test/java/com/coderising/jvm/loader/test/ClassFileloaderTest.java b/group13/2931408816/lesson5/src/test/java/com/coderising/jvm/loader/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..1c6c111f03 --- /dev/null +++ b/group13/2931408816/lesson5/src/test/java/com/coderising/jvm/loader/test/ClassFileloaderTest.java @@ -0,0 +1,197 @@ +package com.coderising.jvm.loader.test; + +import org.junit.After; +import org.junit.Assert; +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; + + + + + +public class ClassFileloaderTest { + + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + + static String path1 = "D:\\src\\java\\study\\coding2017\\group13\\2931408816\\lesson5\\build\\classes\\main"; + 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 { + } + + @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(); + } + + /** + * ---------------------------------------------------------------------- + */ + + + @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("<init>", 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/group13/2931408816/lesson5/src/test/java/com/coding/basic/stack/StackUtilTest.java b/group13/2931408816/lesson5/src/test/java/com/coding/basic/stack/StackUtilTest.java new file mode 100644 index 0000000000..b39281b245 --- /dev/null +++ b/group13/2931408816/lesson5/src/test/java/com/coding/basic/stack/StackUtilTest.java @@ -0,0 +1,61 @@ +package com.coding.basic.stack; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.Collections; + +/** + * Created by pikachu on 2017/4/7. + */ +public class StackUtilTest { + // public static void reverse(Stack s) + @Test + public void testReverse(){ + Stack stack = new Stack(); + for (int i = 0; i < 5; i++) { + stack.push(i+1); + } + Assert.assertEquals("[1, 2, 3, 4, 5]",stack.toString()); + StackUtil.reverse(stack); + Assert.assertEquals("[5, 4, 3, 2, 1]",stack.toString()); + } + // public static void remove(Stack s,Object o) + @Test + public void testRemove(){ + Stack stack = new Stack(); + for (int i = 0; i < 6; i++) { + stack.push(i); + } + StackUtil.remove(stack,0); + Assert.assertEquals("[1, 2, 3, 4, 5]", stack.toString()); + + StackUtil.remove(stack,3); + Assert.assertEquals("[1, 2, 4, 5]", stack.toString()); + + StackUtil.remove(stack,5); + Assert.assertEquals("[1, 2, 4]", stack.toString()); + } + // public static Object[] getTop(Stack s,int len) + @Test + public void testGetTop(){ + Stack stack = new Stack(); + for (int i = 0; i < 10; i++) { + stack.push(i); + } + Object[] objects = StackUtil.getTop(stack,2); + Assert.assertArrayEquals(new Object[]{9,8},objects); + } + // public static boolean isValidPairs(String s) + + /** + * + * 例如s = "([e{d}f])" , 则该字符串中的括号是成对出现, 该方法返回true + * 如果 s = "([b{x]y})", 则该字符串中的括号不是成对出现的, 该方法返回false; + */ + @Test + public void testIsValidPairs(){ + Assert.assertTrue( StackUtil.isValidPairs("([e{d}f])")); + Assert.assertFalse(StackUtil.isValidPairs("([b{x]y})")); + } +} diff --git a/group13/2931408816/settings.gradle b/group13/2931408816/settings.gradle index e28c5f17d9..639272767b 100644 --- a/group13/2931408816/settings.gradle +++ b/group13/2931408816/settings.gradle @@ -20,4 +20,5 @@ include 'lesson1' include 'lesson2' include 'lesson3' include 'lesson4' +include 'lesson5' diff --git a/group13/2931408816/src/main/kotlin/main.kt b/group13/2931408816/src/main/kotlin/main.kt new file mode 100644 index 0000000000..c3df289e2d --- /dev/null +++ b/group13/2931408816/src/main/kotlin/main.kt @@ -0,0 +1,13 @@ +/** + * Created by pikachu on 2017/4/10. + */ + +fun main(args: Array<String>) { + (1..25).forEach { + if(it<10) + println("group0${it}/") + else{ + println("group${it}/") + } + } +} \ No newline at end of file From a62dab5bf9a577a3e75f812c4ef791cfc03501d7 Mon Sep 17 00:00:00 2001 From: Admin <Admin@DESKTOP-8UCBO6T> Date: Mon, 10 Apr 2017 08:25:52 +0800 Subject: [PATCH 189/287] paser --- .../src/com/coderising/jvm/loader/ClassFileParser.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/group12/382266293/src/com/coderising/jvm/loader/ClassFileParser.java b/group12/382266293/src/com/coderising/jvm/loader/ClassFileParser.java index 1d981e1dd6..2db5f6e085 100644 --- a/group12/382266293/src/com/coderising/jvm/loader/ClassFileParser.java +++ b/group12/382266293/src/com/coderising/jvm/loader/ClassFileParser.java @@ -111,8 +111,9 @@ public ClassFile parse(byte[] codes) { } - ClassIndex classIndex = parseClassIndex(iter); AccessFlag accessFlag = parseAccessFlag(iter); + ClassIndex classIndex = parseClassIndex(iter); + clzFile.setAccessFlag(accessFlag); clzFile.setClassIndex(classIndex); From 00b7fb984cf13faa0a79db872e4a97e198322a6c Mon Sep 17 00:00:00 2001 From: zhanglei <383117348@qq.com> Date: Mon, 10 Apr 2017 10:13:16 +0800 Subject: [PATCH 190/287] =?UTF-8?q?StackUtil=E6=95=B0=E6=8D=AE=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/com/coding/basic/stack/StackUtil.java | 107 ++++++++++++++++++ .../basic/stack/test/StackUtilTest.java | 68 +++++++++++ 2 files changed, 175 insertions(+) create mode 100644 group27/383117348/src/com/coding/basic/stack/StackUtil.java create mode 100644 group27/383117348/src/com/coding/basic/stack/test/StackUtilTest.java diff --git a/group27/383117348/src/com/coding/basic/stack/StackUtil.java b/group27/383117348/src/com/coding/basic/stack/StackUtil.java new file mode 100644 index 0000000000..dfb1c95e7d --- /dev/null +++ b/group27/383117348/src/com/coding/basic/stack/StackUtil.java @@ -0,0 +1,107 @@ +package com.coding.basic.stack; + +import org.junit.Test; + +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()) { + Object [] obj = new Object[s.size()]; + for(int i =0 ;i < obj.length; i++){ + obj[i] = s.pop(); + } + for(int i =0 ;i < obj.length; i++){ + s.push(obj[i]); + } + }else{ + + } + } + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s, Object o) { + if(s!=null && s.size()>0){ + Stack newStack = new Stack(); + while(s.size()>0){ + newStack.push(s.pop()); + if(newStack.peek().equals(o)){ + newStack.pop(); + } + } + while(newStack.size()>0){ + s.push(newStack.pop()); + } + }else{ + + } + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, + * 可以使用另外一个栈来辅助 + * + * @param len + * @return + */ + public static Object[] getTop(Stack s, int len) { + if(s!=null && s.size()>0 && len>0 && len<=s.size()){ + Object[] objs = new Object[len]; + Stack newStack = new Stack(); + for(int i = 0;i<len;i++){ + objs[i] = s.pop(); + newStack.push(objs[i]); + } + while(newStack.size()>0){ + s.push(newStack.pop()); + } + return objs; + } + 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) { + char[] chars = s.toCharArray(); + Stack special = new Stack(); + for(int i =0; i <chars.length ; i++){ + char cha = chars[i]; + if(cha == '(' || cha == '{' ||cha=='[' ){ + special.push(cha); + }else if(cha == ')'){ + if(special.peek().equals('(')){ + special.pop(); + } + }else if(cha == '}'){ + if(special.peek().equals('{')){ + special.pop(); + } + }else if(cha == ']'){ + if(special.peek().equals('[')){ + special.pop(); + } + } + + } + if(special.size()==0){ + return true; + } + return false; + } + +} diff --git a/group27/383117348/src/com/coding/basic/stack/test/StackUtilTest.java b/group27/383117348/src/com/coding/basic/stack/test/StackUtilTest.java new file mode 100644 index 0000000000..53b221c932 --- /dev/null +++ b/group27/383117348/src/com/coding/basic/stack/test/StackUtilTest.java @@ -0,0 +1,68 @@ +package com.coding.basic.stack.test; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.coding.basic.stack.Stack; +import com.coding.basic.stack.StackUtil; + + +public class StackUtilTest { + + Stack s = null; + + @Before + public void init(){ + s = new Stack(); + s.push("1"); + s.push("2"); + s.push("3"); + s.push("4"); + s.push("5"); + } + @After + public void destory(){ + s = null; + } + + @Test + public void testReverse(){ + StackUtil.reverse(s); + String str = printInfo(); + Assert.assertEquals("1;2;3;4;5;",str); + } + + @Test + public void testRemove(){ + StackUtil.remove(s, "3"); + String str = printInfo(); + Assert.assertEquals("5;4;2;1;",str); + } + + @Test + public void testGetTop(){ + Object[] obj = StackUtil.getTop(s,3); + Assert.assertEquals("3",obj[2]); + String str = printInfo(); + Assert.assertEquals("5;4;3;2;1;",str); + } + + @Test + public void testisValidPairs(){ + boolean flag1 = StackUtil.isValidPairs("([b[[[((({x})))]]]y])"); + Assert.assertEquals(true,flag1); + boolean flag2 = StackUtil.isValidPairs("([b{x]y})"); + Assert.assertEquals(false,flag2); + } + + public String printInfo(){ + String str = ""; + while(s.size()>0){ + str+=s.pop()+";"; + } + return str; + } + +} From 9d07aea4cc36cc64028473cd7281a4479ce7ac1b Mon Sep 17 00:00:00 2001 From: CoderXLoong <413007522@qq.com> Date: Mon, 10 Apr 2017 10:23:53 +0800 Subject: [PATCH 191/287] Signed-off-by: CoderXLoong <413007522@qq.com> --- .../main/java/cn/xl/basic/stack/MyStack.java | 124 +++++++++++ .../java/cn/xl/basic/stack/StackUtil.java | 190 ++++++++++++++++ .../java/cn/xl/basic/stack/StackUtilTest.java | 84 +++++++ .../main/java/cn/xl/jvm/clz/AccessFlag.java | 25 +++ .../main/java/cn/xl/jvm/clz/ClassFile.java | 75 +++++++ .../main/java/cn/xl/jvm/clz/ClassIndex.java | 19 ++ .../java/cn/xl/jvm/constant/ClassInfo.java | 24 ++ .../java/cn/xl/jvm/constant/ConstantInfo.java | 29 +++ .../java/cn/xl/jvm/constant/ConstantPool.java | 29 +++ .../java/cn/xl/jvm/constant/FieldRefInfo.java | 54 +++++ .../cn/xl/jvm/constant/MethodRefInfo.java | 55 +++++ .../cn/xl/jvm/constant/NameAndTypeInfo.java | 45 ++++ .../cn/xl/jvm/constant/NullConstantInfo.java | 13 ++ .../java/cn/xl/jvm/constant/StringInfo.java | 26 +++ .../java/cn/xl/jvm/constant/UTF8Info.java | 32 +++ .../cn/xl/jvm/loader/ByteCodeIterator.java | 83 +++++++ .../cn/xl/jvm/loader/ClassFileLoader.java | 115 ++++++++++ .../cn/xl/jvm/loader/ClassFileParser.java | 126 +++++++++++ .../java/cn/xl/jvm/loader/EmployeeV1.java | 28 +++ .../src/main/java/cn/xl/jvm/util/Util.java | 43 ++++ .../jvm/loader/ByteCodeInteratorTest.java | 28 +++ .../java/jvm/loader/ClassFileloaderTest.java | 205 ++++++++++++++++++ 22 files changed, 1452 insertions(+) create mode 100644 group13/413007522/lesson05/src/main/java/cn/xl/basic/stack/MyStack.java create mode 100644 group13/413007522/lesson05/src/main/java/cn/xl/basic/stack/StackUtil.java create mode 100644 group13/413007522/lesson05/src/main/java/cn/xl/basic/stack/StackUtilTest.java create mode 100644 group13/413007522/lesson05/src/main/java/cn/xl/jvm/clz/AccessFlag.java create mode 100644 group13/413007522/lesson05/src/main/java/cn/xl/jvm/clz/ClassFile.java create mode 100644 group13/413007522/lesson05/src/main/java/cn/xl/jvm/clz/ClassIndex.java create mode 100644 group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/ClassInfo.java create mode 100644 group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/ConstantInfo.java create mode 100644 group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/ConstantPool.java create mode 100644 group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/FieldRefInfo.java create mode 100644 group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/MethodRefInfo.java create mode 100644 group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/NameAndTypeInfo.java create mode 100644 group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/NullConstantInfo.java create mode 100644 group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/StringInfo.java create mode 100644 group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/UTF8Info.java create mode 100644 group13/413007522/lesson05/src/main/java/cn/xl/jvm/loader/ByteCodeIterator.java create mode 100644 group13/413007522/lesson05/src/main/java/cn/xl/jvm/loader/ClassFileLoader.java create mode 100644 group13/413007522/lesson05/src/main/java/cn/xl/jvm/loader/ClassFileParser.java create mode 100644 group13/413007522/lesson05/src/main/java/cn/xl/jvm/loader/EmployeeV1.java create mode 100644 group13/413007522/lesson05/src/main/java/cn/xl/jvm/util/Util.java create mode 100644 group13/413007522/lesson05/src/test/java/jvm/loader/ByteCodeInteratorTest.java create mode 100644 group13/413007522/lesson05/src/test/java/jvm/loader/ClassFileloaderTest.java diff --git a/group13/413007522/lesson05/src/main/java/cn/xl/basic/stack/MyStack.java b/group13/413007522/lesson05/src/main/java/cn/xl/basic/stack/MyStack.java new file mode 100644 index 0000000000..8987537b09 --- /dev/null +++ b/group13/413007522/lesson05/src/main/java/cn/xl/basic/stack/MyStack.java @@ -0,0 +1,124 @@ +package cn.xl.basic.stack; + +import java.util.Arrays; +import java.util.EmptyStackException; + +/** + * Stackһȳlast in first outLIFOĶջ + * VectorĻչ5 + * @author XIAOLONG + * + */ +public class MyStack { + + private int elementCount; + + private Object[] elementData = new Object[5]; + + /** + * ޲ι췽һջ + * + */ + public MyStack(){ + + } + + + /** + * Ԫջ + * @param item + * @return ջԪ + */ + public synchronized Object push(Object item){ + + ensureCapacity(elementCount+1); + elementData[elementCount] = item; + elementCount ++; + return item; + } + + /** + * ջԪƳظԪ + * @return ջԪ + */ + public synchronized Object pop(){ + Object obj; + + obj = peek(); + elementCount --; + elementData[elementCount] = null; + + return obj; + } + + /** + * 鿴ջԪ + * + * @return ջԪ + * @throws ջΪ ׳ EmptyStackException쳣 . + */ + public synchronized Object peek(){ + int len = elementCount; + + if(len == 0) + throw new EmptyStackException(); + + return elementData[len - 1]; + + } + + /** + * ջǷΪ + * + * @return True or false + */ + public boolean isEmpty(){ + + return elementCount == 0; + } + + /** + * ѯռջǷijԪ + * @param ѯԪ + * @return ԪشڷԪλãջԪλΪ1 + * Ԫջظ򷵻ؾջԪλã + * Ԫջвڣ򷵻 -1 + */ + public synchronized int search(Object o){ + + if(o == null){ + for(int i = elementCount -1;i >= 0; i--){ + if(elementData[i] == null){ + return elementCount - i; + } + } + }else{ + for(int i = elementCount -1;i >= 0; i-- ){ + if(o.equals(elementData[i])){ + return elementCount - i; + } + } + } + + return -1; + } + + /** + * չһ + * @param ǰջСsize + */ + private void ensureCapacity(int minCapacity){ + int oldCapacity = elementData.length; + if(minCapacity > oldCapacity){ + int newCapacity = oldCapacity << 1; + elementData = Arrays.copyOf(elementData, newCapacity); + } + } + + public static void main(String[] args){ + + + + } + +} diff --git a/group13/413007522/lesson05/src/main/java/cn/xl/basic/stack/StackUtil.java b/group13/413007522/lesson05/src/main/java/cn/xl/basic/stack/StackUtil.java new file mode 100644 index 0000000000..ca686ab19b --- /dev/null +++ b/group13/413007522/lesson05/src/main/java/cn/xl/basic/stack/StackUtil.java @@ -0,0 +1,190 @@ +package cn.xl.basic.stack; + + +public class StackUtil { + + + /** + * 假设栈中的元素是Integer, 从栈顶到栈底是 : 5,4,3,2,1 调用该方法后, 元素次序变为: 1,2,3,4,5 + * 注意:只能使用MyStack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + */ + public static void reverse(MyStack s) { + + if(s == null || s.isEmpty()){ + return ; + } + + MyStack ns = new MyStack(); + Object o = s.pop(); + int count = 0; + while(!s.isEmpty()){ + ns.push(s.pop()); + count ++; + } + s.push(o); + + while(!ns.isEmpty()){ + s.push(ns.pop()); + } + + for(int i = 0; i < count - 1 ;i++){ + o = s.pop(); + for(int j = 0; j < count - 1 - i ;j++){ + ns.push(s.pop()); + } + s.push(o); + while(!ns.isEmpty()){ + s.push(ns.pop()); + } + } + + //组员写的 ,不错 + /*MyStack a = new MyStack(); + + while (!s.isEmpty()){ + Object o = s.pop(); + int count =0; + while (!a.isEmpty()){ + s.push(a.pop()); + count++; + } + a.push(o); + for (int i = 0; i < count; i++) { + a.push(s.pop()); + } + } + while (!a.isEmpty()){ + s.push(a.pop()); + } + + return s;*/ + } + + /** + * 删除栈中的某个元素 注意:只能使用MyStack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(MyStack s,Object o) { + + if(s == null || s.isEmpty()){ + return ; + } + + MyStack ms = new MyStack(); + Object obj = null; + while(!s.isEmpty()){ + obj = s.pop(); + if(obj == null){ + if(o == null){ + continue; + }else{ + ms.push(obj); + } + }else{ + if(obj.equals(o)|| obj.toString().equals(o)){ + continue; + }else{ + ms.push(obj); + } + } + } + + while(!ms.isEmpty()){ + s.push(ms.pop()); + } + + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 + * 注意:只能使用MyStack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * @param len + * @return + */ + public static Object[] getTop(MyStack s,int len) { + MyStack ns = new MyStack(); + int count = 0; + Object[] o = new Object[len]; + while(!s.isEmpty()){ + ns.push(s.pop()); + count++; + } + int n = 0; + for(int i = 0; i < count - len;i++){ + if(i < count - len){ + s.push(ns.pop()); + }else{ + o[n] = ns.pop(); + n++; + } + } + + return o; + } + /** + * 字符串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 || "".equals(s)){ + return true; + } + char[] b = s.toCharArray(); + MyStack ms = new MyStack(); + String str = null; + for(int i = 0; i < b.length ; i++){ + str = String.valueOf(b[i]); + if("(".equals(str)){ + ms.push(b[i]); + }else if(")".equals(str)){ + if(!popObj(ms,"("))return false; + }else if("[".equals(str)){ + ms.push(b[i]); + }else if("]".equals(str)){ + if(!popObj(ms,"["))return false; + }else if("{".equals(str)){ + ms.push(b[i]); + }else if("}".equals(str)){ + if(!popObj(ms,"{"))return false; + } + } + if(ms.isEmpty()){ + return true; + } + return false; + } + + + private static boolean popObj(MyStack s,Object o) { + + MyStack ms = new MyStack(); + Object obj = null; + while(!s.isEmpty()){ + obj = s.pop(); + if(obj.equals(o)||obj.toString().equals(o)){ + while(!ms.isEmpty()){ + s.push(ms.pop()); + } + return true; + }else{ + ms.push(obj); + } + } + return false; + } + + + + public static void main(String[] args){ + + + + } + +} diff --git a/group13/413007522/lesson05/src/main/java/cn/xl/basic/stack/StackUtilTest.java b/group13/413007522/lesson05/src/main/java/cn/xl/basic/stack/StackUtilTest.java new file mode 100644 index 0000000000..c7e4e6a51f --- /dev/null +++ b/group13/413007522/lesson05/src/main/java/cn/xl/basic/stack/StackUtilTest.java @@ -0,0 +1,84 @@ +package cn.xl.basic.stack; + +import org.junit.Test; + +import junit.framework.Assert; + +public class StackUtilTest { + + + @Test + public void reverse(){ + MyStack s = new MyStack(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + s.push(6); + s.push(7); + s.push(8); + s.push(9); + s.push(10); + s.push(11); + /*MyStack my = StackUtil.reverse(s); + while(!my.isEmpty()){ + System.out.println(my.pop()); + }*/ + } + + + @Test + public void getTop(){ + MyStack s = new MyStack(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + s.push(6); + s.push(7); + s.push(8); + s.push(9); + s.push(10); + s.push(11); + + Object[] o = StackUtil.getTop(s,5); + + Assert.assertEquals(5, o.length); + + /*while(!s.isEmpty()){ + System.out.println(s.pop()); + }*/ + } + + @Test + public void remove(){ + + MyStack s = new MyStack(); + s.push(1); + s.push(2); + s.push(4); + s.push(3); + s.push(4); + s.push(5); + s.push(6); + + + StackUtil.remove(s, 4); + while(!s.isEmpty()){ + System.out.println(s.pop()); + } + + } + + + @Test + public void isValidPairs(){ + + Assert.assertEquals(true, StackUtil.isValidPairs("([e[{{}}df]])")); + + + } + +} diff --git a/group13/413007522/lesson05/src/main/java/cn/xl/jvm/clz/AccessFlag.java b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..26d209563c --- /dev/null +++ b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/clz/AccessFlag.java @@ -0,0 +1,25 @@ +package cn.xl.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/group13/413007522/lesson05/src/main/java/cn/xl/jvm/clz/ClassFile.java b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..384afe2efe --- /dev/null +++ b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/clz/ClassFile.java @@ -0,0 +1,75 @@ +package cn.xl.jvm.clz; + +import cn.xl.jvm.constant.ClassInfo; +import cn.xl.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/group13/413007522/lesson05/src/main/java/cn/xl/jvm/clz/ClassIndex.java b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..3f7b12dcdf --- /dev/null +++ b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/clz/ClassIndex.java @@ -0,0 +1,19 @@ +package cn.xl.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/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/ClassInfo.java b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..a57c7f31b4 --- /dev/null +++ b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/ClassInfo.java @@ -0,0 +1,24 @@ +package cn.xl.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/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/ConstantInfo.java b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..146329cdf1 --- /dev/null +++ b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/ConstantInfo.java @@ -0,0 +1,29 @@ +package cn.xl.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/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/ConstantPool.java b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..45c0b54c57 --- /dev/null +++ b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/ConstantPool.java @@ -0,0 +1,29 @@ +package cn.xl.jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/FieldRefInfo.java b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..6764edb21d --- /dev/null +++ b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/FieldRefInfo.java @@ -0,0 +1,54 @@ +package cn.xl.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/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/MethodRefInfo.java b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..0340d77b52 --- /dev/null +++ b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/MethodRefInfo.java @@ -0,0 +1,55 @@ +package cn.xl.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/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/NameAndTypeInfo.java b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..5a13ce1a38 --- /dev/null +++ b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,45 @@ +package cn.xl.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/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/NullConstantInfo.java b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..85b23e1862 --- /dev/null +++ b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/NullConstantInfo.java @@ -0,0 +1,13 @@ +package cn.xl.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo(){ + + } + @Override + public int getType() { + return -1; + } + +} diff --git a/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/StringInfo.java b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..df8c0586f2 --- /dev/null +++ b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/StringInfo.java @@ -0,0 +1,26 @@ +package cn.xl.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/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/UTF8Info.java b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..83ba9153cc --- /dev/null +++ b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/constant/UTF8Info.java @@ -0,0 +1,32 @@ +package cn.xl.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/group13/413007522/lesson05/src/main/java/cn/xl/jvm/loader/ByteCodeIterator.java b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..41ecfe5411 --- /dev/null +++ b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,83 @@ +package cn.xl.jvm.loader; + +import java.util.Arrays; + +import cn.xl.jvm.util.Util; + +public class ByteCodeIterator { + + private byte[] bt; + + private int size; + + public int pos = 0; + + public ByteCodeIterator(byte[] b){ + + if(b != null){ + this.bt = b; + this.size = b.length; + } + } + + public boolean hasNext(){ + if(pos < size){ + return true; + }else{ + return false; + } + } + + public Object next(){ + if(bt != null && pos < size){ + return bt[pos++]; + }else{ + return -1; + } + } + + public byte[] nextLenBytes(int len){ + + if(pos+len >= size){ + throw new ArrayIndexOutOfBoundsException(); + } + + byte[] b = Arrays.copyOfRange(bt, pos, pos+len); + pos = pos+len; + + return b; + } + + public int nextU1ToInt(){ + + return Util.byteToInt(new byte[]{bt[pos++]}); + } + + public int nextU2ToInt(){ + + return Util.byteToInt(new byte[]{bt[pos++],bt[pos++]}); + } + + public int nextU4ToInt(){ + + return Util.byteToInt(new byte[]{bt[pos++],bt[pos++],bt[pos++],bt[pos++]}); + } + + + public String nextU4ToHexString(){ + + return Util.byteToHexString(new byte[]{bt[pos++],bt[pos++],bt[pos++],bt[pos++]}); + } + + + public static void main(String[] args){ + + byte[] codes = new byte[]{1,2,3,4,5,6,7}; + + byte[] b = Arrays.copyOfRange(codes, 0, 3); + + for(int i = 0; i < b.length; i++){ + System.out.println(b[i]); + } + } +} diff --git a/group13/413007522/lesson05/src/main/java/cn/xl/jvm/loader/ClassFileLoader.java b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..4c3917a6ab --- /dev/null +++ b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/loader/ClassFileLoader.java @@ -0,0 +1,115 @@ +package cn.xl.jvm.loader; + +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 cn.xl.jvm.clz.ClassFile; + + + +public class ClassFileLoader { + + private List<String> clzPaths = new ArrayList<String>(); + + + 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; + } + + + public ClassFile loadClass(String className){ + + byte[] codes = readBinaryCode(className); + + ClassFileParser classFileParser = new ClassFileParser(); + ClassFile classFile = classFileParser.parse(codes); + + return classFile; + + } + + + + + private byte[] loadClassFile(String clzFileName){ + + try { + File f = new File(clzFileName); + + return IOUtils.toByteArray(new FileInputStream(f)); + } catch (FileNotFoundException e) { + e.printStackTrace(); + return null; + } catch (IOException e) { + e.printStackTrace(); + return null; + } + + /*InputStream in = null; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + // 一次读一个字节 + in = new FileInputStream(file); + int tempbyte; + while ((tempbyte = in.read()) != -1) { + baos.write(tempbyte); + } + in.close(); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + return baos.toByteArray(); */ + + } + + + + public void addClassPath(String path) { + if(this.clzPaths.contains(path)){ + return; + } + clzPaths.add(path); + } + + + + public String getClassPath(){ + /*StringBuffer sbf = new StringBuffer(); + if(clzPaths.size() >= 1){ + sbf.append(clzPaths.get(0)); + } + for(int i = 1; i < clzPaths.size(); i++){ + sbf.append(";"); + sbf.append(clzPaths.get(i)); + } + return sbf.toString(); + */ + + + return StringUtils.join(this.clzPaths, ";"); + + } + + + +} diff --git a/group13/413007522/lesson05/src/main/java/cn/xl/jvm/loader/ClassFileParser.java b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..4f34da4d86 --- /dev/null +++ b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/loader/ClassFileParser.java @@ -0,0 +1,126 @@ +package cn.xl.jvm.loader; + +import java.io.UnsupportedEncodingException; + +import cn.xl.jvm.clz.AccessFlag; +import cn.xl.jvm.clz.ClassFile; +import cn.xl.jvm.clz.ClassIndex; +import cn.xl.jvm.constant.ClassInfo; +import cn.xl.jvm.constant.ConstantPool; +import cn.xl.jvm.constant.FieldRefInfo; +import cn.xl.jvm.constant.MethodRefInfo; +import cn.xl.jvm.constant.NameAndTypeInfo; +import cn.xl.jvm.constant.NullConstantInfo; +import cn.xl.jvm.constant.StringInfo; +import cn.xl.jvm.constant.UTF8Info; + +public class ClassFileParser { + + public ClassFile parse(byte[] codes) { + + ClassFile classFile = new ClassFile(); + + ByteCodeIterator iter = new ByteCodeIterator(codes); + + if(!"cafebabe".equals(iter.nextU4ToHexString())){ + return null; + } + classFile.setMinorVersion(iter.nextU2ToInt()); + classFile.setMajorVersion(iter.nextU2ToInt()); + classFile.setAccessFlag(this.parseAccessFlag(iter)); + classFile.setClassIndex(this.parseClassIndex(iter)); + classFile.setConstPool(this.parseConstantPool(iter)); + + + return classFile; + } + + + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + + /*AccessFlag accessFlag = new AccessFlag(iter.nextU2ToInt()); + + return accessFlag;*/ + return null; + } + + private ClassIndex parseClassIndex(ByteCodeIterator iter) { + + return null; + + } + + private ConstantPool parseConstantPool(ByteCodeIterator iter) { + + int constantCount = iter.nextU2ToInt(); + System.out.println("constantPool count:"+constantCount); + + ConstantPool constantPool = new ConstantPool(); + constantPool.addConstantInfo(new NullConstantInfo()); + + for(int i = 0; i < constantCount; i++){ + int tag = iter.nextU1ToInt(); + if(tag == 7){ + + int utf8Index = iter.nextU2ToInt(); + ClassInfo classInfo = new ClassInfo(constantPool); + classInfo.setUtf8Index(utf8Index); + constantPool.addConstantInfo(classInfo); + }else if(tag == 1){ + + int length = iter.nextU2ToInt(); + UTF8Info utf8Info = new UTF8Info(constantPool); + utf8Info.setLength(length); + byte[] b = iter.nextLenBytes(length); + String strValue = null; + try { + strValue = new String(b,"UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + utf8Info.setValue(strValue); + constantPool.addConstantInfo(utf8Info); + }else if(tag == 8){ + + int index = iter.nextU2ToInt(); + StringInfo stringInfo = new StringInfo(constantPool); + stringInfo.setIndex(index); + constantPool.addConstantInfo(stringInfo); + }else if(tag == 9){ + + int classInfoindex = iter.nextU2ToInt(); + int nameTypeIndex = iter.nextU2ToInt(); + FieldRefInfo filedRefInfo = new FieldRefInfo(constantPool); + filedRefInfo.setClassInfoIndex(classInfoindex); + filedRefInfo.setNameAndTypeIndex(nameTypeIndex); + constantPool.addConstantInfo(filedRefInfo); + }else if(tag == 10){ + + int classInfoindex = iter.nextU2ToInt(); + int nameTypeIndex = iter.nextU2ToInt(); + MethodRefInfo methodRefInfo = new MethodRefInfo(constantPool); + methodRefInfo.setClassInfoIndex(classInfoindex); + methodRefInfo.setNameAndTypeIndex(nameTypeIndex); + constantPool.addConstantInfo(methodRefInfo); + }else if(tag == 12){ + + int nameIndex = iter.nextU2ToInt(); + int descIndex = iter.nextU2ToInt(); + NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(constantPool); + nameAndTypeInfo.setIndex1(nameIndex); + nameAndTypeInfo.setIndex2(descIndex); + constantPool.addConstantInfo(nameAndTypeInfo); + }else{ + //throw new RuntimeException("the constant Pool tag "+tag+" has not been implement yet!"); + } + + } + + return constantPool; + } + + + +} diff --git a/group13/413007522/lesson05/src/main/java/cn/xl/jvm/loader/EmployeeV1.java b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/loader/EmployeeV1.java new file mode 100644 index 0000000000..93642d6066 --- /dev/null +++ b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/loader/EmployeeV1.java @@ -0,0 +1,28 @@ +package cn.xl.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(); + + } +} \ No newline at end of file diff --git a/group13/413007522/lesson05/src/main/java/cn/xl/jvm/util/Util.java b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/util/Util.java new file mode 100644 index 0000000000..32e0200220 --- /dev/null +++ b/group13/413007522/lesson05/src/main/java/cn/xl/jvm/util/Util.java @@ -0,0 +1,43 @@ +package cn.xl.jvm.util; + +import java.math.BigDecimal; + +public class Util { + public static int byteToInt(byte[] codes){ + String s1 = byteToHexString(codes); + return Integer.valueOf(s1, 16).intValue(); + } + + public static BigDecimal byteToFloat(byte[] codes){ + String s1 = byteToHexString(codes); + int bits = Integer.valueOf(s1, 16).intValue(); + int s = ((bits >> 31) == 0) ? 1 : -1; + int e = ((bits >> 23) & 0xff); + int m =(e == 0) ?(bits & 0x7fffff) << 1 :(bits & 0x7fffff) | 0x800000; + + double f = Math.pow(2, e-150); + + BigDecimal bs = new BigDecimal(Double.toString(s)); + BigDecimal bm = new BigDecimal(Double.toString(m)); + BigDecimal bf = new BigDecimal(Double.toString(f)); + + return bs.multiply(bm).multiply(bf); + + + + } + + 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/group13/413007522/lesson05/src/test/java/jvm/loader/ByteCodeInteratorTest.java b/group13/413007522/lesson05/src/test/java/jvm/loader/ByteCodeInteratorTest.java new file mode 100644 index 0000000000..c38d4ce742 --- /dev/null +++ b/group13/413007522/lesson05/src/test/java/jvm/loader/ByteCodeInteratorTest.java @@ -0,0 +1,28 @@ +package jvm.loader; + +import org.junit.Test; + +import cn.xl.jvm.loader.ByteCodeIterator; + +public class ByteCodeInteratorTest { + + @Test + public void iter(){ + byte[] b = new byte[8]; + b[0] = 'C'; + b[1] = 'A'; + b[2] = 'F'; + b[3] = 'E'; + b[4] = 'B'; + b[5] = 'A'; + b[6] = 'B'; + b[7] = 'E'; + + ByteCodeIterator bcit = new ByteCodeIterator(b); + + while(bcit.hasNext()){ + System.out.println(bcit.next()); + } + + } +} diff --git a/group13/413007522/lesson05/src/test/java/jvm/loader/ClassFileloaderTest.java b/group13/413007522/lesson05/src/test/java/jvm/loader/ClassFileloaderTest.java new file mode 100644 index 0000000000..795d69e596 --- /dev/null +++ b/group13/413007522/lesson05/src/test/java/jvm/loader/ClassFileloaderTest.java @@ -0,0 +1,205 @@ +package jvm.loader; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import cn.xl.jvm.clz.ClassFile; +import cn.xl.jvm.clz.ClassIndex; +import cn.xl.jvm.constant.ClassInfo; +import cn.xl.jvm.constant.ConstantPool; +import cn.xl.jvm.constant.MethodRefInfo; +import cn.xl.jvm.constant.NameAndTypeInfo; +import cn.xl.jvm.constant.UTF8Info; +import cn.xl.jvm.loader.ClassFileLoader; +import cn.xl.jvm.loader.ClassFileParser; + + + + + + +public class ClassFileloaderTest { + + private static final String FULL_QUALIFIED_CLASS_NAME = "cn/xl/jvm/loader/EmployeeV1"; + + + static String path1 = "D:/trainingworkspace/lesson01/target/classes"; + static String path2 = "D://??"; + + static ClassFile clzFile = null; + static { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "cn.xl.jvm.loader.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 = "cn.xl.jvm.loader.EmployeeV1"; + + byte[] byteCodes = loader.readBinaryCode(className); + + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + Assert.assertEquals(1042, byteCodes.length); + + } + + + @Test + public void testMagicNumber(){ + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "cn.xl.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<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("<init>", 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());*/ + } + + +} From b83b1f9fdea74e270111247a4999cc9b3507eb92 Mon Sep 17 00:00:00 2001 From: GUK0 <1685605435@qq.com> Date: Mon, 10 Apr 2017 11:14:38 +0800 Subject: [PATCH 192/287] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=AC=AC6=E5=91=A8?= =?UTF-8?q?=E4=BD=9C=E4=B8=9A=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group12/247565311/week6/clz/AccessFlag.java | 25 +++ group12/247565311/week6/clz/ClassFile.java | 75 +++++++ group12/247565311/week6/clz/ClassIndex.java | 19 ++ .../247565311/week6/constant/ClassInfo.java | 24 +++ .../week6/constant/ConstantInfo.java | 29 +++ .../week6/constant/ConstantPool.java | 29 +++ .../week6/constant/FieldRefInfo.java | 54 +++++ .../week6/constant/MethodRefInfo.java | 55 +++++ .../week6/constant/NameAndTypeInfo.java | 45 ++++ .../week6/constant/NullConstantInfo.java | 13 ++ .../247565311/week6/constant/StringInfo.java | 26 +++ .../247565311/week6/constant/UTF8Info.java | 32 +++ .../week6/loader/ByteCodeIterator.java | 5 + .../week6/loader/ClassFileLoader.java | 136 ++++++++++++ .../week6/loader/ClassFileParser.java | 44 ++++ group12/247565311/week6/struts.java | 5 + .../week6/test/ClassFileloaderTest.java | 202 ++++++++++++++++++ group12/247565311/week6/test/EmployeeV1.java | 28 +++ group12/247565311/week6/util/Util.java | 24 +++ 19 files changed, 870 insertions(+) create mode 100644 group12/247565311/week6/clz/AccessFlag.java create mode 100644 group12/247565311/week6/clz/ClassFile.java create mode 100644 group12/247565311/week6/clz/ClassIndex.java create mode 100644 group12/247565311/week6/constant/ClassInfo.java create mode 100644 group12/247565311/week6/constant/ConstantInfo.java create mode 100644 group12/247565311/week6/constant/ConstantPool.java create mode 100644 group12/247565311/week6/constant/FieldRefInfo.java create mode 100644 group12/247565311/week6/constant/MethodRefInfo.java create mode 100644 group12/247565311/week6/constant/NameAndTypeInfo.java create mode 100644 group12/247565311/week6/constant/NullConstantInfo.java create mode 100644 group12/247565311/week6/constant/StringInfo.java create mode 100644 group12/247565311/week6/constant/UTF8Info.java create mode 100644 group12/247565311/week6/loader/ByteCodeIterator.java create mode 100644 group12/247565311/week6/loader/ClassFileLoader.java create mode 100644 group12/247565311/week6/loader/ClassFileParser.java create mode 100644 group12/247565311/week6/struts.java create mode 100644 group12/247565311/week6/test/ClassFileloaderTest.java create mode 100644 group12/247565311/week6/test/EmployeeV1.java create mode 100644 group12/247565311/week6/util/Util.java diff --git a/group12/247565311/week6/clz/AccessFlag.java b/group12/247565311/week6/clz/AccessFlag.java new file mode 100644 index 0000000000..e0296ad596 --- /dev/null +++ b/group12/247565311/week6/clz/AccessFlag.java @@ -0,0 +1,25 @@ +package week6.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/247565311/week6/clz/ClassFile.java b/group12/247565311/week6/clz/ClassFile.java new file mode 100644 index 0000000000..3ee6f00701 --- /dev/null +++ b/group12/247565311/week6/clz/ClassFile.java @@ -0,0 +1,75 @@ +package week6.clz; + +import week6.constant.ClassInfo; +import week6.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/247565311/week6/clz/ClassIndex.java b/group12/247565311/week6/clz/ClassIndex.java new file mode 100644 index 0000000000..5bf00fcc13 --- /dev/null +++ b/group12/247565311/week6/clz/ClassIndex.java @@ -0,0 +1,19 @@ +package week6.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/247565311/week6/constant/ClassInfo.java b/group12/247565311/week6/constant/ClassInfo.java new file mode 100644 index 0000000000..9320ae828c --- /dev/null +++ b/group12/247565311/week6/constant/ClassInfo.java @@ -0,0 +1,24 @@ +package week6.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/247565311/week6/constant/ConstantInfo.java b/group12/247565311/week6/constant/ConstantInfo.java new file mode 100644 index 0000000000..4eaebf241d --- /dev/null +++ b/group12/247565311/week6/constant/ConstantInfo.java @@ -0,0 +1,29 @@ +package week6.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/247565311/week6/constant/ConstantPool.java b/group12/247565311/week6/constant/ConstantPool.java new file mode 100644 index 0000000000..83c71e30a1 --- /dev/null +++ b/group12/247565311/week6/constant/ConstantPool.java @@ -0,0 +1,29 @@ +package week6.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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/247565311/week6/constant/FieldRefInfo.java b/group12/247565311/week6/constant/FieldRefInfo.java new file mode 100644 index 0000000000..0c96b0e537 --- /dev/null +++ b/group12/247565311/week6/constant/FieldRefInfo.java @@ -0,0 +1,54 @@ +package week6.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/247565311/week6/constant/MethodRefInfo.java b/group12/247565311/week6/constant/MethodRefInfo.java new file mode 100644 index 0000000000..75a4efdc98 --- /dev/null +++ b/group12/247565311/week6/constant/MethodRefInfo.java @@ -0,0 +1,55 @@ +package week6.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/247565311/week6/constant/NameAndTypeInfo.java b/group12/247565311/week6/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..404571f46a --- /dev/null +++ b/group12/247565311/week6/constant/NameAndTypeInfo.java @@ -0,0 +1,45 @@ +package week6.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/247565311/week6/constant/NullConstantInfo.java b/group12/247565311/week6/constant/NullConstantInfo.java new file mode 100644 index 0000000000..d7453d52e4 --- /dev/null +++ b/group12/247565311/week6/constant/NullConstantInfo.java @@ -0,0 +1,13 @@ +package week6.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo(){ + + } + @Override + public int getType() { + return -1; + } + +} diff --git a/group12/247565311/week6/constant/StringInfo.java b/group12/247565311/week6/constant/StringInfo.java new file mode 100644 index 0000000000..90fbf14752 --- /dev/null +++ b/group12/247565311/week6/constant/StringInfo.java @@ -0,0 +1,26 @@ +package week6.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/247565311/week6/constant/UTF8Info.java b/group12/247565311/week6/constant/UTF8Info.java new file mode 100644 index 0000000000..23ce5c011d --- /dev/null +++ b/group12/247565311/week6/constant/UTF8Info.java @@ -0,0 +1,32 @@ +package week6.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/247565311/week6/loader/ByteCodeIterator.java b/group12/247565311/week6/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..3c5efed8e1 --- /dev/null +++ b/group12/247565311/week6/loader/ByteCodeIterator.java @@ -0,0 +1,5 @@ +package week6.loader; + +public class ByteCodeIterator { + +} diff --git a/group12/247565311/week6/loader/ClassFileLoader.java b/group12/247565311/week6/loader/ClassFileLoader.java new file mode 100644 index 0000000000..2963ed821c --- /dev/null +++ b/group12/247565311/week6/loader/ClassFileLoader.java @@ -0,0 +1,136 @@ +package week6.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 week6.clz.ClassFile; + +public class ClassFileLoader { + + private List<String> clzPaths = new ArrayList<String>(); + + 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/group12/247565311/week6/loader/ClassFileParser.java b/group12/247565311/week6/loader/ClassFileParser.java new file mode 100644 index 0000000000..4062e68226 --- /dev/null +++ b/group12/247565311/week6/loader/ClassFileParser.java @@ -0,0 +1,44 @@ +package week6.loader; + +import java.io.UnsupportedEncodingException; + +import week6.clz.AccessFlag; +import week6.clz.ClassFile; +import week6.clz.ClassIndex; +import week6.constant.ClassInfo; +import week6.constant.ConstantPool; +import week6.constant.FieldRefInfo; +import week6.constant.MethodRefInfo; +import week6.constant.NameAndTypeInfo; +import week6.constant.NullConstantInfo; +import week6.constant.StringInfo; +import week6.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/group12/247565311/week6/struts.java b/group12/247565311/week6/struts.java new file mode 100644 index 0000000000..57126bc314 --- /dev/null +++ b/group12/247565311/week6/struts.java @@ -0,0 +1,5 @@ +package week6; + +public class struts { + +} diff --git a/group12/247565311/week6/test/ClassFileloaderTest.java b/group12/247565311/week6/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..492c48475e --- /dev/null +++ b/group12/247565311/week6/test/ClassFileloaderTest.java @@ -0,0 +1,202 @@ +package week6.test; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import week6.clz.ClassFile; +import week6.clz.ClassIndex; +import week6.constant.ClassInfo; +import week6.constant.ConstantPool; +import week6.constant.MethodRefInfo; +import week6.constant.NameAndTypeInfo; +import week6.constant.UTF8Info; +import week6.loader.ClassFileLoader; + + + + + +public class ClassFileloaderTest { + + + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + + static String path1 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\mini-jvm\\bin"; + static String path2 = "C:\temp"; + + static ClassFile clzFile = null; + static { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "week6.test.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 = "week6.test.EmployeeV1"; + + byte[] byteCodes = loader.readBinaryCode(className); + + // 娉ㄦ剰锛氳繖涓瓧鑺傛暟鍙兘鍜屼綘鐨凧VM鐗堟湰鏈夊叧绯伙紝 浣犲彲浠ョ湅鐪嬬紪璇戝ソ鐨勭被鍒板簳鏈夊澶� + Assert.assertEquals(1056, byteCodes.length); + + } + + + @Test + public void testMagicNumber(){ + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "week6.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(); + } + + /** + * ---------------------------------------------------------------------- + */ + + + @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("<init>", 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/247565311/week6/test/EmployeeV1.java b/group12/247565311/week6/test/EmployeeV1.java new file mode 100644 index 0000000000..ad2b054733 --- /dev/null +++ b/group12/247565311/week6/test/EmployeeV1.java @@ -0,0 +1,28 @@ +package week6.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/group12/247565311/week6/util/Util.java b/group12/247565311/week6/util/Util.java new file mode 100644 index 0000000000..7192b2473c --- /dev/null +++ b/group12/247565311/week6/util/Util.java @@ -0,0 +1,24 @@ +package week6.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 4627fd69f1a7928475d80d6ff91f3ff9b819b237 Mon Sep 17 00:00:00 2001 From: zhanglei <383117348@qq.com> Date: Mon, 10 Apr 2017 11:26:47 +0800 Subject: [PATCH 193/287] =?UTF-8?q?class=E6=96=87=E4=BB=B6=E8=A7=A3?= =?UTF-8?q?=E6=9E=90?= 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 | 43 ++++ .../jvm/loader/ClassFileParser.java | 100 +++++++++ .../jvm/test/ClassFileloaderTest.java | 198 ++++++++++++++---- .../com/coderising/jvm/test/EmployeeV1.java | 48 ++--- .../src/com/coderising/jvm/util/Util.java | 24 +++ 17 files changed, 776 insertions(+), 63 deletions(-) create mode 100644 group27/383117348/src/com/coderising/jvm/clz/AccessFlag.java create mode 100644 group27/383117348/src/com/coderising/jvm/clz/ClassFile.java create mode 100644 group27/383117348/src/com/coderising/jvm/clz/ClassIndex.java create mode 100644 group27/383117348/src/com/coderising/jvm/constant/ClassInfo.java create mode 100644 group27/383117348/src/com/coderising/jvm/constant/ConstantInfo.java create mode 100644 group27/383117348/src/com/coderising/jvm/constant/ConstantPool.java create mode 100644 group27/383117348/src/com/coderising/jvm/constant/FieldRefInfo.java create mode 100644 group27/383117348/src/com/coderising/jvm/constant/MethodRefInfo.java create mode 100644 group27/383117348/src/com/coderising/jvm/constant/NameAndTypeInfo.java create mode 100644 group27/383117348/src/com/coderising/jvm/constant/NullConstantInfo.java create mode 100644 group27/383117348/src/com/coderising/jvm/constant/StringInfo.java create mode 100644 group27/383117348/src/com/coderising/jvm/constant/UTF8Info.java create mode 100644 group27/383117348/src/com/coderising/jvm/loader/ByteCodeIterator.java create mode 100644 group27/383117348/src/com/coderising/jvm/loader/ClassFileParser.java create mode 100644 group27/383117348/src/com/coderising/jvm/util/Util.java diff --git a/group27/383117348/src/com/coderising/jvm/clz/AccessFlag.java b/group27/383117348/src/com/coderising/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..cdb8f8859a --- /dev/null +++ b/group27/383117348/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/383117348/src/com/coderising/jvm/clz/ClassFile.java b/group27/383117348/src/com/coderising/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..1b5a8b95a6 --- /dev/null +++ b/group27/383117348/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/383117348/src/com/coderising/jvm/clz/ClassIndex.java b/group27/383117348/src/com/coderising/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..df22981441 --- /dev/null +++ b/group27/383117348/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/383117348/src/com/coderising/jvm/constant/ClassInfo.java b/group27/383117348/src/com/coderising/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..e12b3e164e --- /dev/null +++ b/group27/383117348/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/383117348/src/com/coderising/jvm/constant/ConstantInfo.java b/group27/383117348/src/com/coderising/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..c8035ae876 --- /dev/null +++ b/group27/383117348/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/383117348/src/com/coderising/jvm/constant/ConstantPool.java b/group27/383117348/src/com/coderising/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..0e940b78d0 --- /dev/null +++ b/group27/383117348/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<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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/383117348/src/com/coderising/jvm/constant/FieldRefInfo.java b/group27/383117348/src/com/coderising/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..7ff9d5fb77 --- /dev/null +++ b/group27/383117348/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/383117348/src/com/coderising/jvm/constant/MethodRefInfo.java b/group27/383117348/src/com/coderising/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..0feffa65b5 --- /dev/null +++ b/group27/383117348/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/383117348/src/com/coderising/jvm/constant/NameAndTypeInfo.java b/group27/383117348/src/com/coderising/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..dcac7f97c4 --- /dev/null +++ b/group27/383117348/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/383117348/src/com/coderising/jvm/constant/NullConstantInfo.java b/group27/383117348/src/com/coderising/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..fa90d110fe --- /dev/null +++ b/group27/383117348/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/383117348/src/com/coderising/jvm/constant/StringInfo.java b/group27/383117348/src/com/coderising/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..d01065fd53 --- /dev/null +++ b/group27/383117348/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/383117348/src/com/coderising/jvm/constant/UTF8Info.java b/group27/383117348/src/com/coderising/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..b7407d146f --- /dev/null +++ b/group27/383117348/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/383117348/src/com/coderising/jvm/loader/ByteCodeIterator.java b/group27/383117348/src/com/coderising/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..44909a2f72 --- /dev/null +++ b/group27/383117348/src/com/coderising/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,43 @@ +package com.coderising.jvm.loader; + +import com.coderising.jvm.util.Util; + +public class ByteCodeIterator { + + private byte[] code = null; + private int pos = 0; + + public ByteCodeIterator(byte[] code){ + this.code = code; + } + + public int nextU1Int(){ + return Util.byteToInt(getByteBySize(1)); + } + + public int nextU2Int(){ + + return Util.byteToInt(getByteBySize(2)); + } + + public String nextU4HexString(){ + return Util.byteToHexString(getByteBySize(4)); + } + + public byte[] getByteByLength(int length){ + if(pos+length>code.length){ + throw new RuntimeException("长度超出字节数组最大长度"); + }else{ + byte[] by = getByteBySize(length); + return by; + } + } + + private byte[] getByteBySize(int size){ + byte[] by = new byte[size]; + for(int i=0;i<size;i++){ + by[i] = code[pos++]; + } + return by; + } +} diff --git a/group27/383117348/src/com/coderising/jvm/loader/ClassFileParser.java b/group27/383117348/src/com/coderising/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..292eb727de --- /dev/null +++ b/group27/383117348/src/com/coderising/jvm/loader/ClassFileParser.java @@ -0,0 +1,100 @@ +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) { + ByteCodeIterator by = new ByteCodeIterator(codes); + ClassFile file = new ClassFile(); + String magicNum = by.nextU4HexString(); + if(!magicNum.equals("cafebabe")){ + throw new RuntimeException("文件类型错误"); + } + + int minVersion = by.nextU2Int(); + int majorVersion = by.nextU2Int(); + + ConstantPool constant = parseConstantPool(by); + AccessFlag flag = parseAccessFlag(by); + ClassIndex index = parseClassIndex(by); + + file.setMinorVersion(minVersion); + file.setMajorVersion(majorVersion); + file.setAccessFlag(flag); + file.setClassIndex(index); + file.setConstPool(constant); + return file; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + AccessFlag flag = new AccessFlag(iter.nextU2Int()); + return flag; + } + + private ClassIndex parseClassIndex(ByteCodeIterator iter) { + ClassIndex index = new ClassIndex(); + index.setThisClassIndex(iter.nextU2Int()); + index.setSuperClassIndex(iter.nextU2Int()); + return index; + + } + + private ConstantPool parseConstantPool(ByteCodeIterator iter) { + int constantCount = iter.nextU2Int(); + ConstantPool pool = new ConstantPool(); + pool.addConstantInfo(new NullConstantInfo()); + for(int i=1;i<constantCount;i++){ + int tag = iter.nextU1Int(); + if(tag == 1){ + UTF8Info utf8 = new UTF8Info(pool); + int length = iter.nextU2Int(); + try { + utf8.setValue(new String(iter.getByteByLength(length),"utf-8")); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + pool.addConstantInfo(utf8); + }else if(tag == 7){ + ClassInfo classInfo = new ClassInfo(pool); + classInfo.setUtf8Index(iter.nextU2Int()); + pool.addConstantInfo(classInfo); + }else if(tag == 8){ + StringInfo stringInfo = new StringInfo(pool); + stringInfo.setIndex(iter.nextU2Int()); + pool.addConstantInfo(stringInfo); + }else if(tag ==9){ + FieldRefInfo fieldRefInfo = new FieldRefInfo(pool); + fieldRefInfo.setClassInfoIndex(iter.nextU2Int()); + fieldRefInfo.setNameAndTypeIndex(iter.nextU2Int()); + pool.addConstantInfo(fieldRefInfo); + }else if(tag == 10){ + MethodRefInfo methodRefInfo = new MethodRefInfo(pool); + methodRefInfo.setClassInfoIndex(iter.nextU2Int()); + methodRefInfo.setNameAndTypeIndex(iter.nextU2Int()); + pool.addConstantInfo(methodRefInfo); + }else if(tag == 12){ + NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(pool); + nameAndTypeInfo.setIndex1(iter.nextU2Int()); + nameAndTypeInfo.setIndex2(iter.nextU2Int()); + pool.addConstantInfo(nameAndTypeInfo); + } + } + return pool; + } + + +} diff --git a/group27/383117348/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group27/383117348/src/com/coderising/jvm/test/ClassFileloaderTest.java index 33229dccb2..ff026ee819 100644 --- a/group27/383117348/src/com/coderising/jvm/test/ClassFileloaderTest.java +++ b/group27/383117348/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -1,76 +1,198 @@ package com.coderising.jvm.test; import org.junit.After; -import org.junit.Assert; +import org.junit.Assert; 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; public class ClassFileloaderTest { + + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + static String path1 = "E:\\MyGit\\coding2017\\group27\\383117348\\bin"; - static String path2 = "C:\\temp"; + 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 { + public void setUp() throws Exception { } @After public void tearDown() throws Exception { } - + @Test - public void testClassPath() { - + public void testClassPath(){ + ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); loader.addClassPath(path2); - + String clzPath = loader.getClassPath(); - System.out.println(clzPath); - Assert.assertEquals(path1 + ";" + path2, clzPath); - + + Assert.assertEquals(path1+";"+path2,clzPath); + } - + @Test - public void testClassFileLength() { - + 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(); + + + @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] }; - + 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); + + + + 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()); } - return buffer.toString(); - } - -} \ No newline at end of file + { + 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("<init>", 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/383117348/src/com/coderising/jvm/test/EmployeeV1.java b/group27/383117348/src/com/coderising/jvm/test/EmployeeV1.java index d36b122f60..9a36573dd3 100644 --- a/group27/383117348/src/com/coderising/jvm/test/EmployeeV1.java +++ b/group27/383117348/src/com/coderising/jvm/test/EmployeeV1.java @@ -1,30 +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(); - - } + 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/group27/383117348/src/com/coderising/jvm/util/Util.java b/group27/383117348/src/com/coderising/jvm/util/Util.java new file mode 100644 index 0000000000..176f70d002 --- /dev/null +++ b/group27/383117348/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<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 434304164c0114f59ba866e0390cbbf50ba8c99b Mon Sep 17 00:00:00 2001 From: zhanglei <383117348@qq.com> Date: Mon, 10 Apr 2017 12:09:35 +0800 Subject: [PATCH 194/287] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86=E5=B8=B8?= =?UTF-8?q?=E9=87=8F=E6=B1=A0=E4=B8=ADInteger=E5=92=8CFloat=E5=B8=B8?= =?UTF-8?q?=E9=87=8F=E7=9A=84=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coderising/jvm/constant/ConstantInfo.java | 1 + .../coderising/jvm/constant/FloatInfo.java | 26 +++++++++++++++++ .../coderising/jvm/constant/IntegerInfo.java | 28 +++++++++++++++++++ .../jvm/loader/ByteCodeIterator.java | 8 ++++++ .../jvm/loader/ClassFileParser.java | 10 +++++++ .../src/com/coderising/jvm/util/Util.java | 5 ++++ 6 files changed, 78 insertions(+) create mode 100644 group27/383117348/src/com/coderising/jvm/constant/FloatInfo.java create mode 100644 group27/383117348/src/com/coderising/jvm/constant/IntegerInfo.java diff --git a/group27/383117348/src/com/coderising/jvm/constant/ConstantInfo.java b/group27/383117348/src/com/coderising/jvm/constant/ConstantInfo.java index c8035ae876..a3a0b53b76 100644 --- a/group27/383117348/src/com/coderising/jvm/constant/ConstantInfo.java +++ b/group27/383117348/src/com/coderising/jvm/constant/ConstantInfo.java @@ -2,6 +2,7 @@ public abstract class ConstantInfo { public static final int UTF8_INFO = 1; + public static final int INTEGER_INFO = 3; public static final int FLOAT_INFO = 4; public static final int CLASS_INFO = 7; public static final int STRING_INFO = 8; diff --git a/group27/383117348/src/com/coderising/jvm/constant/FloatInfo.java b/group27/383117348/src/com/coderising/jvm/constant/FloatInfo.java new file mode 100644 index 0000000000..dc3765720c --- /dev/null +++ b/group27/383117348/src/com/coderising/jvm/constant/FloatInfo.java @@ -0,0 +1,26 @@ +package com.coderising.jvm.constant; + + +public class FloatInfo extends ConstantInfo{ + private int type = ConstantInfo.FLOAT_INFO; + + private float value; + + public FloatInfo(ConstantPool pool){ + super(pool); + } + + @Override + public int getType() { + // TODO Auto-generated method stub + return type; + } + + public float getValue() { + return value; + } + + public void setValue(float value) { + this.value = value; + } +} diff --git a/group27/383117348/src/com/coderising/jvm/constant/IntegerInfo.java b/group27/383117348/src/com/coderising/jvm/constant/IntegerInfo.java new file mode 100644 index 0000000000..06e66c6e08 --- /dev/null +++ b/group27/383117348/src/com/coderising/jvm/constant/IntegerInfo.java @@ -0,0 +1,28 @@ +package com.coderising.jvm.constant; + +public class IntegerInfo extends ConstantInfo { + + private int type = ConstantInfo.INTEGER_INFO; + + private int value; + + public IntegerInfo(ConstantPool pool) { + super(pool); + } + + @Override + public int getType() { + + return type; + } + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + +} diff --git a/group27/383117348/src/com/coderising/jvm/loader/ByteCodeIterator.java b/group27/383117348/src/com/coderising/jvm/loader/ByteCodeIterator.java index 44909a2f72..2688ae5810 100644 --- a/group27/383117348/src/com/coderising/jvm/loader/ByteCodeIterator.java +++ b/group27/383117348/src/com/coderising/jvm/loader/ByteCodeIterator.java @@ -24,6 +24,14 @@ public String nextU4HexString(){ return Util.byteToHexString(getByteBySize(4)); } + public float nextU4Float(){ + return Util.byteToFloat(getByteBySize(4)); + } + + public int nextU4Integer(){ + return Util.byteToInt(getByteBySize(4)); + } + public byte[] getByteByLength(int length){ if(pos+length>code.length){ throw new RuntimeException("长度超出字节数组最大长度"); diff --git a/group27/383117348/src/com/coderising/jvm/loader/ClassFileParser.java b/group27/383117348/src/com/coderising/jvm/loader/ClassFileParser.java index 292eb727de..209ee78d36 100644 --- a/group27/383117348/src/com/coderising/jvm/loader/ClassFileParser.java +++ b/group27/383117348/src/com/coderising/jvm/loader/ClassFileParser.java @@ -8,6 +8,8 @@ import com.coderising.jvm.constant.ClassInfo; import com.coderising.jvm.constant.ConstantPool; import com.coderising.jvm.constant.FieldRefInfo; +import com.coderising.jvm.constant.FloatInfo; +import com.coderising.jvm.constant.IntegerInfo; import com.coderising.jvm.constant.MethodRefInfo; import com.coderising.jvm.constant.NameAndTypeInfo; import com.coderising.jvm.constant.NullConstantInfo; @@ -68,6 +70,14 @@ private ConstantPool parseConstantPool(ByteCodeIterator iter) { e.printStackTrace(); } pool.addConstantInfo(utf8); + }else if(tag == 3){ + IntegerInfo integer = new IntegerInfo(pool); + integer.setValue(iter.nextU4Integer()); + pool.addConstantInfo(integer); + }else if(tag == 4){ + FloatInfo floatInfo = new FloatInfo(pool); + floatInfo.setValue(iter.nextU4Float()); + pool.addConstantInfo(floatInfo); }else if(tag == 7){ ClassInfo classInfo = new ClassInfo(pool); classInfo.setUtf8Index(iter.nextU2Int()); diff --git a/group27/383117348/src/com/coderising/jvm/util/Util.java b/group27/383117348/src/com/coderising/jvm/util/Util.java index 176f70d002..0038d09530 100644 --- a/group27/383117348/src/com/coderising/jvm/util/Util.java +++ b/group27/383117348/src/com/coderising/jvm/util/Util.java @@ -21,4 +21,9 @@ public static String byteToHexString(byte[] codes ){ } return buffer.toString(); } + + public static float byteToFloat(byte[] codes){ + String s1 = byteToHexString(codes); + return Float.valueOf(s1).floatValue(); + } } From dcc31ffae8fc9ac114c2a3c78940091718bdac40 Mon Sep 17 00:00:00 2001 From: onlyliuxin <14703250@qq.com> Date: Mon, 10 Apr 2017 14:49:58 +0800 Subject: [PATCH 195/287] =?UTF-8?q?=E5=AE=9E=E7=8E=B0StackUtil=E5=92=8CSta?= =?UTF-8?q?ckUtilTest?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/com/coding/basic/stack/StackUtil.java | 105 ++++++++++++++++-- .../com/coding/basic/stack/StackUtilTest.java | 78 +++++++++++++ 2 files changed, 176 insertions(+), 7 deletions(-) create mode 100644 liuxin/data-structure/src/com/coding/basic/stack/StackUtilTest.java diff --git a/liuxin/data-structure/src/com/coding/basic/stack/StackUtil.java b/liuxin/data-structure/src/com/coding/basic/stack/StackUtil.java index 434d991447..d4c496a2f9 100644 --- a/liuxin/data-structure/src/com/coding/basic/stack/StackUtil.java +++ b/liuxin/data-structure/src/com/coding/basic/stack/StackUtil.java @@ -1,23 +1,65 @@ package com.coding.basic.stack; - +import java.util.Stack; public class StackUtil { + public static void bad_reverse(Stack<Integer> s) { + if(s == null || s.isEmpty()){ + return; + } + Stack<Integer> tmpStack = new Stack(); + while(!s.isEmpty()){ + tmpStack.push(s.pop()); + } + + s = tmpStack; + + } /** * 假设栈中的元素是Integer, 从栈顶到栈底是 : 5,4,3,2,1 调用该方法后, 元素次序变为: 1,2,3,4,5 * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 */ - public static void reverse(Stack s) { - + public static void reverse(Stack<Integer> s) { + if(s == null || s.isEmpty()){ + return; + } + Integer top = s.pop(); + reverse(s); + addToBottom(s,top); + + + } + public static void addToBottom(Stack<Integer> s, Integer value){ + if(s.isEmpty()){ + s.push(value); + } else{ + Integer top = s.pop(); + addToBottom(s,value); + s.push(top); + } + } - /** * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 * * @param o */ public static void remove(Stack s,Object o) { - + if(s == null || s.isEmpty()){ + return; + } + Stack tmpStack = new Stack(); + + while(!s.isEmpty()){ + Object value = s.pop(); + if(!value.equals(o)){ + tmpStack.push(value); + } + } + + while(!tmpStack.isEmpty()){ + s.push(tmpStack.pop()); + } } /** @@ -27,7 +69,24 @@ public static void remove(Stack s,Object o) { * @return */ public static Object[] getTop(Stack s,int len) { - return null; + + if(s == null || s.isEmpty() || s.size()<len || len <=0 ){ + return null; + } + + Stack tmpStack = new Stack(); + int i = 0; + Object[] result = new Object[len]; + while(!s.isEmpty()){ + Object value = s.pop(); + tmpStack.push(value); + result[i++] = value; + if(i == len){ + break; + } + } + + return result; } /** * 字符串s 可能包含这些字符: ( ) [ ] { }, a,b,c... x,yz @@ -38,7 +97,39 @@ public static Object[] getTop(Stack s,int len) { * @return */ public static boolean isValidPairs(String s){ - return false; + + Stack<Character> stack = new Stack(); + for(int i=0;i<s.length();i++){ + char c = s.charAt(i); + + if(c == '(' || c =='[' || c == '{'){ + + stack.push(c); + + } else if( c == ')'){ + + char topChar = stack.pop(); + if(topChar != '('){ + return false; + } + + } else if( c == ']'){ + + char topChar = stack.pop(); + if(topChar != '['){ + return false; + } + + } else if( c == '}'){ + + char topChar = stack.pop(); + if(topChar != '{'){ + return false; + } + + } + } + return stack.size() == 0; } diff --git a/liuxin/data-structure/src/com/coding/basic/stack/StackUtilTest.java b/liuxin/data-structure/src/com/coding/basic/stack/StackUtilTest.java new file mode 100644 index 0000000000..766c7eeb29 --- /dev/null +++ b/liuxin/data-structure/src/com/coding/basic/stack/StackUtilTest.java @@ -0,0 +1,78 @@ +package com.coding.basic.stack; + +import static org.junit.Assert.fail; + +import java.util.Stack; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +public class StackUtilTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testAddToBottom() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + + StackUtil.addToBottom(s, 0); + + Assert.assertEquals("[0, 1, 2, 3]", s.toString()); + + } + @Test + public void testReverse() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + Assert.assertEquals("[1, 2, 3, 4, 5]", s.toString()); + StackUtil.reverse(s); + Assert.assertEquals("[5, 4, 3, 2, 1]", s.toString()); + } + + @Test + public void testRemove() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + StackUtil.remove(s, 2); + Assert.assertEquals("[1, 3]", s.toString()); + } + + @Test + public void testGetTop() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + { + Object[] values = StackUtil.getTop(s, 3); + Assert.assertEquals(5, values[0]); + Assert.assertEquals(4, values[1]); + Assert.assertEquals(3, values[2]); + } + } + + @Test + public void testIsValidPairs() { + Assert.assertTrue(StackUtil.isValidPairs("([e{d}f])")); + Assert.assertFalse(StackUtil.isValidPairs("([b{x]y})")); + } + +} From e554b99b4c1742c5a607380c6260ce379858d582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BE=9A=E5=90=AF=E7=9B=BC?= <gongqipan@qipeipu.com> Date: Mon, 10 Apr 2017 16:35:22 +0800 Subject: [PATCH 196/287] =?UTF-8?q?=E9=87=8D=E6=96=B0=E6=90=AD=E5=BB=BA?= =?UTF-8?q?=E4=BD=9C=E4=B8=9A=E9=A1=B9=E7=9B=AE=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group11/252308879/README.md | 29 ++ .../main/java/com/pan/week01/Iterator.java | 12 + .../main/java/com/pan/week02/ArrayUtil.java | 282 ++++++++++++++++++ 3 files changed, 323 insertions(+) create mode 100644 group11/252308879/README.md create mode 100644 group11/252308879/data-structure/src/main/java/com/pan/week01/Iterator.java create mode 100644 group11/252308879/data-structure/src/main/java/com/pan/week02/ArrayUtil.java diff --git a/group11/252308879/README.md b/group11/252308879/README.md new file mode 100644 index 0000000000..99f5dc58e0 --- /dev/null +++ b/group11/252308879/README.md @@ -0,0 +1,29 @@ +Coding2017 项目 +=== + +## 简介 + +* 考虑到目前的项目目录比较凌乱,所以整理一下目录。目前还未整理完成。 + +* 该项目主要是个人的日常作业,包含三大部分(后续会更多): + * 前三周的打基础(计算机系统知识) + * 数据结构 + * mini-jvm + +--- + +## 目录 + +[TOC] + +--- + +## 正文 + +* data-structure 项目中主要包含前三周的作业 + * 基本的数据结构 + * 解析struts.xml + * 多线程下载 +* mini-jvm 项目中主要包含解析jvm的作业 + +* 在目前这两个大模块中,都包含了每周的数据结构练习 diff --git a/group11/252308879/data-structure/src/main/java/com/pan/week01/Iterator.java b/group11/252308879/data-structure/src/main/java/com/pan/week01/Iterator.java new file mode 100644 index 0000000000..b59719cd2b --- /dev/null +++ b/group11/252308879/data-structure/src/main/java/com/pan/week01/Iterator.java @@ -0,0 +1,12 @@ +package com.pan.week01; + +/** + * Created by QiPan on 2017/2/23. + */ +public interface Iterator { + boolean hasNext(); + + Object next(); + + void remove(); +} diff --git a/group11/252308879/data-structure/src/main/java/com/pan/week02/ArrayUtil.java b/group11/252308879/data-structure/src/main/java/com/pan/week02/ArrayUtil.java new file mode 100644 index 0000000000..e835e31269 --- /dev/null +++ b/group11/252308879/data-structure/src/main/java/com/pan/week02/ArrayUtil.java @@ -0,0 +1,282 @@ +package com.pan.week02; + +import java.util.Arrays; + +/** + * Created by QiPan on 2017/2/27. + */ +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) { + + // 如果是null, 或者长度小于等于1, 直接返回 + if (origin == null || origin.length <= 1) { + return; + } + for (int i = 0; i < origin.length / 2; i++) { + int tmp = origin[i]; + origin[i] = origin[origin.length - 1 - i]; + origin[origin.length - 1 - i] = tmp; + } + } + + /** + * 现在有如下的一个数组: 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 oldArray; + } + int[] newArray = null; + int count = 0; //统计被移出的数组的个数 + for (int i = 0; i < oldArray.length; i++) { + int num = oldArray[i]; + if (num == 0) { + count++; + System.arraycopy(oldArray, i + 1, oldArray, i, oldArray.length - i - 1); + i--; + } + } + if (count == 0) { + newArray = oldArray; + } else { + newArray = new int[oldArray.length - count]; + System.arraycopy(oldArray, 0, newArray, 0, oldArray.length - count); + } + return newArray; + } + + /** + * 不用JavaAPI来做 + * + * @param oldArray + * @return + */ + public static int[] removeZero_2(int[] oldArray) { + + if (oldArray == null) { + return oldArray; + } + int count = 0; + for (int num : oldArray) { + if (num == 0) { + count++; + } + } + int[] newArray = new int[oldArray.length - count]; + for (int i = 0, j = 0; i < oldArray.length; i++, j++) { + int num = oldArray[i]; + if (num == 0) { + j--; + } else { + newArray[j] = num; + } + } + 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) { + //先初始化一个array3,但不是最后返回的数组 + int[] array3 = new int[array1.length + array2.length]; + int i = 0, j = 0; + int array3Size = 0; // 统计实际上合并数组后的大小 + while (i < array1.length && j < array2.length) { + if (array1[i] < array2[j]) {// 如果array1中元素小,则插入到array3中 + array3[array3Size++] = array1[i]; + ++i; + } else if (array1[i] > array2[j]) {//如果array2中元素小,则插入到array3中 + array3[array3Size++] = array2[j]; + ++j; + } else {//否则随便插入一个,但是计数要同时加1 + array3[array3Size++] = array1[i]; + ++i; + ++j; + } + } + + if (i == array1.length) { //如果array1中全部循环完毕了,那么需要去处理array2中剩余的元素 + for (int n = j; n < array2.length; n++) { + array3[array3Size++] = array2[n]; + } + } else if (j == array2.length) {// 如果array2中全部循环完毕,那么需要去处理array1中剩余的元素 + for (int n = i; n < array1.length; n++) { + array3[array3Size++] = array1[n]; + } + } + int[] returnResultArray = new int[array3Size]; + System.arraycopy(array3, 0, returnResultArray, 0, + array3Size); + return returnResultArray; + } + + /** + * 把一个已经存满数据的数组 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 (oldArray == null) { + oldArray = new int[size]; + } + oldArray = Arrays.copyOf(oldArray, oldArray.length + size); + return oldArray; + } + + /** + * 斐波那契数列为: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]; + } + int[] arrays = new int[max / 2]; + int firstNum = 1; //第一个数字 + int secondNum = 1; // 第二个数字 + int arraySize = 0; + arrays[arraySize++] = 1; // 初始化第一位 + while (secondNum < max) { + arrays[arraySize++] = secondNum; + int tmpNum = secondNum; // 保存第二个数,得会需要付给第一个数 + secondNum = firstNum + secondNum; // 为前两个数之和 + firstNum = tmpNum; // 第一个数,后移 + } + return Arrays.copyOf(arrays, arraySize); + } + + /** + * 返回小于给定最大值max的所有素数数组 + * 例如max = 23, 返回的数组为[2,3,5,7,11,13,17,19] + * + * @param max + * @return + */ + public static int[] getPrimes(int max) { + int[] returnResultArray = new int[max + 1]; + int arraySize = 0; + for (int i = 2; i < max; i++) { + if (isPrime(i)) { + returnResultArray[arraySize++] = i; + } + + } + if (arraySize == returnResultArray.length) { + return returnResultArray; + } + return Arrays.copyOf(returnResultArray, arraySize); + } + + private static boolean isPrime(final int number) { + if (number < 2) { + return false; + } + // 因为不可能将一个数除与所有小于它的数字,只要检查到N的平方根就好了。 + // 但直接开根号还有个精度的问题。这个可能会产生误差。 索性将判断条件写成 i*i<=number + for (int i = 2; i * i <= number; i++) { + if (number % i == 0) {//查看所有小于number平方根的数,能够被整除 + return false; + } + } + // 如果一个都没有,那么就是素数 + return true; + } + + /** + * 所谓“完数”, 是指这个数恰好等于它的因子之和,例如6=1+2+3 + * 给定一个最大值max, 返回一个数组, 数组中是小于max 的所有完数 + * + * @param max + * @return + */ + public static int[] getPerfectNumbers(int max) { + int[] array = new int[max]; + int arraySize = 0; + for (int n = 0; n < max; n++) { + int fac,// 被除的因子 + sum,// 用来统计因子之和 + num;// 除数的因子,中间变量 + for (sum = 1, num = n, fac = 2; fac < num; fac++) { + + if (n % fac == 0) {// 如果余数为0,那么说明有因子 + sum += fac; // 统计因子和 + num = n / fac; // num=等于除数的最大因子 + if (num == fac) // 如果最大和最小相等跳出循环 + break; + sum += num; // 再统计因子 + } + } + + if (sum == n) { //因子和与整数相等,那么就是一个完美数 + if (n != 1) { + System.out.println(n + "是一个完全数,其因子为:"); + } + for (fac = 1; fac < n; fac++) { + if (n % fac == 0) {// 列出所有的因子 + System.out.print(fac + " "); + } + } + System.out.println(); + array[arraySize++] = n; // 放到数组中 + } + } + return Arrays.copyOf(array, arraySize); + } + + /** + * 用seperator 把数组 array给连接起来 + * 例如array= [3,8,9], seperator = "-" + * 则返回值为"3-8-9" + * + * @param array + * @param seperator + * @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]); + continue; + } + str.append(array[i]).append(seperator); + } + return str.toString(); + } + +} From 7d692349b71aaa579e681088a9ebb5e58dd28acb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BE=9A=E5=90=AF=E7=9B=BC?= <gongqipan@qipeipu.com> Date: Mon, 10 Apr 2017 16:55:13 +0800 Subject: [PATCH 197/287] init mini-jvm --- .../main/java/com/pan/alg/LRUPageFrame.java | 133 ++++++++++++++++++ .../java/com/pan/jvm/ClassFileLoader.java | 49 +++++++ .../main/java/com/pan/jvm/clz/AccessFlag.java | 26 ++++ .../main/java/com/pan/jvm/clz/ClassFile.java | 82 +++++++++++ .../main/java/com/pan/jvm/clz/ClassIndex.java | 22 +++ .../java/com/pan/jvm/constant/ClassInfo.java | 28 ++++ .../com/pan/jvm/constant/ConstantInfo.java | 31 ++++ .../com/pan/jvm/constant/ConstantPool.java | 32 +++++ .../com/pan/jvm/constant/FieldRefInfo.java | 58 ++++++++ .../com/pan/jvm/constant/MethodRefInfo.java | 58 ++++++++ .../com/pan/jvm/constant/NameAndTypeInfo.java | 49 +++++++ .../pan/jvm/constant/NullConstantInfo.java | 14 ++ .../java/com/pan/jvm/constant/StringInfo.java | 28 ++++ .../java/com/pan/jvm/constant/UTF8Info.java | 38 +++++ .../com/pan/jvm/loader/ByteCodeIterator.java | 5 + .../com/pan/jvm/loader/ClassFileLoader.java | 130 +++++++++++++++++ .../com/pan/jvm/loader/ClassFileParser.java | 33 +++++ .../src/main/java/com/pan/jvm/util/Util.java | 23 +++ .../test/java/com/pan/jvm/TestReadCFBB.java | 10 ++ 19 files changed, 849 insertions(+) create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/alg/LRUPageFrame.java create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/jvm/ClassFileLoader.java create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/AccessFlag.java create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/ClassFile.java create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/ClassIndex.java create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/ClassInfo.java create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/ConstantInfo.java create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/ConstantPool.java create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/FieldRefInfo.java create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/MethodRefInfo.java create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/NameAndTypeInfo.java create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/NullConstantInfo.java create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/StringInfo.java create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/UTF8Info.java create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ByteCodeIterator.java create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileLoader.java create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileParser.java create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/jvm/util/Util.java create mode 100644 group11/252308879/mini-jvm/src/test/java/com/pan/jvm/TestReadCFBB.java diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/alg/LRUPageFrame.java b/group11/252308879/mini-jvm/src/main/java/com/pan/alg/LRUPageFrame.java new file mode 100644 index 0000000000..d9455d3807 --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/alg/LRUPageFrame.java @@ -0,0 +1,133 @@ +package com.pan.alg; + + +/* + * 用双向链表实现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/252308879/mini-jvm/src/main/java/com/pan/jvm/ClassFileLoader.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/ClassFileLoader.java new file mode 100644 index 0000000000..0961c5ddd5 --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/ClassFileLoader.java @@ -0,0 +1,49 @@ +package com.pan.jvm; + +import java.io.BufferedInputStream; +import java.io.DataInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class ClassFileLoader { + private List<String> clzPaths = new ArrayList<String>(); + 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/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/AccessFlag.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..8c253df200 --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/AccessFlag.java @@ -0,0 +1,26 @@ +package com.pan.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/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/ClassFile.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..a192ad0c82 --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/ClassFile.java @@ -0,0 +1,82 @@ +package com.pan.jvm.clz; + + +import com.pan.jvm.constant.ClassInfo; +import com.pan.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/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/ClassIndex.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..563592ac47 --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/ClassIndex.java @@ -0,0 +1,22 @@ +package com.pan.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/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/ClassInfo.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..b842755586 --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/ClassInfo.java @@ -0,0 +1,28 @@ +package com.pan.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/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/ConstantInfo.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..464e44a79d --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/ConstantInfo.java @@ -0,0 +1,31 @@ +package com.pan.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/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/ConstantPool.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..c2da2637c5 --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/ConstantPool.java @@ -0,0 +1,32 @@ +package com.pan.jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/FieldRefInfo.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..2aaced31d3 --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/FieldRefInfo.java @@ -0,0 +1,58 @@ +package com.pan.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/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/MethodRefInfo.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..a3e6f969b0 --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/MethodRefInfo.java @@ -0,0 +1,58 @@ +package com.pan.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/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/NameAndTypeInfo.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..30be83ef3a --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,49 @@ +package com.pan.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/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/NullConstantInfo.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..cc6989bef7 --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/NullConstantInfo.java @@ -0,0 +1,14 @@ +package com.pan.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo() { + + } + + @Override + public int getType() { + return -1; + } + +} diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/StringInfo.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..ad3f397949 --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/StringInfo.java @@ -0,0 +1,28 @@ +package com.pan.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/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/UTF8Info.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..502adae968 --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/constant/UTF8Info.java @@ -0,0 +1,38 @@ +package com.pan.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/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ByteCodeIterator.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..f808720ef9 --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,5 @@ +package com.pan.jvm.loader; + +public class ByteCodeIterator { + +} diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileLoader.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..1418fa9b83 --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileLoader.java @@ -0,0 +1,130 @@ +package com.pan.jvm.loader; + +import com.pan.jvm.clz.ClassFile; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; + +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 { + + private List<String> clzPaths = new ArrayList<String>(); + + 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/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileParser.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..d2ba152e05 --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileParser.java @@ -0,0 +1,33 @@ +package com.pan.jvm.loader; + +import com.pan.jvm.clz.AccessFlag; +import com.pan.jvm.clz.ClassFile; +import com.pan.jvm.clz.ClassIndex; +import com.pan.jvm.constant.ConstantPool; + +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/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/util/Util.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/util/Util.java new file mode 100644 index 0000000000..ae130b4183 --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/util/Util.java @@ -0,0 +1,23 @@ +package com.pan.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/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/TestReadCFBB.java b/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/TestReadCFBB.java new file mode 100644 index 0000000000..5523fa7696 --- /dev/null +++ b/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/TestReadCFBB.java @@ -0,0 +1,10 @@ +package com.pan.jvm; + +/** + * 用于测试第一次JVM作业,读取.class作业 和 魔幻数字 + */ +public class TestReadCFBB { + + + +} From ae1dada92d2c3b7705203f88e400179066b8997d Mon Sep 17 00:00:00 2001 From: "wangxg922@chinaunincom.cn" <996108220@qq.com> Date: Mon, 10 Apr 2017 17:45:55 +0800 Subject: [PATCH 198/287] =?UTF-8?q?Signed-off-by:=20=E7=AC=AC=E4=BA=8C?= =?UTF-8?q?=E6=AC=A1jvm<996108220@qq.com>?= 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 | 74 ++++++++++ .../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 | 51 +++++++ .../jvm/loader/ClassFileLoader.java | 34 ++++- .../jvm/loader/ClassFileParser.java | 111 ++++++++++++++ .../jvm/test/ClassFileloaderTest.java | 138 ++++++++++++++++-- .../src/com/coderising/jvm/util/Util.java | 33 +++++ .../src/com/coding/basic/ArrayList.java | 6 +- .../996108220/src/com/coding/basic/Stack.java | 24 --- .../src/com/coding/basic/stack/Stack.java | 40 +++++ .../src/com/coding/basic/stack/StackUtil.java | 131 +++++++++++++++++ .../com/coding/basic/stack/StackUtilTest.java | 82 +++++++++++ 22 files changed, 1027 insertions(+), 48 deletions(-) create mode 100644 group11/996108220/src/com/coderising/jvm/clz/AccessFlag.java create mode 100644 group11/996108220/src/com/coderising/jvm/clz/ClassFile.java create mode 100644 group11/996108220/src/com/coderising/jvm/clz/ClassIndex.java create mode 100644 group11/996108220/src/com/coderising/jvm/constant/ClassInfo.java create mode 100644 group11/996108220/src/com/coderising/jvm/constant/ConstantInfo.java create mode 100644 group11/996108220/src/com/coderising/jvm/constant/ConstantPool.java create mode 100644 group11/996108220/src/com/coderising/jvm/constant/FieldRefInfo.java create mode 100644 group11/996108220/src/com/coderising/jvm/constant/MethodRefInfo.java create mode 100644 group11/996108220/src/com/coderising/jvm/constant/NameAndTypeInfo.java create mode 100644 group11/996108220/src/com/coderising/jvm/constant/NullConstantInfo.java create mode 100644 group11/996108220/src/com/coderising/jvm/constant/StringInfo.java create mode 100644 group11/996108220/src/com/coderising/jvm/constant/UTF8Info.java create mode 100644 group11/996108220/src/com/coderising/jvm/loader/ByteCodeIterator.java create mode 100644 group11/996108220/src/com/coderising/jvm/loader/ClassFileParser.java create mode 100644 group11/996108220/src/com/coderising/jvm/util/Util.java delete mode 100644 group11/996108220/src/com/coding/basic/Stack.java create mode 100644 group11/996108220/src/com/coding/basic/stack/Stack.java create mode 100644 group11/996108220/src/com/coding/basic/stack/StackUtil.java create mode 100644 group11/996108220/src/com/coding/basic/stack/StackUtilTest.java diff --git a/group11/996108220/src/com/coderising/jvm/clz/AccessFlag.java b/group11/996108220/src/com/coderising/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..faae056835 --- /dev/null +++ b/group11/996108220/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/group11/996108220/src/com/coderising/jvm/clz/ClassFile.java b/group11/996108220/src/com/coderising/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..8575f5641a --- /dev/null +++ b/group11/996108220/src/com/coderising/jvm/clz/ClassFile.java @@ -0,0 +1,74 @@ +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/group11/996108220/src/com/coderising/jvm/clz/ClassIndex.java b/group11/996108220/src/com/coderising/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..f42e45d48f --- /dev/null +++ b/group11/996108220/src/com/coderising/jvm/clz/ClassIndex.java @@ -0,0 +1,19 @@ +package com.coderising.jvm.clz; + +public class ClassIndex { + private int thisClassIndex;//u2 + private int superClassIndex;//u2 + + 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/group11/996108220/src/com/coderising/jvm/constant/ClassInfo.java b/group11/996108220/src/com/coderising/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..d673cae1bd --- /dev/null +++ b/group11/996108220/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 ;//u2 + 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/group11/996108220/src/com/coderising/jvm/constant/ConstantInfo.java b/group11/996108220/src/com/coderising/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..466b072244 --- /dev/null +++ b/group11/996108220/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/group11/996108220/src/com/coderising/jvm/constant/ConstantPool.java b/group11/996108220/src/com/coderising/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..86c0445695 --- /dev/null +++ b/group11/996108220/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<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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/996108220/src/com/coderising/jvm/constant/FieldRefInfo.java b/group11/996108220/src/com/coderising/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..07133aa3a1 --- /dev/null +++ b/group11/996108220/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;//u2 + private int nameAndTypeIndex;//u2 + + 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/group11/996108220/src/com/coderising/jvm/constant/MethodRefInfo.java b/group11/996108220/src/com/coderising/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..ad3723ad0c --- /dev/null +++ b/group11/996108220/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; //u2 + private int nameAndTypeIndex;//u2 + + 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/group11/996108220/src/com/coderising/jvm/constant/NameAndTypeInfo.java b/group11/996108220/src/com/coderising/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..ee05963d21 --- /dev/null +++ b/group11/996108220/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;//u2 + private int index2;//u2 + + 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/group11/996108220/src/com/coderising/jvm/constant/NullConstantInfo.java b/group11/996108220/src/com/coderising/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..936736016f --- /dev/null +++ b/group11/996108220/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/group11/996108220/src/com/coderising/jvm/constant/StringInfo.java b/group11/996108220/src/com/coderising/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..1f0539dda4 --- /dev/null +++ b/group11/996108220/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;//u2 + 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/group11/996108220/src/com/coderising/jvm/constant/UTF8Info.java b/group11/996108220/src/com/coderising/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..c2c4408421 --- /dev/null +++ b/group11/996108220/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 ;//2 + private String value;//length + 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/group11/996108220/src/com/coderising/jvm/loader/ByteCodeIterator.java b/group11/996108220/src/com/coderising/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..a151decad8 --- /dev/null +++ b/group11/996108220/src/com/coderising/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,51 @@ +package com.coderising.jvm.loader; + +import java.util.Arrays; +import com.coderising.jvm.util.Util; + + + +public class ByteCodeIterator { + byte[] codes; + int cursor=0; + public ByteCodeIterator(byte[] codes) { + this.codes=codes; + } + public ByteCodeIterator(byte[] codes,int cursor) { + this.codes=codes; + this.cursor=cursor; + } + public boolean hasNext() { + return cursor != codes.length; + } + + + public int next() { + + int i = cursor; + if (i >= codes.length) + throw new ArrayIndexOutOfBoundsException(); + cursor = i + 1; + return codes[i]&0xFF; + } + public int nextU2ToInt() { + + return Util.byteToInt(new byte[]{codes[cursor++],codes[cursor++]}); + } + public int nextU4ToInt() { + + return Util.byteToInt(new byte[]{codes[cursor++],codes[cursor++], + codes[cursor++],codes[cursor++]}); + } + public String nextU4ToHexString() { + return Util.byteToHexString(new byte[]{codes[cursor++],codes[cursor++], + codes[cursor++],codes[cursor++]}); + + } + public byte[] getByte(int length) { + int i=cursor; + cursor=cursor+length; + return Arrays.copyOfRange(codes,i, cursor); + } + +} diff --git a/group11/996108220/src/com/coderising/jvm/loader/ClassFileLoader.java b/group11/996108220/src/com/coderising/jvm/loader/ClassFileLoader.java index 7bde3f4288..eccf6dc7b0 100644 --- a/group11/996108220/src/com/coderising/jvm/loader/ClassFileLoader.java +++ b/group11/996108220/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -1,12 +1,13 @@ package com.coderising.jvm.loader; - +import java.io.File; 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.clz.ClassFile; @@ -15,11 +16,23 @@ public class ClassFileLoader { private List<String> clzPaths = new ArrayList<String>(); 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"); + + 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 fileName) { ArrayList<Byte> list=new ArrayList<Byte>(); try { InputStream in=new FileInputStream(fileName.toString()); @@ -44,10 +57,15 @@ public byte[] readBinaryCode(String className) { byteCodes[i]=list.get(i); } - return byteCodes; + return byteCodes; } - + public ClassFile loadClass(String className) { + byte[] codes = this.readBinaryCode(className); + ClassFileParser parser = new ClassFileParser(); + return parser.parse(codes); + + } public void addClassPath(String path) { clzPaths.add(path); diff --git a/group11/996108220/src/com/coderising/jvm/loader/ClassFileParser.java b/group11/996108220/src/com/coderising/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..ac55f25e0e --- /dev/null +++ b/group11/996108220/src/com/coderising/jvm/loader/ClassFileParser.java @@ -0,0 +1,111 @@ +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.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) { + ByteCodeIterator iter=new ByteCodeIterator(codes); + String magicNumber=iter.nextU4ToHexString(); + if (!magicNumber.equals("cafebabe")) { + return null; + } + ClassFile classFile=new ClassFile(); + classFile.setMinorVersion(iter.nextU2ToInt()); + classFile.setMajorVersion(iter.nextU2ToInt()); + classFile.setConstPool(parseConstantPool(iter)); + classFile.setAccessFlag(parseAccessFlag(iter)); + classFile.setClassIndex(parseClassInfex(iter)); + return classFile; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + + return new AccessFlag(iter.nextU2ToInt()); + } + + 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 constPoolCount=iter.nextU2ToInt(); + + ConstantPool pool=new ConstantPool(); + pool.addConstantInfo(new NullConstantInfo()); + for (int i = 1; i <= constPoolCount-1; i++) { + int tag=iter.next(); + if (tag==1) { + //UTF8Info + UTF8Info utf8Info=new UTF8Info(pool); + int length=iter.nextU2ToInt(); + utf8Info.setLength(length); + String value=Util.byteToString(iter.getByte(length)); + utf8Info.setValue(value); + pool.addConstantInfo(utf8Info); + } + else if (tag==7) { + //ClassInfo + ClassInfo classInfo=new ClassInfo(pool); + int utf8Index=iter.nextU2ToInt(); + classInfo.setUtf8Index(utf8Index); + pool.addConstantInfo(classInfo); + } + else if (tag==8) { + //StringInfo + StringInfo stringInfo=new StringInfo(pool); + int index=iter.nextU2ToInt(); + stringInfo.setIndex(index); + pool.addConstantInfo(stringInfo); + } + else if (tag==9) { + //FieldRefInfo + 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==10) { + //MethodRefInfo + 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==12) { + //NameAndTypeInfo + NameAndTypeInfo nameAndTypeInfo=new NameAndTypeInfo(pool); + int index1=iter.nextU2ToInt(); + int index2=iter.nextU2ToInt(); + nameAndTypeInfo.setIndex1(index1); + nameAndTypeInfo.setIndex2(index2); + pool.addConstantInfo(nameAndTypeInfo); + } + else { + new RuntimeException("缺少tag为"+tag+"的常量"); + } + } + + return pool; + } + + +} diff --git a/group11/996108220/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group11/996108220/src/com/coderising/jvm/test/ClassFileloaderTest.java index 8fdc5db819..44d000a19a 100644 --- a/group11/996108220/src/com/coderising/jvm/test/ClassFileloaderTest.java +++ b/group11/996108220/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -4,7 +4,13 @@ import org.junit.Assert; 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; @@ -14,10 +20,20 @@ public class ClassFileloaderTest { - static String path1 = "F:\\mycoding2017\\group11\\996108220\\bin\\com\\coderising\\jvm\\test"; + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; - static String path2 = "C:\\temp"; + static String path1 = "F:\\mycoding2017\\group11\\996108220\\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 @@ -73,21 +89,113 @@ public void testMagicNumber(){ + 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(); + } + /** + * ---------------------------------------------------------------------- + */ - 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); + @Test + public void testVersion(){ + + Assert.assertEquals(0, clzFile.getMinorVersion()); + Assert.assertEquals(51, 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()); } - return buffer.toString(); - } + { + 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("<init>", 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/group11/996108220/src/com/coderising/jvm/util/Util.java b/group11/996108220/src/com/coderising/jvm/util/Util.java new file mode 100644 index 0000000000..c9808b1c1c --- /dev/null +++ b/group11/996108220/src/com/coderising/jvm/util/Util.java @@ -0,0 +1,33 @@ +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(); + } + public static String byteToString(byte[] codes ){ + StringBuffer buffer = new StringBuffer(); + for(int i=0;i<codes.length;i++){ + byte b = codes[i]; + int value = b & 0xFF; + buffer.append((char)value); + } + return buffer.toString(); + } +} diff --git a/group11/996108220/src/com/coding/basic/ArrayList.java b/group11/996108220/src/com/coding/basic/ArrayList.java index 2445d52ae5..e0fc20f718 100644 --- a/group11/996108220/src/com/coding/basic/ArrayList.java +++ b/group11/996108220/src/com/coding/basic/ArrayList.java @@ -10,7 +10,11 @@ public class ArrayList implements List { */ public void add(Object o){ if(size+1>elementData.length)this.grow(elementData); - else elementData[size++]=o; + else{ + elementData[size]=o; + size++; + } + } /** * 在index处添加元素,index+1到size-1元素向后移动 diff --git a/group11/996108220/src/com/coding/basic/Stack.java b/group11/996108220/src/com/coding/basic/Stack.java deleted file mode 100644 index ea41c87d1b..0000000000 --- a/group11/996108220/src/com/coding/basic/Stack.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.coding.basic; - -public class Stack { - //用动态数组实现栈 - private ArrayList elementData = new ArrayList(); - - public void push(Object o){ - elementData.add(elementData.size()); - } - - public Object pop(){ - return elementData.remove(elementData.size()-1); - } - - public Object peek(){ - return elementData.get(elementData.size()-1); - } - public boolean isEmpty(){ - return elementData.size()==0?true:false; - } - public int size(){ - return elementData.size(); - } -} diff --git a/group11/996108220/src/com/coding/basic/stack/Stack.java b/group11/996108220/src/com/coding/basic/stack/Stack.java new file mode 100644 index 0000000000..05f380a304 --- /dev/null +++ b/group11/996108220/src/com/coding/basic/stack/Stack.java @@ -0,0 +1,40 @@ +package com.coding.basic.stack; + +import com.coding.basic.ArrayList; + +public class Stack { + //用动态数组实现栈 + private ArrayList elementData = new ArrayList(); + + public void push(Object o){ + elementData.add(o); + } + + public Object pop(){ + return elementData.remove(elementData.size()-1); + } + + public Object peek(){ + return elementData.get(elementData.size()-1); + } + public boolean isEmpty(){ + return elementData.size()==0?true:false; + } + public int size(){ + return elementData.size(); + } + public String toString() { + + StringBuffer buffer=new StringBuffer("["); + for (int i = elementData.size()-1; i >=0; i--) { + if (i==0) { + buffer.append(elementData.get(i).toString()+"]"); + } + else { + buffer.append(elementData.get(i).toString()+","); + } + } + return buffer.toString(); + } + +} diff --git a/group11/996108220/src/com/coding/basic/stack/StackUtil.java b/group11/996108220/src/com/coding/basic/stack/StackUtil.java new file mode 100644 index 0000000000..2499f144ea --- /dev/null +++ b/group11/996108220/src/com/coding/basic/stack/StackUtil.java @@ -0,0 +1,131 @@ +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) { + + reverse(s,s.size()); + } + + private static void reverse(Stack s, int length) { + if (length==1) { + return ; + } + Stack s1=new Stack(); + Object o=s.pop(); + for (int i = 1; i < length; i++) { + s1.push(s.pop()); + } + s.push(o); + for (int i = 1; i < length; i++) { + s.push(s1.pop()); + } + reverse(s, length-1); + + } + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s,Object o) { + if (s.size()==0) { + return; + } + Stack s1=new Stack(); + while(s.size()!=0) { + if (!s.peek().equals(o)) { + s1.push(s.pop()); + + } + else { + s.pop(); + break; + } + } + while(s1.size()!=0) { + s.push(s1.pop()); + } + + + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * @param len + * @return + */ + public static Object[] getTop(Stack s,int len) { + if (len>s.size()||len<=0) { + return null; + } + Stack s1=new Stack(); + Object[] array=new Object[len]; + for (int i = 0; i < len; i++) { + Object object=s.pop(); + array[i]=object; + s1.push(object); + } + while(s1.size()!=0) { + s.push(s1.pop()); + } + return array; + } + /** + * 字符串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 stack=new Stack(); + for (int i = 0; i < s.length(); i++) { + switch (s.charAt(i)) { + case '(': + stack.push(s.charAt(i)); + break; + case '[': + stack.push(s.charAt(i)); + break; + case '{': + stack.push(s.charAt(i)); + break; + case ')': + if (stack.size()==0||(!stack.pop().equals('('))) { + return false; + } + break; + case ']': + if (stack.size()==0||(!stack.pop().equals('['))) { + return false; + } + break; + case '}': + if (stack.size()==0||(!stack.pop().equals('{'))) { + return false; + } + break; + default: + break; + } + } + if (stack.size()!=0) { + return false; + } + else { + return true; + } + + } + + +} diff --git a/group11/996108220/src/com/coding/basic/stack/StackUtilTest.java b/group11/996108220/src/com/coding/basic/stack/StackUtilTest.java new file mode 100644 index 0000000000..91e3211683 --- /dev/null +++ b/group11/996108220/src/com/coding/basic/stack/StackUtilTest.java @@ -0,0 +1,82 @@ +package com.coding.basic.stack; + +import static org.junit.Assert.*; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class StackUtilTest { + Stack s; + @Before + public void setUp() throws Exception { + + } + + @After + public void tearDown() throws Exception { + } + @Test + public void testToString() { + s=new Stack(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + s.push(6); + + Assert.assertEquals("[6,5,4,3,2,1]", s.toString()); + } + + @Test + public void testReverse() { + s=new Stack(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + s.push(6); + StackUtil.reverse(s); + //System.out.println(s.size()); + Assert.assertEquals("[1,2,3,4,5,6]", s.toString()); + } + @Test + public void testRemove() { + s=new Stack(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + s.push(6); + StackUtil.remove(s, 6); + //System.out.println(s.toString()); + Assert.assertEquals("[5,4,3,2,1]", s.toString()); + } + @Test + public void testGetTop() { + s=new Stack(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + s.push(6); + Object[] s1=StackUtil.getTop(s, s.size()); + for (int i = 0; i < s1.length; i++) { + System.out.println(s1[i]); + } + //Assert.assertEquals("[5,6]", s1.toString()); + } + @Test + public void testIsValidPairs() { + String s="([e{df])" ; + Assert.assertEquals(false, StackUtil.isValidPairs(s)); + } + +} From 6ba808f8265f925554ca2876c59d5c4bd3f29047 Mon Sep 17 00:00:00 2001 From: GUK0 <1685605435@qq.com> Date: Mon, 10 Apr 2017 18:04:02 +0800 Subject: [PATCH 199/287] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=AC=AC6=E5=91=A8?= =?UTF-8?q?=E4=BD=9C=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../week5/{LRU.java => LRUPageFrame.java} | 2 +- .../{LRUTest.java => LRUPageFrameTest.java} | 4 +- group12/247565311/week6/InfixExpr.java | 103 ++++++++++++++++++ group12/247565311/week6/InfixExprTest.java | 42 +++++++ group12/247565311/week6/struts.java | 5 - 5 files changed, 148 insertions(+), 8 deletions(-) rename group12/247565311/week5/{LRU.java => LRUPageFrame.java} (98%) rename group12/247565311/week5/{LRUTest.java => LRUPageFrameTest.java} (89%) create mode 100644 group12/247565311/week6/InfixExpr.java create mode 100644 group12/247565311/week6/InfixExprTest.java delete mode 100644 group12/247565311/week6/struts.java diff --git a/group12/247565311/week5/LRU.java b/group12/247565311/week5/LRUPageFrame.java similarity index 98% rename from group12/247565311/week5/LRU.java rename to group12/247565311/week5/LRUPageFrame.java index 705b0b0c87..a3b99870e3 100644 --- a/group12/247565311/week5/LRU.java +++ b/group12/247565311/week5/LRUPageFrame.java @@ -2,7 +2,7 @@ import java.util.HashSet; import week1.ArrayList; -public class LRU { +public class LRUPageFrame { int size; Node head = new Node(0); HashSet<Integer> lib = new HashSet<Integer>(); diff --git a/group12/247565311/week5/LRUTest.java b/group12/247565311/week5/LRUPageFrameTest.java similarity index 89% rename from group12/247565311/week5/LRUTest.java rename to group12/247565311/week5/LRUPageFrameTest.java index 0ee0d95309..8593a83739 100644 --- a/group12/247565311/week5/LRUTest.java +++ b/group12/247565311/week5/LRUPageFrameTest.java @@ -7,7 +7,7 @@ import org.junit.Before; import org.junit.Test; -public class LRUTest { +public class LRUPageFrameTest { @Before public void setUp() throws Exception { @@ -19,7 +19,7 @@ public void tearDown() throws Exception { @Test public void testAdd() { - LRU lru = new LRU(5); + LRUPageFrame lru = new LRUPageFrame(5); lru.add(3); lru.add(7); lru.add(5); diff --git a/group12/247565311/week6/InfixExpr.java b/group12/247565311/week6/InfixExpr.java new file mode 100644 index 0000000000..d50bc09c32 --- /dev/null +++ b/group12/247565311/week6/InfixExpr.java @@ -0,0 +1,103 @@ +package week6; + +public class InfixExpr { + String expr = null; + Node node = new Node(); + Element getElem = null; + public InfixExpr(String expr) { + this.expr = expr; + getElem = new Element(expr); + } + public float evaluate() { + Node node = new Node('\0',getElem.getNextNum()); + Node root = createNode(node); + return getValue(root); + } + class Element{ + private int index; + private String str + public Element(String _str){ + index = 0; + str = _str; + } + public double getNextNum(){ + double resl = 0,resr; + int fbits = 0; + char ch = str.charAt(index); + boolean hasp = false; + while(ch=='.' || (ch<='9' && '0'<=ch)){ + index += 1; + if(ch == '.') hasp = true; + else{ + if(hasp){ + fbits -= 1; + resr += (double)(ch-'0') * Math.pow(10,fbits) + }else{ + resl *= 10; + resl += (ch-'0'); + } + } + if(hasNext()) ch = str.charAt(index); + else break; + } + return resl+resr; + } + public char getNextOper(){ + if(hasNext()){ + char ch = str.charAt(index); + if((ch>='0' && '9'>=ch) || ch=='.') return '\0'; + else{ + index += 1; + return ch; + } + }else{ + return '\0'; + } + } + public boolean hasNext(){ + return index<str.length(); + } + } + class Node{ + char op; + double val; + Node left,right; + Node(char o,double v){ + left = null; + right = null; + op = o; + val =v; + } + } + private Node createNode(Node root){ + char ch = getElem.getNextOper(); + if(ch == '\0'){ + + }else{ + + } + Node node = new Node(getElem.getNextOper,0); + node.left = root; + node.right = + } + private double getValue(Node root){ + if(root == null) throw new Exception("inlegal operator found"); + switch(root.op){ + case '+': + return getValue(root.left)+getValue(root.right); + break; + case '-': + return getValue(root.left)-getValue(root.right); + break; + case '*': + return getValue(root.left)*getValue(root.right); + break; + case '/': + return getValue(root.left)/getValue(root.right); + break; + default: + return root.val; + break; + } + } +} diff --git a/group12/247565311/week6/InfixExprTest.java b/group12/247565311/week6/InfixExprTest.java new file mode 100644 index 0000000000..cbf7e5ef39 --- /dev/null +++ b/group12/247565311/week6/InfixExprTest.java @@ -0,0 +1,42 @@ +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class InfixExprTest { + + @Before + public void setUp() throws Exception { + } + @After + public void tearDown() throws Exception { + } + @Test + public void testEvaluate() { + //InfixExpr expr = new InfixExpr("300*20+12*5-20/4"); + { + InfixExpr expr = new InfixExpr("2+3*4+5"); + Assert.assertEquals(19.0, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("3*20+12*5-40/2"); + Assert.assertEquals(100.0, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("3*20/2"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("20/2*3"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("10-30+50"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + } +} \ No newline at end of file diff --git a/group12/247565311/week6/struts.java b/group12/247565311/week6/struts.java deleted file mode 100644 index 57126bc314..0000000000 --- a/group12/247565311/week6/struts.java +++ /dev/null @@ -1,5 +0,0 @@ -package week6; - -public class struts { - -} From a27b9ab8edde438798fa55793eb1c83f93d9bdb6 Mon Sep 17 00:00:00 2001 From: DonaldY <448641125@qq.com> Date: Mon, 10 Apr 2017 21:01:54 +0800 Subject: [PATCH 200/287] fifth week homework --- .../src/com/donaldy/basic/StackUtil.java | 23 +++- .../src/com/donaldy/jvm/clz/AccessFlag.java | 25 ++++ .../src/com/donaldy/jvm/clz/ClassFile.java | 75 +++++++++++ .../src/com/donaldy/jvm/clz/ClassIndex.java | 19 +++ .../com/donaldy/jvm/constant/ClassInfo.java | 24 ++++ .../donaldy/jvm/constant/ConstantInfo.java | 29 ++++ .../donaldy/jvm/constant/ConstantPool.java | 29 ++++ .../donaldy/jvm/constant/FieldRefInfo.java | 54 ++++++++ .../donaldy/jvm/constant/MethodRefInfo.java | 55 ++++++++ .../donaldy/jvm/constant/NameAndTypeInfo.java | 45 +++++++ .../jvm/constant/NullConstantInfo.java | 13 ++ .../com/donaldy/jvm/constant/StringInfo.java | 26 ++++ .../com/donaldy/jvm/constant/UTF8Info.java | 32 +++++ .../donaldy/jvm/loader/ByteCodeIterator.java | 51 +++++++ .../donaldy/jvm/loader/ClassFileLoader.java | 80 ++++++++--- .../donaldy/jvm/loader/ClassFileParser.java | 127 ++++++++++++++++++ .../donaldy/jvm/test/ClassFileloaderTest.java | 119 +++++++++++++++- .../src/com/donaldy/jvm/util/Util.java | 24 ++++ .../src/com/donaldy/test/StackUtilTest.java | 7 +- 19 files changed, 827 insertions(+), 30 deletions(-) create mode 100644 group24/448641125/src/com/donaldy/jvm/clz/AccessFlag.java create mode 100644 group24/448641125/src/com/donaldy/jvm/clz/ClassFile.java create mode 100644 group24/448641125/src/com/donaldy/jvm/clz/ClassIndex.java create mode 100644 group24/448641125/src/com/donaldy/jvm/constant/ClassInfo.java create mode 100644 group24/448641125/src/com/donaldy/jvm/constant/ConstantInfo.java create mode 100644 group24/448641125/src/com/donaldy/jvm/constant/ConstantPool.java create mode 100644 group24/448641125/src/com/donaldy/jvm/constant/FieldRefInfo.java create mode 100644 group24/448641125/src/com/donaldy/jvm/constant/MethodRefInfo.java create mode 100644 group24/448641125/src/com/donaldy/jvm/constant/NameAndTypeInfo.java create mode 100644 group24/448641125/src/com/donaldy/jvm/constant/NullConstantInfo.java create mode 100644 group24/448641125/src/com/donaldy/jvm/constant/StringInfo.java create mode 100644 group24/448641125/src/com/donaldy/jvm/constant/UTF8Info.java create mode 100644 group24/448641125/src/com/donaldy/jvm/loader/ByteCodeIterator.java create mode 100644 group24/448641125/src/com/donaldy/jvm/loader/ClassFileParser.java create mode 100644 group24/448641125/src/com/donaldy/jvm/util/Util.java diff --git a/group24/448641125/src/com/donaldy/basic/StackUtil.java b/group24/448641125/src/com/donaldy/basic/StackUtil.java index a950fa77e4..ca0014b34e 100644 --- a/group24/448641125/src/com/donaldy/basic/StackUtil.java +++ b/group24/448641125/src/com/donaldy/basic/StackUtil.java @@ -10,15 +10,14 @@ public class StackUtil { * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 */ public static void reverse(Stack s) { - Stack stack = new Stack(); + ArrayList arrayList = new ArrayList(); while (!s.isEmpty()) { Object element = s.pop(); - stack.push(element); + arrayList.add(element); } - while (!stack.isEmpty()) { - Object element = stack.pop(); - s.push(element); + for (int i = 0; i < arrayList.size(); ++i) { + s.push(arrayList.get(i)); } } @@ -53,11 +52,21 @@ public static void remove(Stack s,Object o) { 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(); + ArrayList arrayList = new ArrayList(); + + while (!s.isEmpty()) { + arrayList.add(s.pop()); } + + for (int i = arrayList.size() - 1; i >= 0; --i) + s.push(arrayList.get(i)); + + for (int i = 0 ; i < len; ++i) + arr[i] = arrayList.get(i); + return arr; } /** diff --git a/group24/448641125/src/com/donaldy/jvm/clz/AccessFlag.java b/group24/448641125/src/com/donaldy/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..ea06ad07cb --- /dev/null +++ b/group24/448641125/src/com/donaldy/jvm/clz/AccessFlag.java @@ -0,0 +1,25 @@ +package com.donaldy.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/group24/448641125/src/com/donaldy/jvm/clz/ClassFile.java b/group24/448641125/src/com/donaldy/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..e37a77e5ad --- /dev/null +++ b/group24/448641125/src/com/donaldy/jvm/clz/ClassFile.java @@ -0,0 +1,75 @@ +package com.donaldy.jvm.clz; + +import com.donaldy.jvm.constant.ClassInfo; +import com.donaldy.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/group24/448641125/src/com/donaldy/jvm/clz/ClassIndex.java b/group24/448641125/src/com/donaldy/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..d7e0524060 --- /dev/null +++ b/group24/448641125/src/com/donaldy/jvm/clz/ClassIndex.java @@ -0,0 +1,19 @@ +package com.donaldy.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/group24/448641125/src/com/donaldy/jvm/constant/ClassInfo.java b/group24/448641125/src/com/donaldy/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..71f31261e4 --- /dev/null +++ b/group24/448641125/src/com/donaldy/jvm/constant/ClassInfo.java @@ -0,0 +1,24 @@ +package com.donaldy.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/group24/448641125/src/com/donaldy/jvm/constant/ConstantInfo.java b/group24/448641125/src/com/donaldy/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..20cad6fcd5 --- /dev/null +++ b/group24/448641125/src/com/donaldy/jvm/constant/ConstantInfo.java @@ -0,0 +1,29 @@ +package com.donaldy.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/group24/448641125/src/com/donaldy/jvm/constant/ConstantPool.java b/group24/448641125/src/com/donaldy/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..77bdfc8e67 --- /dev/null +++ b/group24/448641125/src/com/donaldy/jvm/constant/ConstantPool.java @@ -0,0 +1,29 @@ +package com.donaldy.jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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/448641125/src/com/donaldy/jvm/constant/FieldRefInfo.java b/group24/448641125/src/com/donaldy/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..6a6f72f5da --- /dev/null +++ b/group24/448641125/src/com/donaldy/jvm/constant/FieldRefInfo.java @@ -0,0 +1,54 @@ +package com.donaldy.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/group24/448641125/src/com/donaldy/jvm/constant/MethodRefInfo.java b/group24/448641125/src/com/donaldy/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..e65135279f --- /dev/null +++ b/group24/448641125/src/com/donaldy/jvm/constant/MethodRefInfo.java @@ -0,0 +1,55 @@ +package com.donaldy.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/group24/448641125/src/com/donaldy/jvm/constant/NameAndTypeInfo.java b/group24/448641125/src/com/donaldy/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..21ecd2b411 --- /dev/null +++ b/group24/448641125/src/com/donaldy/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,45 @@ +package com.donaldy.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/group24/448641125/src/com/donaldy/jvm/constant/NullConstantInfo.java b/group24/448641125/src/com/donaldy/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..3a2cc11017 --- /dev/null +++ b/group24/448641125/src/com/donaldy/jvm/constant/NullConstantInfo.java @@ -0,0 +1,13 @@ +package com.donaldy.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo(){ + + } + @Override + public int getType() { + return -1; + } + +} diff --git a/group24/448641125/src/com/donaldy/jvm/constant/StringInfo.java b/group24/448641125/src/com/donaldy/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..f59d34a497 --- /dev/null +++ b/group24/448641125/src/com/donaldy/jvm/constant/StringInfo.java @@ -0,0 +1,26 @@ +package com.donaldy.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/group24/448641125/src/com/donaldy/jvm/constant/UTF8Info.java b/group24/448641125/src/com/donaldy/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..7432e5b6c4 --- /dev/null +++ b/group24/448641125/src/com/donaldy/jvm/constant/UTF8Info.java @@ -0,0 +1,32 @@ +package com.donaldy.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/group24/448641125/src/com/donaldy/jvm/loader/ByteCodeIterator.java b/group24/448641125/src/com/donaldy/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..052bbe1034 --- /dev/null +++ b/group24/448641125/src/com/donaldy/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,51 @@ +package com.donaldy.jvm.loader; + +import com.donaldy.jvm.util.Util; + +public class ByteCodeIterator { + + private byte[] codes; + + private int pointer = 0; + + public ByteCodeIterator(byte[] codes) { + this.codes = codes; + } + + public String nextU4ToHexString() { + byte [] byteCodes = nextLenByte(4); + + return Util.byteToHexString(byteCodes); + } + + public int nextU2ToInt() { + byte [] byteCodes = nextLenByte(2); + + return Util.byteToInt(byteCodes); + } + + public int nextU1toInt() { + byte [] byteCodes = nextLenByte(1); + + return Util.byteToInt(byteCodes); + } + + public byte[] getBytes(int len) { + byte [] byteCodes = nextLenByte(len); + + return byteCodes; + } + + private byte[] nextLenByte(int len) { + if (this.pointer + len >= this.codes.length) + throw new IndexOutOfBoundsException("codes.length : " + this.codes.length); + + byte [] byteCodes = new byte[len]; + + for (int i = 0 ; i < len; ++i) { + byteCodes[i] = this.codes[pointer ++]; + } + + return byteCodes; + } +} diff --git a/group24/448641125/src/com/donaldy/jvm/loader/ClassFileLoader.java b/group24/448641125/src/com/donaldy/jvm/loader/ClassFileLoader.java index 96d55334d1..e1132dd023 100644 --- a/group24/448641125/src/com/donaldy/jvm/loader/ClassFileLoader.java +++ b/group24/448641125/src/com/donaldy/jvm/loader/ClassFileLoader.java @@ -2,7 +2,10 @@ import java.io.*; import java.util.ArrayList; -import java.util.Iterator; + +import com.donaldy.jvm.clz.ClassFile; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; import java.util.List; @@ -12,10 +15,64 @@ public class ClassFileLoader { private List<String> clzPaths = new ArrayList<String>(); static final int BUFFER_SIZE = 1024; - + public byte[] readBinaryCode(String className) { + className = className.replace(".", File.separator) + ".class"; + + for (String path : this.clzPaths) { + + String clzFileName = path + File.separator + 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 byte[] readBinaryCode_V1(String className) { for (String clzPath : clzPaths) { @@ -52,24 +109,17 @@ public byte[] readBinaryCode(String className) { } - - public void addClassPath(String path) { - if (path == null) - return; - - clzPaths.add(path); - } - - - - public String getClassPath(){ + public String getClassPath_V1(){ StringBuilder sb = new StringBuilder(); - int length = clzPaths.size(); + + int length = this.clzPaths.size(); + for (int i = 0 ; i < length; ++i) { - sb.append(clzPaths.get(i)); + sb.append(this.clzPaths.get(i)); if (i + 1 < length) sb.append(";"); } + return sb.toString(); } diff --git a/group24/448641125/src/com/donaldy/jvm/loader/ClassFileParser.java b/group24/448641125/src/com/donaldy/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..395e989426 --- /dev/null +++ b/group24/448641125/src/com/donaldy/jvm/loader/ClassFileParser.java @@ -0,0 +1,127 @@ +package com.donaldy.jvm.loader; + +import com.donaldy.jvm.clz.AccessFlag; +import com.donaldy.jvm.clz.ClassFile; +import com.donaldy.jvm.clz.ClassIndex; +import com.donaldy.jvm.constant.*; + +import javax.lang.model.element.Name; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Method; + + +public class ClassFileParser { + + public ClassFile parse(byte[] codes) { + + ByteCodeIterator iter = new ByteCodeIterator(codes); + ClassFile clzFile = new ClassFile(); + + 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); + + AccessFlag flag = parseAccessFlag(iter); + clzFile.setAccessFlag(flag); + + ClassIndex clzIndex = parseClassIndex(iter); + clzFile.setClassIndex(clzIndex); + + return clzFile; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + AccessFlag flag = new AccessFlag(iter.nextU2ToInt()); + return flag; + } + + private ClassIndex parseClassIndex(ByteCodeIterator iter) { + + int thisClassIndex = iter.nextU2ToInt(); + int superClassIndex = iter.nextU2ToInt(); + + ClassIndex clzIndex = new ClassIndex(); + + clzIndex.setThisClassIndex(thisClassIndex); + clzIndex.setSuperClassIndex(superClassIndex); + + return clzIndex; + + } + + private ConstantPool parseConstantPool(ByteCodeIterator iter) { + + int constPoolCount = iter.nextU2ToInt(); + + System.out.println("Constant Pool Count : " + constPoolCount); + + ConstantPool pool = new ConstantPool(); + + 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); + + pool.addConstantInfo(clzInfo); + } else if (tag == 1) { + //UTF-8 String + int len = iter.nextU2ToInt(); + byte [] data = iter.getBytes(len); + String value = null; + try { + value = new String(data, "UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + UTF8Info utf8Info = new UTF8Info(pool); + utf8Info.setLength(len); + utf8Info.setValue(value); + pool.addConstantInfo(utf8Info); + } 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) { + //MethodRef + MethodRefInfo method = new MethodRefInfo(pool); + method.setClassInfoIndex(iter.nextU2ToInt()); + method.setNameAndTypeIndex(iter.nextU2ToInt()); + pool.addConstantInfo(method); + } else if (tag == 12) { + // Name and Type Info + NameAndTypeInfo nameType = new NameAndTypeInfo(pool); + nameType.setIndex1(iter.nextU2ToInt()); + nameType.setIndex2(iter.nextU2ToInt()); + pool.addConstantInfo(nameType); + } else { + throw new RuntimeException("the constant pool tag" + tag); + } + } + + return pool; + } + + +} diff --git a/group24/448641125/src/com/donaldy/jvm/test/ClassFileloaderTest.java b/group24/448641125/src/com/donaldy/jvm/test/ClassFileloaderTest.java index 2ed50aa8b5..387990b9b7 100644 --- a/group24/448641125/src/com/donaldy/jvm/test/ClassFileloaderTest.java +++ b/group24/448641125/src/com/donaldy/jvm/test/ClassFileloaderTest.java @@ -1,5 +1,8 @@ package com.donaldy.jvm.test; +import com.donaldy.jvm.clz.ClassFile; +import com.donaldy.jvm.clz.ClassIndex; +import com.donaldy.jvm.constant.*; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -13,11 +16,12 @@ public class ClassFileloaderTest { - + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + static String path1 = "D:\\tools\\Code\\Y_Repository\\coding2017\\group24\\448641125\\out\\production\\448641125\\"; static String path2 = "C:\\temp"; - - + + static ClassFile clzFile = null; @Before public void setUp() throws Exception { @@ -69,10 +73,7 @@ public void testMagicNumber(){ Assert.assertEquals("cafebabe", acctualValue); } - - - - + private String byteToHexString(byte[] codes ){ @@ -89,4 +90,108 @@ private String byteToHexString(byte[] codes ){ return buffer.toString(); } + + /** + * ---------------------------------------------------------------------- + */ + + + @Test + public void testVersion(){ + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(this.path1); + clzFile = loader.loadClass("com.donaldy.jvm.test.EmployeeV1"); + + Assert.assertEquals(0, clzFile.getMinorVersion()); + Assert.assertEquals(52, clzFile.getMajorVersion()); + + } + + @Test + public void testConstantPool(){ + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(this.path1); + clzFile = loader.loadClass("com.donaldy.jvm.test.EmployeeV1"); + + 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("<init>", 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(){ + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(this.path1); + clzFile = loader.loadClass("com.donaldy.jvm.test.EmployeeV1"); + + 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/448641125/src/com/donaldy/jvm/util/Util.java b/group24/448641125/src/com/donaldy/jvm/util/Util.java new file mode 100644 index 0000000000..f316117565 --- /dev/null +++ b/group24/448641125/src/com/donaldy/jvm/util/Util.java @@ -0,0 +1,24 @@ +package com.donaldy.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/group24/448641125/src/com/donaldy/test/StackUtilTest.java b/group24/448641125/src/com/donaldy/test/StackUtilTest.java index 2bfe6101eb..680a377d4d 100644 --- a/group24/448641125/src/com/donaldy/test/StackUtilTest.java +++ b/group24/448641125/src/com/donaldy/test/StackUtilTest.java @@ -17,7 +17,7 @@ public void testReverse() { for (int i = 4; i >= 0 ; --i) stack.push(intArr[i]); StackUtil.reverse(stack); - for (int i = 0 ; i < 5; ++i) { + for (int i = 4 ; i >= 0; --i) { Assert.assertEquals((int)stack.pop(), (int)intArr[i]); } } @@ -51,6 +51,10 @@ public void testGetTop() { for (int i = 0 ; i < arr.length ; ++i) { Assert.assertEquals((int)arr[i], (int)intArr[i]); } + + for (int i = 0; i < 5; ++i) { + Assert.assertEquals((int)intArr[i], (int)stack.pop()); + } } @Test @@ -61,5 +65,6 @@ public void testIsValidPairs() { String str2 = "([b{x]y})"; Assert.assertEquals(false, StackUtil.isValidPairs(str2)); + } } From b2b47910fa6dd8784c9c61444389d046c70987db Mon Sep 17 00:00:00 2001 From: brucejiao1 <jiao.xiaopan@163.com> Date: Mon, 10 Apr 2017 21:13:26 +0800 Subject: [PATCH 201/287] =?UTF-8?q?jvm=E7=AC=AC=E4=BA=8C=E6=AC=A1=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../homework0409/jvm/clz/AccessFlag.java | 25 +++ .../bruce/homework0409/jvm/clz/ClassFile.java | 75 +++++++ .../homework0409/jvm/clz/ClassIndex.java | 19 ++ .../homework0409/jvm/constant/ClassInfo.java | 24 +++ .../jvm/constant/ConstantInfo.java | 29 +++ .../jvm/constant/ConstantPool.java | 29 +++ .../jvm/constant/FieldRefInfo.java | 54 +++++ .../jvm/constant/MethodRefInfo.java | 55 +++++ .../jvm/constant/NameAndTypeInfo.java | 45 ++++ .../jvm/constant/NullConstantInfo.java | 13 ++ .../homework0409/jvm/constant/StringInfo.java | 26 +++ .../homework0409/jvm/constant/UTF8Info.java | 32 +++ .../jvm/loader/ByteCodeIterator.java | 39 ++++ .../jvm/loader/ClassFileLoader.java | 102 +++++++++ .../jvm/loader/ClassFileParser.java | 99 +++++++++ .../jvm/test/ClassFileloaderTest.java | 202 ++++++++++++++++++ .../homework0409/jvm/test/EmployeeV1.java | 28 +++ .../com/bruce/homework0409/jvm/util/Util.java | 24 +++ .../bruce/homework0409/stack/StackUtil.java | 120 +++++++++++ .../homework0409/stack/StackUtilTest.java | 55 +++++ 20 files changed, 1095 insertions(+) create mode 100644 group15/1510_739253131/src/com/bruce/homework0409/jvm/clz/AccessFlag.java create mode 100644 group15/1510_739253131/src/com/bruce/homework0409/jvm/clz/ClassFile.java create mode 100644 group15/1510_739253131/src/com/bruce/homework0409/jvm/clz/ClassIndex.java create mode 100644 group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/ClassInfo.java create mode 100644 group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/ConstantInfo.java create mode 100644 group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/ConstantPool.java create mode 100644 group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/FieldRefInfo.java create mode 100644 group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/MethodRefInfo.java create mode 100644 group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/NameAndTypeInfo.java create mode 100644 group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/NullConstantInfo.java create mode 100644 group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/StringInfo.java create mode 100644 group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/UTF8Info.java create mode 100644 group15/1510_739253131/src/com/bruce/homework0409/jvm/loader/ByteCodeIterator.java create mode 100644 group15/1510_739253131/src/com/bruce/homework0409/jvm/loader/ClassFileLoader.java create mode 100644 group15/1510_739253131/src/com/bruce/homework0409/jvm/loader/ClassFileParser.java create mode 100644 group15/1510_739253131/src/com/bruce/homework0409/jvm/test/ClassFileloaderTest.java create mode 100644 group15/1510_739253131/src/com/bruce/homework0409/jvm/test/EmployeeV1.java create mode 100644 group15/1510_739253131/src/com/bruce/homework0409/jvm/util/Util.java create mode 100644 group15/1510_739253131/src/com/bruce/homework0409/stack/StackUtil.java create mode 100644 group15/1510_739253131/src/com/bruce/homework0409/stack/StackUtilTest.java diff --git a/group15/1510_739253131/src/com/bruce/homework0409/jvm/clz/AccessFlag.java b/group15/1510_739253131/src/com/bruce/homework0409/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..0678df8b4e --- /dev/null +++ b/group15/1510_739253131/src/com/bruce/homework0409/jvm/clz/AccessFlag.java @@ -0,0 +1,25 @@ +package com.bruce.homework0409.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/1510_739253131/src/com/bruce/homework0409/jvm/clz/ClassFile.java b/group15/1510_739253131/src/com/bruce/homework0409/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..8cc51f7c7c --- /dev/null +++ b/group15/1510_739253131/src/com/bruce/homework0409/jvm/clz/ClassFile.java @@ -0,0 +1,75 @@ +package com.bruce.homework0409.jvm.clz; + +import com.bruce.homework0409.jvm.constant.ClassInfo; +import com.bruce.homework0409.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/1510_739253131/src/com/bruce/homework0409/jvm/clz/ClassIndex.java b/group15/1510_739253131/src/com/bruce/homework0409/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..a860931c9f --- /dev/null +++ b/group15/1510_739253131/src/com/bruce/homework0409/jvm/clz/ClassIndex.java @@ -0,0 +1,19 @@ +package com.bruce.homework0409.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/1510_739253131/src/com/bruce/homework0409/jvm/constant/ClassInfo.java b/group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..053d36b18d --- /dev/null +++ b/group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/ClassInfo.java @@ -0,0 +1,24 @@ +package com.bruce.homework0409.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/1510_739253131/src/com/bruce/homework0409/jvm/constant/ConstantInfo.java b/group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..9cdbcfa6c0 --- /dev/null +++ b/group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/ConstantInfo.java @@ -0,0 +1,29 @@ +package com.bruce.homework0409.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/1510_739253131/src/com/bruce/homework0409/jvm/constant/ConstantPool.java b/group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..d8cc06a731 --- /dev/null +++ b/group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/ConstantPool.java @@ -0,0 +1,29 @@ +package com.bruce.homework0409.jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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/1510_739253131/src/com/bruce/homework0409/jvm/constant/FieldRefInfo.java b/group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..1fc5bee059 --- /dev/null +++ b/group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/FieldRefInfo.java @@ -0,0 +1,54 @@ +package com.bruce.homework0409.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/1510_739253131/src/com/bruce/homework0409/jvm/constant/MethodRefInfo.java b/group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..e6cfe7d0a4 --- /dev/null +++ b/group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/MethodRefInfo.java @@ -0,0 +1,55 @@ +package com.bruce.homework0409.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/1510_739253131/src/com/bruce/homework0409/jvm/constant/NameAndTypeInfo.java b/group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..aff23210a4 --- /dev/null +++ b/group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,45 @@ +package com.bruce.homework0409.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/1510_739253131/src/com/bruce/homework0409/jvm/constant/NullConstantInfo.java b/group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..e5c505e530 --- /dev/null +++ b/group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/NullConstantInfo.java @@ -0,0 +1,13 @@ +package com.bruce.homework0409.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo(){ + + } + @Override + public int getType() { + return -1; + } + +} diff --git a/group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/StringInfo.java b/group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..944062270d --- /dev/null +++ b/group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/StringInfo.java @@ -0,0 +1,26 @@ +package com.bruce.homework0409.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/1510_739253131/src/com/bruce/homework0409/jvm/constant/UTF8Info.java b/group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..4c2d3b2783 --- /dev/null +++ b/group15/1510_739253131/src/com/bruce/homework0409/jvm/constant/UTF8Info.java @@ -0,0 +1,32 @@ +package com.bruce.homework0409.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/1510_739253131/src/com/bruce/homework0409/jvm/loader/ByteCodeIterator.java b/group15/1510_739253131/src/com/bruce/homework0409/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..d03dc786dd --- /dev/null +++ b/group15/1510_739253131/src/com/bruce/homework0409/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,39 @@ +package com.bruce.homework0409.jvm.loader; + +import com.bruce.homework0409.jvm.util.Util; + +import java.util.Arrays; + +public class ByteCodeIterator { + private byte[] codes; + private int pos = 0; + + public ByteCodeIterator(byte[] codes) { + this.codes = codes; + } + + public byte[] getBytes(int len) { + if (pos + len >= codes.length) { + throw new ArrayIndexOutOfBoundsException(); + } + byte[] array = Arrays.copyOfRange(codes, pos, pos + len); + pos += len; + return array; + } + + 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++] }); + } +} diff --git a/group15/1510_739253131/src/com/bruce/homework0409/jvm/loader/ClassFileLoader.java b/group15/1510_739253131/src/com/bruce/homework0409/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..0b4d6ad870 --- /dev/null +++ b/group15/1510_739253131/src/com/bruce/homework0409/jvm/loader/ClassFileLoader.java @@ -0,0 +1,102 @@ +package com.bruce.homework0409.jvm.loader; + +import com.bruce.homework0409.jvm.clz.ClassFile; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; + +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 { + + private List<String> clzPaths = new ArrayList<String>(); + + 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/1510_739253131/src/com/bruce/homework0409/jvm/loader/ClassFileParser.java b/group15/1510_739253131/src/com/bruce/homework0409/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..0c2d6ef2f1 --- /dev/null +++ b/group15/1510_739253131/src/com/bruce/homework0409/jvm/loader/ClassFileParser.java @@ -0,0 +1,99 @@ +package com.bruce.homework0409.jvm.loader; + +import com.bruce.homework0409.jvm.clz.AccessFlag; +import com.bruce.homework0409.jvm.clz.ClassFile; +import com.bruce.homework0409.jvm.clz.ClassIndex; +import com.bruce.homework0409.jvm.constant.ClassInfo; +import com.bruce.homework0409.jvm.constant.ConstantPool; +import com.bruce.homework0409.jvm.constant.FieldRefInfo; +import com.bruce.homework0409.jvm.constant.MethodRefInfo; +import com.bruce.homework0409.jvm.constant.NameAndTypeInfo; +import com.bruce.homework0409.jvm.constant.NullConstantInfo; +import com.bruce.homework0409.jvm.constant.UTF8Info; + +import java.util.Arrays; + +public class ClassFileParser { + + public ClassFile parse(byte[] codes) { + ClassFile clzFile = new ClassFile(); + ByteCodeIterator iter = new ByteCodeIterator(codes); + String magicNumber = iter.nextU4ToHexString(); + if (!"cafebabe".equalsIgnoreCase(magicNumber)) { + return null; + } + clzFile.setMinorVersion(iter.nextU2ToInt()); + clzFile.setMajorVersion(iter.nextU2ToInt()); + + ConstantPool pool = parseConstantPool(iter); + clzFile.setConstPool(pool); + + AccessFlag flag = parseAccessFlag(iter); + clzFile.setAccessFlag(flag); + + ClassIndex index = parseClassInfex(iter); + clzFile.setClassIndex(index); + return clzFile; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + int flagValue = iter.nextU1ToInt(); + AccessFlag flag = new AccessFlag(flagValue); + return flag; + } + + private ClassIndex parseClassInfex(ByteCodeIterator iter) { + ClassIndex clzIndex = new ClassIndex(); + int thisClassIndex = iter.nextU2ToInt(); + int superClassIndex = iter.nextU2ToInt(); + clzIndex.setThisClassIndex(thisClassIndex); + clzIndex.setSuperClassIndex(superClassIndex); + return clzIndex; + + } + + private ConstantPool parseConstantPool(ByteCodeIterator iter) { + int constantPoolCount = iter.nextU2ToInt(); + ConstantPool pool = new ConstantPool(); + pool.addConstantInfo(new NullConstantInfo()); + for (int i = 1; i < constantPoolCount - 1; i++) { + int tag = iter.nextU1ToInt(); + if (tag == 7) {//class_info + int utf8Index = iter.nextU2ToInt(); + ClassInfo clzInfo = new ClassInfo(pool); + clzInfo.setUtf8Index(utf8Index); + pool.addConstantInfo(clzInfo); + } else if (tag == 1) {//utf8_info + int len = iter.nextU2ToInt(); + byte[] data = iter.getBytes(len); + UTF8Info utf8Info = new UTF8Info(pool); + utf8Info.setValue(Arrays.toString(data)); + pool.addConstantInfo(utf8Info); + } else if (tag == 9) {//fieldref_info + int clzIndex = iter.nextU2ToInt(); + int nameAndTypeIndex = iter.nextU2ToInt(); + FieldRefInfo fieldRefInfo = new FieldRefInfo(pool); + fieldRefInfo.setClassInfoIndex(clzIndex); + fieldRefInfo.setNameAndTypeIndex(nameAndTypeIndex); + pool.addConstantInfo(fieldRefInfo); + } else if (tag == 10) {//methodref_info + int clzIndex = iter.nextU2ToInt(); + int nameAndTypeIndex = iter.nextU2ToInt(); + MethodRefInfo methodRefInfo = new MethodRefInfo(pool); + methodRefInfo.setClassInfoIndex(clzIndex); + methodRefInfo.setNameAndTypeIndex(nameAndTypeIndex); + pool.addConstantInfo(methodRefInfo); + } else if (tag == 12) {//nameAndType_info + int nameIndex = iter.nextU2ToInt(); + int descriptorIndex = iter.nextU2ToInt(); + NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(pool); + nameAndTypeInfo.setIndex1(nameIndex); + nameAndTypeInfo.setIndex2(descriptorIndex); + pool.addConstantInfo(nameAndTypeInfo); + } else { + throw new RuntimeException("The constant "+ tag + " has not been build"); + } + } + return null; + } +} \ No newline at end of file diff --git a/group15/1510_739253131/src/com/bruce/homework0409/jvm/test/ClassFileloaderTest.java b/group15/1510_739253131/src/com/bruce/homework0409/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..a837e0a74b --- /dev/null +++ b/group15/1510_739253131/src/com/bruce/homework0409/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,202 @@ +package com.bruce.homework0409.jvm.test; + +import org.junit.After; +import org.junit.Assert; +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; + + + + + +public class ClassFileloaderTest { + + + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + + static String path1 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\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 { + } + + @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(); + } + + /** + * ---------------------------------------------------------------------- + */ + + + @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("<init>", 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/1510_739253131/src/com/bruce/homework0409/jvm/test/EmployeeV1.java b/group15/1510_739253131/src/com/bruce/homework0409/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..6e3cfdca42 --- /dev/null +++ b/group15/1510_739253131/src/com/bruce/homework0409/jvm/test/EmployeeV1.java @@ -0,0 +1,28 @@ +package com.bruce.homework0409.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/1510_739253131/src/com/bruce/homework0409/jvm/util/Util.java b/group15/1510_739253131/src/com/bruce/homework0409/jvm/util/Util.java new file mode 100644 index 0000000000..f316c1f339 --- /dev/null +++ b/group15/1510_739253131/src/com/bruce/homework0409/jvm/util/Util.java @@ -0,0 +1,24 @@ +package com.bruce.homework0409.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/group15/1510_739253131/src/com/bruce/homework0409/stack/StackUtil.java b/group15/1510_739253131/src/com/bruce/homework0409/stack/StackUtil.java new file mode 100644 index 0000000000..b8db26d2f6 --- /dev/null +++ b/group15/1510_739253131/src/com/bruce/homework0409/stack/StackUtil.java @@ -0,0 +1,120 @@ +package com.bruce.homework0409.stack; + +import java.util.Arrays; +import java.util.LinkedHashMap; +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 Stack reverse(Stack s) { + if (s == null || s.isEmpty()) { + return s; + } + Stack temp = new Stack(); + int size = s.size(); + for (int i = 0; i < size; i++) { + temp.push(s.pop()); + } + return temp; + } + + /** + * 删除栈中的某个元素 注意:只能使用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(); + int size = s.size(); + for (int i = 0; i < size; i++) { + Object pop = s.pop(); + if (Objects.equals(o, pop)) { + continue; + } + temp.push(pop); + } + for (int j = 0; j < size; j++) { + if(!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; + } + Object[] array = new Object[s.size()]; + Object[] result = new Object[len]; + Stack copy = new Stack(); + int size = s.size(); + for (int i = 0; i < size; i++) { + array[i] = s.pop(); + } + for (int j = array.length - 1; j >= 0; j--) { + s.push(array[j]); + if (array.length-1-j < len) { + result[array.length-1-j] = array[j]; + } + } + 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 == null || s.trim().length() < 2) { + return false; + } + char[] array = s.toCharArray(); + StringBuffer sb = new StringBuffer("#"); + //从原字符串中提取出“()[]{}”这几种字符,顺序与在原字符串中出现的顺序相同 + for (int i = 0; i < array.length; i++) { + if (array[i] == '(' || array[i] == ')' || array[i] == '[' || array[i] == ']' + || array[i] == '{' || array[i] == '}') { + sb.append(array[i]); + } + } + if (sb.length() % 2 == 0) { + return false; + } + //将得到的新的字符串拆分为字符数组,根据数组下标判断应该成对出现的括号 + String str = sb.toString(); + char[] chars = str.toCharArray(); + LinkedHashMap<Character, Integer> map = new LinkedHashMap(); + for (int i = 1; i < chars.length; i++) { + if (map.containsKey(chars[i])) { + map.put(chars[i], map.get(chars[i]) + i); + } else { + map.put(chars[i], i); + } + } + if (map.containsKey('(') && !map.containsKey(')') || map.containsKey('[') && !map.containsKey(']') + || map.containsKey('{') && !map.containsKey('}')) { + return false; + } + int parentheses = map.get('(') + map.get(')'); + int bracket = map.get('[') + map.get(']'); + int brace = map.get('{') + map.get('}'); + return parentheses == bracket && bracket == brace; + } +} diff --git a/group15/1510_739253131/src/com/bruce/homework0409/stack/StackUtilTest.java b/group15/1510_739253131/src/com/bruce/homework0409/stack/StackUtilTest.java new file mode 100644 index 0000000000..e66a6e98aa --- /dev/null +++ b/group15/1510_739253131/src/com/bruce/homework0409/stack/StackUtilTest.java @@ -0,0 +1,55 @@ +package com.bruce.homework0409.stack; + +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.Stack; + +/** + * Created by Bruce.Jiao on 2017/4/8. + */ +public class StackUtilTest { + + private Stack<Integer> stack; + + @Before + public void create() { + stack = new Stack<>(); + stack.push(3); + stack.push(5); + stack.push(6); + stack.push(9); + stack.push(0); + } + + @Test + public void testReverse() { + System.out.println("original:" + stack.toString()); + stack = StackUtil.reverse(stack); + System.out.println("after reverse:" + stack.toString()); + } + + @Test + public void testRemove() { + System.out.println("original:" + stack.toString()); + StackUtil.remove(stack, 5); + System.out.println("after remove 5 :" + stack.toString()); + } + + @Test + public void testGetTop() { + System.out.println("original:" + stack.toString()); + Object[] top = StackUtil.getTop(stack, 3); + System.out.println("get top 3 :" + Arrays.toString(top)); + System.out.println("after get top :" + stack.toString()); + } + + @Test + public void test() { + System.out.println("({[e({d})f]}) : " + StackUtil.isValidPairs("({[e({d})f]})")); + System.out.println("(d)" + StackUtil.isValidPairs("(d)")); + System.out.println("([b{x]y})" + StackUtil.isValidPairs("([b{x]y})")); + } +} From e55ba17664068862a25cd737c48dfaf46d9e51c6 Mon Sep 17 00:00:00 2001 From: xuxiqoqing <xu0822@gmail.com> Date: Mon, 10 Apr 2017 21:56:57 +0800 Subject: [PATCH 202/287] L5 --- .../L5/datastructure/less5/Stack.java | 39 ++++ .../L5/datastructure/less5/StackUtil.java | 120 +++++++++++ group13/2729382520/L5/jvm/clz/AccessFlag.java | 26 +++ group13/2729382520/L5/jvm/clz/ClassFile.java | 80 ++++++++ group13/2729382520/L5/jvm/clz/ClassIndex.java | 22 ++ .../2729382520/L5/jvm/clz/ConstantPool.java | 35 ++++ .../2729382520/L5/jvm/constant/ClassInfo.java | 30 +++ .../L5/jvm/constant/ConstantInfo.java | 42 ++++ .../L5/jvm/constant/FieldRefInfo.java | 60 ++++++ .../L5/jvm/constant/MethodRefInfo.java | 60 ++++++ .../L5/jvm/constant/NameAndTypeInfo.java | 51 +++++ .../L5/jvm/constant/NullConstantInfo.java | 14 ++ .../L5/jvm/constant/StringInfo.java | 30 +++ .../2729382520/L5/jvm/constant/UTF8Info.java | 40 ++++ .../L5/jvm/loader/ByteCodeIterator.java | 41 ++++ .../L5/jvm/loader/ClassFileLoader.java | 108 ++++++++++ .../L5/jvm/loader/ClassFileParser.java | 99 +++++++++ .../L5/jvm/test/ClassFileloaderTest.java | 188 ++++++++++++++++++ .../2729382520/L5/jvm/test/EmployeeV1.java | 29 +++ group13/2729382520/L5/jvm/util/Util.java | 23 +++ 20 files changed, 1137 insertions(+) create mode 100644 group13/2729382520/L5/datastructure/less5/Stack.java create mode 100644 group13/2729382520/L5/datastructure/less5/StackUtil.java create mode 100755 group13/2729382520/L5/jvm/clz/AccessFlag.java create mode 100755 group13/2729382520/L5/jvm/clz/ClassFile.java create mode 100755 group13/2729382520/L5/jvm/clz/ClassIndex.java create mode 100755 group13/2729382520/L5/jvm/clz/ConstantPool.java create mode 100755 group13/2729382520/L5/jvm/constant/ClassInfo.java create mode 100755 group13/2729382520/L5/jvm/constant/ConstantInfo.java create mode 100755 group13/2729382520/L5/jvm/constant/FieldRefInfo.java create mode 100755 group13/2729382520/L5/jvm/constant/MethodRefInfo.java create mode 100755 group13/2729382520/L5/jvm/constant/NameAndTypeInfo.java create mode 100755 group13/2729382520/L5/jvm/constant/NullConstantInfo.java create mode 100755 group13/2729382520/L5/jvm/constant/StringInfo.java create mode 100755 group13/2729382520/L5/jvm/constant/UTF8Info.java create mode 100644 group13/2729382520/L5/jvm/loader/ByteCodeIterator.java create mode 100755 group13/2729382520/L5/jvm/loader/ClassFileLoader.java create mode 100644 group13/2729382520/L5/jvm/loader/ClassFileParser.java create mode 100755 group13/2729382520/L5/jvm/test/ClassFileloaderTest.java create mode 100755 group13/2729382520/L5/jvm/test/EmployeeV1.java create mode 100644 group13/2729382520/L5/jvm/util/Util.java diff --git a/group13/2729382520/L5/datastructure/less5/Stack.java b/group13/2729382520/L5/datastructure/less5/Stack.java new file mode 100644 index 0000000000..2bf939fd7c --- /dev/null +++ b/group13/2729382520/L5/datastructure/less5/Stack.java @@ -0,0 +1,39 @@ +package io.github.vxzh.datastructure.less5; + +import java.util.ArrayList; + +public class Stack { + + private ArrayList elementData; + + public Stack() { + this.elementData = new ArrayList(); + } + + public int size() { + return elementData.size(); + } + + public boolean isEmpty() { + return elementData.size() == 0; + } + + public void push(Object o) { + elementData.add(o); + } + + public Object pop() { + if (isEmpty()) + throw new RuntimeException("EmptyStackException"); + Object obj = peek(); + elementData.remove(elementData.size() - 1); + return obj; + } + + public Object peek() { + if (isEmpty()) + throw new RuntimeException("EmptyStackException"); + return elementData.get(elementData.size() - 1); + } + +} \ No newline at end of file diff --git a/group13/2729382520/L5/datastructure/less5/StackUtil.java b/group13/2729382520/L5/datastructure/less5/StackUtil.java new file mode 100644 index 0000000000..c2232eeb39 --- /dev/null +++ b/group13/2729382520/L5/datastructure/less5/StackUtil.java @@ -0,0 +1,120 @@ +package io.github.vxzh.datastructure.less5; + + +public class StackUtil { + + public static void main(String[] args) { + String s = "(9[O{er}P]0)"; + System.out.println(isValidPairs(s)); + } + + /** + * 假设栈中的元素是Integer, 从栈顶到栈底是 : 5,4,3,2,1 调用该方法后, 元素次序变为: 1,2,3,4,5 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + */ + public static void reverse(Stack s) { + Stack stack = s; + s = new Stack(); + while (!stack.isEmpty()) { + s.push(stack.pop()); + } + } + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s, Object o) { + Stack stack = s; + s = new Stack(); + while (!stack.isEmpty()) { + Object obj = stack.pop(); + if (obj != o) { + s.push(obj); + } + } + + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param len + * @return + */ + public static Object[] getTop(Stack s, int len) { + if (len > s.size()) { + Object[] arr = new Object[s.size()]; + int i = 0; + while (!s.isEmpty()) { + arr[i] = s.pop(); + i++; + } + for (int j = 0; j < arr.length; j++) { + s.push(arr[j]); + } + return arr; + } else { + Object[] arr = new Object[len]; + int i = 0; + while (!s.isEmpty()) { + arr[i] = s.pop(); + i++; + } + for (int j = 0; j < arr.length; j++) { + s.push(arr[j]); + } + 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 st1 = new Stack(); + Stack st2 = new Stack(); + for (int i = 0; i < arr.length; i++) { + st1.push(arr[i]); + } + for (int i = arr.length - 1; i >= 0; i--) { + st2.push(arr[i]); + } + + while (!st1.isEmpty()) { + + char ch1 = (char) st1.pop(); + char ch2 = (char) st2.pop(); + switch (ch1) { + case '{': + if (ch2 != '}') { + return false; + } + break; + case '[': + if (ch2 != ']') { + return false; + } + break; + case '(': + if (ch2 != ')') { + return false; + } + break; + } + } + + return true; + } + + +} \ No newline at end of file diff --git a/group13/2729382520/L5/jvm/clz/AccessFlag.java b/group13/2729382520/L5/jvm/clz/AccessFlag.java new file mode 100755 index 0000000000..4c3a3c8900 --- /dev/null +++ b/group13/2729382520/L5/jvm/clz/AccessFlag.java @@ -0,0 +1,26 @@ +package io.github.vxzh.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/group13/2729382520/L5/jvm/clz/ClassFile.java b/group13/2729382520/L5/jvm/clz/ClassFile.java new file mode 100755 index 0000000000..1d7011545b --- /dev/null +++ b/group13/2729382520/L5/jvm/clz/ClassFile.java @@ -0,0 +1,80 @@ +package io.github.vxzh.jvm.clz; + +import io.github.vxzh.jvm.constant.ClassInfo; + +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/group13/2729382520/L5/jvm/clz/ClassIndex.java b/group13/2729382520/L5/jvm/clz/ClassIndex.java new file mode 100755 index 0000000000..4500959430 --- /dev/null +++ b/group13/2729382520/L5/jvm/clz/ClassIndex.java @@ -0,0 +1,22 @@ +package io.github.vxzh.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/group13/2729382520/L5/jvm/clz/ConstantPool.java b/group13/2729382520/L5/jvm/clz/ConstantPool.java new file mode 100755 index 0000000000..b96e330020 --- /dev/null +++ b/group13/2729382520/L5/jvm/clz/ConstantPool.java @@ -0,0 +1,35 @@ +package io.github.vxzh.jvm.clz; + +import io.github.vxzh.jvm.constant.ConstantInfo; +import io.github.vxzh.jvm.constant.UTF8Info; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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/group13/2729382520/L5/jvm/constant/ClassInfo.java b/group13/2729382520/L5/jvm/constant/ClassInfo.java new file mode 100755 index 0000000000..c9586ee16c --- /dev/null +++ b/group13/2729382520/L5/jvm/constant/ClassInfo.java @@ -0,0 +1,30 @@ +package io.github.vxzh.jvm.constant; + +import io.github.vxzh.jvm.clz.ConstantPool; + +public class ClassInfo extends ConstantInfo { + private int tag = ConstantInfo.CONSTANT_CLASS_INFO; + private int nameIndex; + + public ClassInfo(ConstantPool pool) { + super(pool); + } + + public int getNameIndex() { + return nameIndex; + } + + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + + public int getTag() { + return tag; + } + + public String getClassName() { + int index = getNameIndex(); + UTF8Info utf8Info = (UTF8Info) constantPool.getConstantInfo(index); + return utf8Info.getValue(); + } +} diff --git a/group13/2729382520/L5/jvm/constant/ConstantInfo.java b/group13/2729382520/L5/jvm/constant/ConstantInfo.java new file mode 100755 index 0000000000..0f3d63685c --- /dev/null +++ b/group13/2729382520/L5/jvm/constant/ConstantInfo.java @@ -0,0 +1,42 @@ +package io.github.vxzh.jvm.constant; + +import io.github.vxzh.jvm.clz.ConstantPool; + +public abstract class ConstantInfo { + + public static final int CONSTANT_UTF8_INFO = 1;// + public static final int CONSTANT_INTEGER_INFO = 3; + public static final int CONSTANT_FLOAT_INFO = 4;// + public static final int CONSTANT_LONG_INFO = 5; + public static final int CONSTANT_DOUBLE_INFO = 6; + public static final int CONSTANT_CLASS_INFO = 7;// + public static final int CONSTANT_STRING_INFO = 8;// + public static final int CONSTANT_FIELDREF_INFO = 9;// + public static final int CONSTANT_METHODREF_INFO = 10;// + public static final int CONSTANT_INTERFACEMETHODREF_INFO = 11; + public static final int CONSTANT_NAMEANDTYPE_INFO = 12;// + public static final int CONSTANT_METHODHANDLE_INFO = 15; + public static final int CONSTANT_METHODTYPE_INFO = 16; + public static final int CONSTANT_INVOKEDYNAMIC_INFO = 18; + + protected ConstantPool constantPool; + + public ConstantInfo() { + + } + + public ConstantInfo(ConstantPool pool) { + this.constantPool = pool; + } + + public abstract int getTag(); + + public ConstantPool getConstantPool() { + return constantPool; + } + + public ConstantInfo getConstantInfo(int index) { + return this.constantPool.getConstantInfo(index); + } + +} diff --git a/group13/2729382520/L5/jvm/constant/FieldRefInfo.java b/group13/2729382520/L5/jvm/constant/FieldRefInfo.java new file mode 100755 index 0000000000..f39bc87b72 --- /dev/null +++ b/group13/2729382520/L5/jvm/constant/FieldRefInfo.java @@ -0,0 +1,60 @@ +package io.github.vxzh.jvm.constant; + +import io.github.vxzh.jvm.clz.ConstantPool; + +public class FieldRefInfo extends ConstantInfo { + private int tag = ConstantInfo.CONSTANT_FIELDREF_INFO; + private int classInfoIndex; + private int nameAndTypeIndex; + + public FieldRefInfo(ConstantPool pool) { + super(pool); + } + + public int getTag() { + return tag; + } + + 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.getNameIndex()); + + 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/group13/2729382520/L5/jvm/constant/MethodRefInfo.java b/group13/2729382520/L5/jvm/constant/MethodRefInfo.java new file mode 100755 index 0000000000..46535b7769 --- /dev/null +++ b/group13/2729382520/L5/jvm/constant/MethodRefInfo.java @@ -0,0 +1,60 @@ +package io.github.vxzh.jvm.constant; + +import io.github.vxzh.jvm.clz.ConstantPool; + +public class MethodRefInfo extends ConstantInfo { + + private int tag = ConstantInfo.CONSTANT_METHODREF_INFO; + + private int classInfoIndex; + private int nameAndTypeIndex; + + public MethodRefInfo(ConstantPool pool) { + super(pool); + } + + public int getTag() { + return tag; + } + + 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/group13/2729382520/L5/jvm/constant/NameAndTypeInfo.java b/group13/2729382520/L5/jvm/constant/NameAndTypeInfo.java new file mode 100755 index 0000000000..a081902eac --- /dev/null +++ b/group13/2729382520/L5/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,51 @@ +package io.github.vxzh.jvm.constant; + +import io.github.vxzh.jvm.clz.ConstantPool; + +public class NameAndTypeInfo extends ConstantInfo { + public int tag = ConstantInfo.CONSTANT_NAMEANDTYPE_INFO; + + private int nameIndex; + private int descriptorIndex; + + public NameAndTypeInfo(ConstantPool pool) { + super(pool); + } + + 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; + } + + public int getTag() { + return tag; + } + + + public String getName() { + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info1 = (UTF8Info) pool.getConstantInfo(nameIndex); + return utf8Info1.getValue(); + } + + public String getTypeInfo() { + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info2 = (UTF8Info) pool.getConstantInfo(descriptorIndex); + return utf8Info2.getValue(); + } + + public String toString() { + return "(" + getName() + "," + getTypeInfo() + ")"; + } +} diff --git a/group13/2729382520/L5/jvm/constant/NullConstantInfo.java b/group13/2729382520/L5/jvm/constant/NullConstantInfo.java new file mode 100755 index 0000000000..1d1d8394f9 --- /dev/null +++ b/group13/2729382520/L5/jvm/constant/NullConstantInfo.java @@ -0,0 +1,14 @@ +package io.github.vxzh.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo() { + + } + + @Override + public int getTag() { + return -1; + } + +} diff --git a/group13/2729382520/L5/jvm/constant/StringInfo.java b/group13/2729382520/L5/jvm/constant/StringInfo.java new file mode 100755 index 0000000000..e5175eed4a --- /dev/null +++ b/group13/2729382520/L5/jvm/constant/StringInfo.java @@ -0,0 +1,30 @@ +package io.github.vxzh.jvm.constant; + +import io.github.vxzh.jvm.clz.ConstantPool; + +public class StringInfo extends ConstantInfo { + private int tag = ConstantInfo.CONSTANT_STRING_INFO; + private int index; + + public StringInfo(ConstantPool pool) { + super(pool); + } + + public int getTag() { + return tag; + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + + + public String toString() { + return this.getConstantPool().getUTF8String(index); + } + +} diff --git a/group13/2729382520/L5/jvm/constant/UTF8Info.java b/group13/2729382520/L5/jvm/constant/UTF8Info.java new file mode 100755 index 0000000000..e1fb81006b --- /dev/null +++ b/group13/2729382520/L5/jvm/constant/UTF8Info.java @@ -0,0 +1,40 @@ +package io.github.vxzh.jvm.constant; + +import io.github.vxzh.jvm.clz.ConstantPool; + +public class UTF8Info extends ConstantInfo { + private int tag = ConstantInfo.CONSTANT_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 getTag() { + return tag; + } + + @Override + public String toString() { + return "UTF8Info [tag=" + tag + ", length=" + length + ", value=" + value + ")]"; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + +} diff --git a/group13/2729382520/L5/jvm/loader/ByteCodeIterator.java b/group13/2729382520/L5/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..2b3fd9b896 --- /dev/null +++ b/group13/2729382520/L5/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,41 @@ +package io.github.vxzh.jvm.loader; + +import io.github.vxzh.jvm.util.Util; + +import java.util.Arrays; + +public class ByteCodeIterator { + private int pos = 0; + private byte[] code; + + public ByteCodeIterator(byte[] code) { + this.code = code; + } + + public String nextU4ToHexString() { + byte[] bytes = nextBytes(4); + return Util.byteToHexString(bytes); + } + + public int nextU2ToInt() { + byte[] bytes = nextBytes(2); + return Util.byteToInt(bytes); + } + + public int nextU1ToInt() { + byte[] bytes = nextBytes(1); + return Util.byteToInt(bytes); + } + + public String nextBytesToString(int len) { + byte[] bytes = nextBytes(len); + return new String(bytes); + } + + private byte[] nextBytes(int len) { + byte[] bytes = Arrays.copyOfRange(code, pos, pos+len); + pos += len; + return bytes; + } + +} \ No newline at end of file diff --git a/group13/2729382520/L5/jvm/loader/ClassFileLoader.java b/group13/2729382520/L5/jvm/loader/ClassFileLoader.java new file mode 100755 index 0000000000..c10a6ad295 --- /dev/null +++ b/group13/2729382520/L5/jvm/loader/ClassFileLoader.java @@ -0,0 +1,108 @@ +package io.github.vxzh.jvm.loader; + +import io.github.vxzh.jvm.clz.ClassFile; +import org.apache.commons.io.IOUtils; + +import java.io.*; +import java.util.ArrayList; +import java.util.List; + + +public class ClassFileLoader { + + private static final int BUFFER_MAX_SIZE = 1024; + private List<String> clzPaths = new ArrayList<String>(); + + public byte[] readBinaryCode(String className) { + + className = className.replaceAll("\\.", "/"); + File file = findFile(className); + if (file == null) { + return new byte[0]; + } + + FileInputStream fis = null; + ByteArrayOutputStream bos = null; + try { + fis = new FileInputStream(file); + bos = new ByteArrayOutputStream(); + byte buffer[] = new byte[BUFFER_MAX_SIZE]; + int len = -1; + while ((len = fis.read(buffer)) != -1) { + bos.write(buffer, 0, len); + } + return bos.toByteArray(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (fis != null) + fis.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + try { + if (bos != null) + bos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + return null; + } + + public void addClassPath(String path) { + if (this.clzPaths.contains(path)) { + return; + } + clzPaths.add(path); + } + + public String getClassPath() { + + StringBuilder builder = new StringBuilder(); + for (String path : clzPaths) { + builder.append(path).append(";"); + } + + return builder.toString().substring(0, builder.toString().length() - 1); + } + + private File findFile(String className) { + for (String path : clzPaths) { + String filePath = path + "/" + className + ".class"; + File file = new File(filePath); + if (file.exists()) { + return file; + } + } + 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 ClassFile loadClass(String className) { + byte[] codes = this.readBinaryCode(className); + ClassFileParser parser = new ClassFileParser(); + return parser.parse(codes); + + } + + +} \ No newline at end of file diff --git a/group13/2729382520/L5/jvm/loader/ClassFileParser.java b/group13/2729382520/L5/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..378d1b68e8 --- /dev/null +++ b/group13/2729382520/L5/jvm/loader/ClassFileParser.java @@ -0,0 +1,99 @@ +package io.github.vxzh.jvm.loader; + +import io.github.vxzh.jvm.clz.AccessFlag; +import io.github.vxzh.jvm.clz.ClassFile; +import io.github.vxzh.jvm.clz.ClassIndex; +import io.github.vxzh.jvm.clz.ConstantPool; +import io.github.vxzh.jvm.constant.*; + + +public class ClassFileParser { + + public ClassFile parse(byte[] codes) { + + ByteCodeIterator byteCodeIterator = new ByteCodeIterator(codes); + String magicNumber = byteCodeIterator.nextU4ToHexString(); + if (!"cafebabe".equals(magicNumber)) + throw new RuntimeException("This is not a Java Class file!"); + + ClassFile classFile = new ClassFile(); + int minorVersion = byteCodeIterator.nextU2ToInt(); + classFile.setMinorVersion(minorVersion); + int majorVersion = byteCodeIterator.nextU2ToInt(); + classFile.setMajorVersion(majorVersion); + + classFile.setConstPool(this.parseConstantPool(byteCodeIterator)); + classFile.setAccessFlag(this.parseAccessFlag(byteCodeIterator)); + classFile.setClassIndex(this.parseClassInfex(byteCodeIterator)); + + return classFile; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iterator) { + return new AccessFlag(iterator.nextU2ToInt()); + } + + private ClassIndex parseClassInfex(ByteCodeIterator iterator) { + ClassIndex classIndex = new ClassIndex(); + classIndex.setThisClassIndex(iterator.nextU2ToInt()); + classIndex.setSuperClassIndex(iterator.nextU2ToInt()); + return classIndex; + } + + private ConstantPool parseConstantPool(ByteCodeIterator iterator) { + + int constantCount = iterator.nextU2ToInt(); + ConstantPool constantPool = new ConstantPool(); + constantPool.addConstantInfo(new NullConstantInfo()); + for (int i = 0; i < constantCount; i++) { + int tag = iterator.nextU1ToInt(); + switch (tag) { + case ConstantInfo.CONSTANT_CLASS_INFO: + ClassInfo classInfo = new ClassInfo(constantPool); + classInfo.setNameIndex(iterator.nextU2ToInt()); + constantPool.addConstantInfo(classInfo); + System.out.println("classInfo " + classInfo.getNameIndex()); + break; + case ConstantInfo.CONSTANT_UTF8_INFO: + UTF8Info utf8Info = new UTF8Info(constantPool); + utf8Info.setLength(iterator.nextU2ToInt()); + utf8Info.setValue(iterator.nextBytesToString(utf8Info.getLength())); + constantPool.addConstantInfo(utf8Info); + System.out.println("utf-8 " + utf8Info.getValue()); + break; + case ConstantInfo.CONSTANT_METHODREF_INFO: + MethodRefInfo methodRefInfo = new MethodRefInfo(constantPool); + methodRefInfo.setClassInfoIndex(iterator.nextU2ToInt()); + methodRefInfo.setNameAndTypeIndex(iterator.nextU2ToInt()); + constantPool.addConstantInfo(methodRefInfo); + System.out.println("method ref " + methodRefInfo.getClassInfoIndex() + " " + methodRefInfo.getNameAndTypeIndex()); + break; + case ConstantInfo.CONSTANT_NAMEANDTYPE_INFO: + NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(constantPool); + nameAndTypeInfo.setNameIndex(iterator.nextU2ToInt()); + nameAndTypeInfo.setDescriptorIndex(iterator.nextU2ToInt()); + constantPool.addConstantInfo(nameAndTypeInfo); + System.out.println("name and type " + nameAndTypeInfo.getNameIndex() + " " + nameAndTypeInfo.getDescriptorIndex()); + break; + case ConstantInfo.CONSTANT_FIELDREF_INFO: + FieldRefInfo fieldRefInfo = new FieldRefInfo(constantPool); + fieldRefInfo.setClassInfoIndex(iterator.nextU2ToInt()); + fieldRefInfo.setNameAndTypeIndex(iterator.nextU2ToInt()); + constantPool.addConstantInfo(fieldRefInfo); + System.out.println("field ref " + fieldRefInfo.getClassInfoIndex() + " " + fieldRefInfo.getNameAndTypeIndex()); + break; + case ConstantInfo.CONSTANT_STRING_INFO: + StringInfo stringInfo = new StringInfo(constantPool); + stringInfo.setIndex(iterator.nextU2ToInt()); + constantPool.addConstantInfo(stringInfo); + System.out.println("string " + stringInfo.getIndex()); + break; + default: + //throw new RuntimeException("the constant Pool tag "+tag+" has not been implement yet!"); + } + } + return constantPool; + } + + +} diff --git a/group13/2729382520/L5/jvm/test/ClassFileloaderTest.java b/group13/2729382520/L5/jvm/test/ClassFileloaderTest.java new file mode 100755 index 0000000000..9223e0f7ad --- /dev/null +++ b/group13/2729382520/L5/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,188 @@ +package io.github.vxzh.jvm.test; + +import io.github.vxzh.jvm.clz.ClassFile; +import io.github.vxzh.jvm.clz.ClassIndex; +import io.github.vxzh.jvm.clz.ConstantPool; +import io.github.vxzh.jvm.constant.*; +import io.github.vxzh.jvm.loader.ClassFileLoader; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class ClassFileloaderTest { + + + private static final String FULL_QUALIFIED_CLASS_NAME = "io/github/vxzh/jvm/test/EmployeeV1.java"; + static String path1 = "/Users/xuxiaoqing/Workspace/test"; + static String path2 = "/Users/xuxiaoqing/Documents/demo"; + + static ClassFile clzFile = null; + + static { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "io.github.vxzh.jvm.test.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 = "io.github.vxzh.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 = "io.github.vxzh.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(); + } + + @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.getNameIndex()); + + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(2); + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, utf8Info.getValue()); + } + { + ClassInfo clzInfo = (ClassInfo) pool.getConstantInfo(3); + Assert.assertEquals(4, clzInfo.getNameIndex()); + + 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("<init>", 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()); + } + + +} \ No newline at end of file diff --git a/group13/2729382520/L5/jvm/test/EmployeeV1.java b/group13/2729382520/L5/jvm/test/EmployeeV1.java new file mode 100755 index 0000000000..87e05ff033 --- /dev/null +++ b/group13/2729382520/L5/jvm/test/EmployeeV1.java @@ -0,0 +1,29 @@ +package io.github.vxzh.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/group13/2729382520/L5/jvm/util/Util.java b/group13/2729382520/L5/jvm/util/Util.java new file mode 100644 index 0000000000..9a659ef3eb --- /dev/null +++ b/group13/2729382520/L5/jvm/util/Util.java @@ -0,0 +1,23 @@ +package io.github.vxzh.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(); + } +} \ No newline at end of file From 4bd9c3cfe757e6775528b988c8c9868cd284e734 Mon Sep 17 00:00:00 2001 From: brucejiao1 <jiao.xiaopan@163.com> Date: Mon, 10 Apr 2017 21:57:59 +0800 Subject: [PATCH 203/287] update some code --- .../homework0409/jvm/loader/ByteCodeIterator.java | 11 +++++++++++ .../homework0409/jvm/loader/ClassFileParser.java | 6 ++++++ 2 files changed, 17 insertions(+) diff --git a/group15/1510_739253131/src/com/bruce/homework0409/jvm/loader/ByteCodeIterator.java b/group15/1510_739253131/src/com/bruce/homework0409/jvm/loader/ByteCodeIterator.java index d03dc786dd..f33ae3a203 100644 --- a/group15/1510_739253131/src/com/bruce/homework0409/jvm/loader/ByteCodeIterator.java +++ b/group15/1510_739253131/src/com/bruce/homework0409/jvm/loader/ByteCodeIterator.java @@ -36,4 +36,15 @@ public int nextU4ToInt() { public String nextU4ToHexString() { return Util.byteToHexString(new byte[] { codes[pos++], codes[pos++], codes[pos++], codes[pos++] }); } + + public String nextUxToHexString(int len) { + if (len < 1) { + return null; + } + byte[] array = new byte[len]; + for (int i = 0; i < len; i++) { + array[i] = codes[pos++]; + } + return Util.byteToHexString(array); + } } diff --git a/group15/1510_739253131/src/com/bruce/homework0409/jvm/loader/ClassFileParser.java b/group15/1510_739253131/src/com/bruce/homework0409/jvm/loader/ClassFileParser.java index 0c2d6ef2f1..e3a08e8268 100644 --- a/group15/1510_739253131/src/com/bruce/homework0409/jvm/loader/ClassFileParser.java +++ b/group15/1510_739253131/src/com/bruce/homework0409/jvm/loader/ClassFileParser.java @@ -9,6 +9,7 @@ import com.bruce.homework0409.jvm.constant.MethodRefInfo; import com.bruce.homework0409.jvm.constant.NameAndTypeInfo; import com.bruce.homework0409.jvm.constant.NullConstantInfo; +import com.bruce.homework0409.jvm.constant.StringInfo; import com.bruce.homework0409.jvm.constant.UTF8Info; import java.util.Arrays; @@ -90,6 +91,11 @@ private ConstantPool parseConstantPool(ByteCodeIterator iter) { nameAndTypeInfo.setIndex1(nameIndex); nameAndTypeInfo.setIndex2(descriptorIndex); pool.addConstantInfo(nameAndTypeInfo); + } else if (tag == 8) {//string_info + int stringIndex = iter.nextU2ToInt(); + StringInfo stringInfo = new StringInfo(pool); + stringInfo.setIndex(stringIndex); + pool.addConstantInfo(stringInfo); } else { throw new RuntimeException("The constant "+ tag + " has not been build"); } From e17c53f80be866aee78c0ad845c2045b5f8db7d3 Mon Sep 17 00:00:00 2001 From: maishihang <446031103@qq.com> Date: Mon, 10 Apr 2017 22:02:32 +0800 Subject: [PATCH 204/287] compete jvm 2weekwork --- .../com/datastructure/stack/StackUtil.java | 74 ++++++++++++++++++- 1 file changed, 70 insertions(+), 4 deletions(-) diff --git a/group12/446031103/src/com/datastructure/stack/StackUtil.java b/group12/446031103/src/com/datastructure/stack/StackUtil.java index 64c3bb07e7..7cab99ede3 100644 --- a/group12/446031103/src/com/datastructure/stack/StackUtil.java +++ b/group12/446031103/src/com/datastructure/stack/StackUtil.java @@ -1,4 +1,6 @@ package com.datastructure.stack; +import java.util.Objects; +import java.util.Stack; public class StackUtil { /** @@ -6,7 +8,11 @@ public class StackUtil { * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 */ public static void reverse(Stack s) { - + Stack temp = new Stack(); + while(!s.isEmpty()){ + temp.push(s.pop()); + } + s = temp; } /** @@ -15,7 +21,17 @@ public static void reverse(Stack s) { * @param o */ public static void remove(Stack s,Object o) { - + Stack temp = new Stack(); + while(!s.isEmpty()){ + Object result=s.pop(); + if(Objects.equals(result, o)){ + continue; + } + temp.push(result); + } + while(!temp.isEmpty()){ + s.push(temp.pop()); + } } /** @@ -25,7 +41,17 @@ public static void remove(Stack s,Object o) { * @return */ public static Object[] getTop(Stack s,int len) { - return null; + Object [] obj= new Object[len] ; + Stack temp = new Stack(); + for (int i = 0; i <len; i++) { + Object result=s.pop(); + obj[i] = result; + temp.push(result); + } + while(!temp.isEmpty()){ + s.push(temp.pop()); + } + return obj; } /** * 字符串s 可能包含这些字符: ( ) [ ] { }, a,b,c... x,yz @@ -36,6 +62,46 @@ public static Object[] getTop(Stack s,int len) { * @return */ public static boolean isValidPairs(String s){ - return false; + Stack temp1 = new Stack(); + Stack temp2 = new Stack(); + char [] c = s.toCharArray(); + int clength = c.length; + if(clength%2==0){ + for (int i = 0; i < clength; i++) { + if(i<clength/2){ + temp1.push(c[i]); + }else{ + temp2.push(c[i]); + } + } + }else{ + char result=c[clength/2+1]; + if(contain(result)){ + return false; + }; + for (int i = 0; i < clength; i++) { + if(i<clength/2){ + temp1.push(c[i]); + }else{ + if(i==clength/2-1){ + continue; + } + temp2.push(c[i]); + } + } + } + StackUtil.reverse(temp2); + while(!temp1.isEmpty()){ + if(Objects.equals(temp1.pop(), temp2.pop())||contain(temp1.pop())||contain(temp2.pop())){ + return false; + } + } + return true; + } + + private static boolean contain(Object object){ + return Objects.equals(object, '(')||Objects.equals(object, ')')|| + Objects.equals(object, '[')||Objects.equals(object, ']')|| + Objects.equals(object, '{')||Objects.equals(object, '}'); } } From 835b35677aebeac317a69988f766104d0b799743 Mon Sep 17 00:00:00 2001 From: sdnb <xgct0505@qq.com> Date: Mon, 10 Apr 2017 23:25:03 +0800 Subject: [PATCH 205/287] =?UTF-8?q?=E7=AC=AC=E4=BA=94=E5=91=A8=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A?= 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 | 76 +++++++++++ .../com/coderising/jvm/clz/ClassIndex.java | 19 +++ .../coderising/jvm/constant/ClassInfo.java | 24 ++++ .../coderising/jvm/constant/ConstantInfo.java | 29 +++++ .../coderising/jvm/constant/ConstantPool.java | 36 +++++ .../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 | 52 ++++++++ .../jvm/loader/ClassFileLoader.java | 53 +++++--- .../jvm/loader/ClassFileParser.java | 103 +++++++++++++++ .../src/com/coderising/jvm/util/Util.java | 40 ++++++ .../src/main/java/com/coding/weak1/Stack.java | 14 ++ .../com/coding/week5/stack/StackUtil.java | 111 ++++++++++++++++ .../mini_jvm/test/ClassFileloaderTest.java | 123 +++++++++++++++--- .../com/coding/week5/stack/StackUtilTest.java | 56 ++++++++ 20 files changed, 945 insertions(+), 41 deletions(-) create mode 100644 group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/clz/AccessFlag.java create mode 100644 group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/clz/ClassFile.java create mode 100644 group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/clz/ClassIndex.java create mode 100644 group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/ClassInfo.java create mode 100644 group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/ConstantInfo.java create mode 100644 group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/ConstantPool.java create mode 100644 group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/FieldRefInfo.java create mode 100644 group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/MethodRefInfo.java create mode 100644 group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/NameAndTypeInfo.java create mode 100644 group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/NullConstantInfo.java create mode 100644 group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/StringInfo.java create mode 100644 group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/UTF8Info.java create mode 100644 group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java create mode 100644 group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/loader/ClassFileParser.java create mode 100644 group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/util/Util.java create mode 100644 group24/494800949/src/main/java/com/coding/week5/stack/StackUtil.java create mode 100644 group24/494800949/src/test/java/com/coding/week5/stack/StackUtilTest.java diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/clz/AccessFlag.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..0dedb245ee --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/clz/AccessFlag.java @@ -0,0 +1,25 @@ +package com.coding.mini_jvm.src.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/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/clz/ClassFile.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..0d2525e416 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/clz/ClassFile.java @@ -0,0 +1,76 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.clz; + + +import com.coding.mini_jvm.src.com.coderising.jvm.constant.ClassInfo; +import com.coding.mini_jvm.src.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/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/clz/ClassIndex.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..4dc110fe5f --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/clz/ClassIndex.java @@ -0,0 +1,19 @@ +package com.coding.mini_jvm.src.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/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/ClassInfo.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..227bb010a1 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/ClassInfo.java @@ -0,0 +1,24 @@ +package com.coding.mini_jvm.src.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/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/ConstantInfo.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..e7c849ca59 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/ConstantInfo.java @@ -0,0 +1,29 @@ +package com.coding.mini_jvm.src.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/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/ConstantPool.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..d4210647be --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/ConstantPool.java @@ -0,0 +1,36 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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; + } + + @Override + public String toString() { + return "ConstantPool{" + + "constantInfos=" + constantInfos + + '}'; + } +} diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/FieldRefInfo.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..1808a35c65 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/FieldRefInfo.java @@ -0,0 +1,54 @@ +package com.coding.mini_jvm.src.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/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/MethodRefInfo.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..dc62d438e6 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/MethodRefInfo.java @@ -0,0 +1,55 @@ +package com.coding.mini_jvm.src.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/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/NameAndTypeInfo.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..b8b9da7353 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,45 @@ +package com.coding.mini_jvm.src.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/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/NullConstantInfo.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..bf19f681d8 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/NullConstantInfo.java @@ -0,0 +1,13 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo(){ + + } + @Override + public int getType() { + return -1; + } + +} diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/StringInfo.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..05a4afad6a --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/StringInfo.java @@ -0,0 +1,26 @@ +package com.coding.mini_jvm.src.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/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/UTF8Info.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..61f20ed8f1 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/UTF8Info.java @@ -0,0 +1,32 @@ +package com.coding.mini_jvm.src.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/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..27d0c63af0 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,52 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.loader; + +import com.coding.mini_jvm.src.com.coderising.jvm.util.Util; + +public class ByteCodeIterator { + private static final int U1 = 1; + private static final int U2 = 2; + private static final int U4 = 4; + private static final int U8 = 8; + private byte[] bytes; + private int cursor; + + public ByteCodeIterator(byte[] bytes) { + this.bytes = bytes; + } + + public String readTwoBytesToString() { + String ret = Util.byte2String(bytes, cursor, U2); + cursor += U2; + return ret; + } + + public String readBytesToString(int len) { + String ret = Util.byte2String(bytes, cursor, len); + cursor += len; + return ret; + } + + + public int readTwoBytesToInt() { + int ret = Util.bytes2Int(bytes, cursor, U2); + cursor += U2; + return ret; + } + + public int readByteToInt() { + int ret = Util.bytes2Int(bytes, cursor, U1); + cursor += U1; + return ret; + } + + + + + public int skip(int len) { + if (cursor + len < 0 || cursor + len > bytes.length - 1) { + throw new IndexOutOfBoundsException(); + } + cursor += len; + return cursor; + } +} 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 index 1ca7cc8ece..452f6bce7d 100644 --- 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 @@ -1,6 +1,11 @@ package com.coding.mini_jvm.src.com.coderising.jvm.loader; -import java.io.*; +import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassFile; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -14,29 +19,35 @@ public class ClassFileLoader { public byte[] readBinaryCode(String className) { String classPath = getClassPath(); String[] paths = classPath.split(File.pathSeparator); - className = className.replaceAll("\\.", "\\"+File.separator) ; + className = className.replace('.', File.separatorChar) ; 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(); - } + String clzFilename = path + File.separator + className + CLASS_FILE_SUFFIX; + byte[] data = loadClassFile(clzFilename); + if (data != null) { + return data; } } return null; } - + + private byte[] loadClassFile(String clzFileName) { + File file = new File(clzFileName); + BufferedInputStream bis = null; + try { + bis = new BufferedInputStream(new FileInputStream(file)); + byte[] data = new byte[bis.available()]; + bis.read(data); + return data; + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } public void addClassPath(String path) { + if (this.clzPaths.contains(path)) { + return; + } clzPaths.add(path); } @@ -52,8 +63,10 @@ public String getClassPath(){ return path.substring(0, path.lastIndexOf(";")); } - - - + public ClassFile loadClass(String className) { + byte[] data = readBinaryCode(className); + ClassFileParser classFileParser = new ClassFileParser(); + return classFileParser.parse(data); + } } diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/loader/ClassFileParser.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..542968c809 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/loader/ClassFileParser.java @@ -0,0 +1,103 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.loader; + +import com.coding.mini_jvm.src.com.coderising.jvm.clz.AccessFlag; +import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassFile; +import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassIndex; +import com.coding.mini_jvm.src.com.coderising.jvm.constant.*; + + +public class ClassFileParser { + + public ClassFile parse(byte[] codes) { + ClassFile classFile = new ClassFile(); + ByteCodeIterator iterator = new ByteCodeIterator(codes); + //跳过魔数 + iterator.skip(4); + //次版本号 + classFile.setMinorVersion(iterator.readTwoBytesToInt()); + //主版本号 + classFile.setMajorVersion(iterator.readTwoBytesToInt()); + //解析常量池 + classFile.setConstPool(parseConstantPool(iterator)); + //访问限制符 + classFile.setAccessFlag(parseAccessFlag(iterator)); + //当前类/父类 + classFile.setClassIndex(parseClassIndex(iterator)); + return classFile; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + return new AccessFlag(iter.readTwoBytesToInt()); + } + + private ClassIndex parseClassIndex(ByteCodeIterator iter) { + ClassIndex classIndex = new ClassIndex(); + classIndex.setThisClassIndex(iter.readTwoBytesToInt()); + classIndex.setSuperClassIndex(iter.readTwoBytesToInt()); + return classIndex; + } + + private ConstantPool parseConstantPool(ByteCodeIterator iterator) { + ConstantPool constantPool = new ConstantPool(); + //读取常量个数 + int constantPoolCount = iterator.readTwoBytesToInt(); + constantPool.addConstantInfo(new NullConstantInfo()); + for (int i = 1; i < constantPoolCount; i++) { + int flag = iterator.readByteToInt(); + int utf8Index; + int clzIndex; + int nameAndTypeIndex; + switch (flag) { + case 1: + int length = iterator.readTwoBytesToInt(); + String val = iterator.readBytesToString(length); + UTF8Info utf8Info = new UTF8Info(constantPool); + utf8Info.setLength(length); + utf8Info.setValue(val); + constantPool.addConstantInfo(utf8Info); + break; + case 7: + utf8Index = iterator.readTwoBytesToInt(); + ClassInfo classInfo = new ClassInfo(constantPool); + classInfo.setUtf8Index(utf8Index); + constantPool.addConstantInfo(classInfo); + break; + case 8: + utf8Index = iterator.readTwoBytesToInt(); + StringInfo stringInfo = new StringInfo(constantPool); + stringInfo.setIndex(utf8Index); + constantPool.addConstantInfo(stringInfo); + break; + case 9: + clzIndex = iterator.readTwoBytesToInt(); + nameAndTypeIndex = iterator.readTwoBytesToInt(); + FieldRefInfo fieldRefInfo = new FieldRefInfo(constantPool); + fieldRefInfo.setNameAndTypeIndex(nameAndTypeIndex); + fieldRefInfo.setClassInfoIndex(clzIndex); + constantPool.addConstantInfo(fieldRefInfo); + break; + case 10: + clzIndex = iterator.readTwoBytesToInt(); + nameAndTypeIndex = iterator.readTwoBytesToInt(); + MethodRefInfo methodRefInfo = new MethodRefInfo(constantPool); + methodRefInfo.setClassInfoIndex(clzIndex); + methodRefInfo.setNameAndTypeIndex(nameAndTypeIndex); + constantPool.addConstantInfo(methodRefInfo); + break; + case 12: + utf8Index = iterator.readTwoBytesToInt(); + int utf8Index1 = iterator.readTwoBytesToInt(); + NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(constantPool); + nameAndTypeInfo.setIndex1(utf8Index); + nameAndTypeInfo.setIndex2(utf8Index1); + constantPool.addConstantInfo(nameAndTypeInfo); + break; + default: + throw new RuntimeException("flag "+ flag +" is not exists"); + } + } + return constantPool; + } + + +} diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/util/Util.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/util/Util.java new file mode 100644 index 0000000000..8811e3541c --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/util/Util.java @@ -0,0 +1,40 @@ +package com.coding.mini_jvm.src.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 int bytes2Int(byte[] b, int start, int len) { + int sum = 0; + int end = start + len; + for (int i = start; i < end; i++) { + int n = ((int) b[i]) & 0xff; + n <<= (--len) * 8; + sum = n + sum; + } + return sum; + } + + + public static String byte2String(byte[] b, int start, int len) { + return new String(b, start, len); + } + + 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/group24/494800949/src/main/java/com/coding/weak1/Stack.java b/group24/494800949/src/main/java/com/coding/weak1/Stack.java index d1088e7db0..ffa00f99e7 100644 --- a/group24/494800949/src/main/java/com/coding/weak1/Stack.java +++ b/group24/494800949/src/main/java/com/coding/weak1/Stack.java @@ -1,5 +1,6 @@ package com.coding.weak1; +import java.util.ArrayList; import java.util.NoSuchElementException; public class Stack { @@ -26,4 +27,17 @@ public boolean isEmpty(){ public int size(){ return elementData.size(); } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + if (isEmpty()) { + return ""; + } + for (int i = elementData.size() - 1; i >= 0; i--) { + sb.append(elementData.get(i).toString()); + sb.append(","); + } + return sb.substring(0, sb.lastIndexOf(",")); + } } diff --git a/group24/494800949/src/main/java/com/coding/week5/stack/StackUtil.java b/group24/494800949/src/main/java/com/coding/week5/stack/StackUtil.java new file mode 100644 index 0000000000..d893fcaa24 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/week5/stack/StackUtil.java @@ -0,0 +1,111 @@ +package com.coding.week5.stack; + +import com.coding.weak1.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 o1 = s.pop(); + if (!o.equals(o1)) { + stack.push(o1); + } + } + 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 IllegalArgumentException(len+""); + } + + Object[] objects = new Object[len]; + for (int i = 0; i < len; i++) { + objects[i] = s.pop(); + } + for (int i = len - 1; i >= 0 ; i--) { + s.push(objects[i]); + } + return objects; + } + /** + * 字符串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 stack = new Stack(); + Stack stack1 = new Stack(); + char[] chars = s.toCharArray(); + for (char c : chars) { + if ( c >= 'a' && c <= 'z') { + continue; + } + stack.push(c); + stack1.push(c); + } + reverse(stack); + while (!stack.isEmpty()) { + if (!isPair((char)stack1.pop(), (char)stack.pop())) { + return false; + } + } + return true; + } + + private static boolean isPair(char c1, char c2) { + switch (c1) { + case '{': + return c2 == '}'; + case '}': + return c2 == '{'; + case '[': + return c2 == ']'; + case ']': + return c2 == '['; + case '(': + return c2 == ')'; + case ')': + return c2 == '('; + default: + return false; + } + } + +} 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 index 830d0b7efe..a03f29c0c3 100644 --- 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 @@ -1,6 +1,10 @@ package com.coding.mini_jvm.test; +import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassFile; +import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassIndex; +import com.coding.mini_jvm.src.com.coderising.jvm.constant.*; import com.coding.mini_jvm.src.com.coderising.jvm.loader.ClassFileLoader; +import com.coding.mini_jvm.src.com.coderising.jvm.util.Util; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -16,9 +20,19 @@ public class ClassFileloaderTest { static String path1 = "H:\\sourceCode\\coding2017\\group24\\494800949\\build\\classes\\test"; static String path2 = "C:\temp"; - - - + + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + + static ClassFile clzFile = null; + static { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "com.coding.mini_jvm.test.EmployeeV1"; + + clzFile = loader.loadClass(className); +// clzFile.print(); + } + @Before public void setUp() throws Exception { } @@ -65,28 +79,95 @@ 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<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); + + @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("<init>", 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()); } - 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/494800949/src/test/java/com/coding/week5/stack/StackUtilTest.java b/group24/494800949/src/test/java/com/coding/week5/stack/StackUtilTest.java new file mode 100644 index 0000000000..8e14b7cf00 --- /dev/null +++ b/group24/494800949/src/test/java/com/coding/week5/stack/StackUtilTest.java @@ -0,0 +1,56 @@ +package com.coding.week5.stack; + +import com.coding.weak1.Stack; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * Created by Administrator on 2017/4/9 0009. + */ +public class StackUtilTest { + + private Stack stack; + + @Before + public void setup() { + stack = new Stack(); + stack.push(1); + stack.push(2); + stack.push(3); + stack.push(4); + + } + @Test + public void reverse() throws Exception { + Assert.assertEquals("4,3,2,1",stack.toString()); + StackUtil.reverse(stack); + Assert.assertEquals("1,2,3,4",stack.toString()); + } + + @Test + public void remove() throws Exception { + StackUtil.remove(stack, 3); + Assert.assertEquals(stack.toString(), "4,2,1"); + } + + @Test + public void getTop() throws Exception { + Object[] objects = StackUtil.getTop(stack, 2); + Assert.assertEquals(objects[0], 4); + Assert.assertEquals(objects[1], 3); + } + + @Test + public void isValidPairs() throws Exception { + String str = "[abdd]}"; + Assert.assertEquals(StackUtil.isValidPairs(str), false); + str = "{add{ad[ddd]}}"; + Assert.assertEquals(StackUtil.isValidPairs(str), true); + str = "{add{ad[d(dd]}}"; + Assert.assertEquals(StackUtil.isValidPairs(str), false); + str = "{add{ad[d(d)d]}dfd}"; + Assert.assertEquals(StackUtil.isValidPairs(str), true); + } + +} \ No newline at end of file From 830964bc3a6bed90149d85b68641c04907d61aa2 Mon Sep 17 00:00:00 2001 From: sdnb <xgct0505@qq.com> Date: Tue, 11 Apr 2017 00:05:27 +0800 Subject: [PATCH 206/287] =?UTF-8?q?stackUtil=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/coding/week5/stack/StackUtil.java | 38 ++++++++----------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/group24/494800949/src/main/java/com/coding/week5/stack/StackUtil.java b/group24/494800949/src/main/java/com/coding/week5/stack/StackUtil.java index d893fcaa24..7b750b3549 100644 --- a/group24/494800949/src/main/java/com/coding/week5/stack/StackUtil.java +++ b/group24/494800949/src/main/java/com/coding/week5/stack/StackUtil.java @@ -71,38 +71,30 @@ public static Object[] getTop(Stack s,int len) { */ public static boolean isValidPairs(String s){ Stack stack = new Stack(); - Stack stack1 = new Stack(); char[] chars = s.toCharArray(); for (char c : chars) { - if ( c >= 'a' && c <= 'z') { - continue; - } - stack.push(c); - stack1.push(c); - } - reverse(stack); - while (!stack.isEmpty()) { - if (!isPair((char)stack1.pop(), (char)stack.pop())) { - return false; + if (c == '(' || c == '{' || c == '[') { + stack.push(c); + } else if (c == ')' || c == '}' || c == ']'){ + if (stack.isEmpty()) { + return false; + } + if (!isPair((char)stack.pop(), c)){ + return false; + } } } - return true; + return stack.isEmpty(); } - private static boolean isPair(char c1, char c2) { - switch (c1) { + private static boolean isPair(char left, char right) { + switch (left) { case '{': - return c2 == '}'; - case '}': - return c2 == '{'; + return right == '}'; case '[': - return c2 == ']'; - case ']': - return c2 == '['; + return right == ']'; case '(': - return c2 == ')'; - case ')': - return c2 == '('; + return right == ')'; default: return false; } From a7a71ad25e298b33eff4ccdf72274074de2e3c4e Mon Sep 17 00:00:00 2001 From: ZhaoHongxin <zhaohongxin621@126.com> Date: Tue, 11 Apr 2017 00:21:22 +0800 Subject: [PATCH 207/287] JVM V2 --- .../coderising/jvm/constant/ClassInfo.java | 2 +- .../coderising/jvm/constant/ConstantInfo.java | 1 + .../jvm/loader/ByteCodeIterator.java | 36 ++++++- .../jvm/loader/ClassFileParser.java | 94 +++++++++++++++++-- .../jvm/test/ClassFileloaderTest.java | 8 +- 5 files changed, 129 insertions(+), 12 deletions(-) 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 index e12b3e164e..92ae6bd6f6 100644 --- a/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/ClassInfo.java +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/ClassInfo.java @@ -2,7 +2,7 @@ public class ClassInfo extends ConstantInfo { private int type = ConstantInfo.CLASS_INFO; - private int utf8Index ; + private int utf8Index ;//name_index public ClassInfo(ConstantPool pool) { super(pool); } 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 index c8035ae876..2e3bef0a4e 100644 --- a/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/ConstantInfo.java +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/constant/ConstantInfo.java @@ -8,6 +8,7 @@ public abstract class ConstantInfo { 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(){ 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 index 2dff6746da..9c7c2fa591 100644 --- a/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java @@ -1,5 +1,39 @@ package com.coderising.jvm.loader; -public class ByteCodeIterator { +import java.util.Arrays; + +import com.coderising.jvm.util.Util; +public class ByteCodeIterator { + + byte[] codes; + int pos = 0; + + ByteCodeIterator(byte[] codes) { + this.codes = codes; + } + + 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; + } + + 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++] }); + } + } 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 index bc18b7916c..780adc0a51 100644 --- a/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java @@ -17,24 +17,100 @@ public class ClassFileParser { public ClassFile parse(byte[] codes) { - - return null; + 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); + clzFile.setAccessFlag(parseAccessFlag(iter)); + clzFile.setClassIndex(parseClassIndex(iter)); + return clzFile; } private AccessFlag parseAccessFlag(ByteCodeIterator iter) { - - return null; + //int flagValue = iter.nextU2toInt(); + return new AccessFlag(iter.nextU2toInt()); } - private ClassIndex parseClassInfex(ByteCodeIterator iter) { - - return null; + private ClassIndex parseClassIndex(ByteCodeIterator iter) { + ClassIndex classIndex = new ClassIndex(); + classIndex.setThisClassIndex(iter.nextU2toInt()); + classIndex.setSuperClassIndex(iter.nextU2toInt()); + return classIndex; } private ConstantPool parseConstantPool(ByteCodeIterator iter) { - - return null; + int constantPoolIndexCount = iter.nextU2toInt(); + System.out.println("Constant Pool Index Count:" + constantPoolIndexCount); + ConstantPool pool = new ConstantPool(); + + pool.addConstantInfo(new NullConstantInfo()); + + for (int i = 1; i <= constantPoolIndexCount - 1; i++) { + int tag = iter.nextU1toInt(); + if (tag == 7) {//Class Info + int nameIndex = iter.nextU2toInt(); + ClassInfo clzInfo = new ClassInfo(pool); + clzInfo.setUtf8Index(nameIndex); + + pool.addConstantInfo(clzInfo); + } else if (tag == 1) {//Utf8 Info + int length = iter.nextU2toInt(); + byte[] data = iter.getBytes(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 == 8) {// String Info + int strIndex = iter.nextU2toInt(); + StringInfo stringInfo = new StringInfo(pool); + stringInfo.setIndex(strIndex); + + pool.addConstantInfo(stringInfo); + } else if (tag == 9) {// Fieldref Info + FieldRefInfo fieldRefInfo = new FieldRefInfo(pool); + fieldRefInfo.setClassInfoIndex(iter.nextU2toInt()); + fieldRefInfo.setNameAndTypeIndex(iter.nextU2toInt()); + + pool.addConstantInfo(fieldRefInfo); + } else if (tag == 10) {// Methodref Info + int classIndex = iter.nextU2toInt(); + int nameAndTypeIndex = iter.nextU2toInt(); + MethodRefInfo methodRefInfo = new MethodRefInfo(pool); + methodRefInfo.setClassInfoIndex(classIndex); + methodRefInfo.setNameAndTypeIndex(nameAndTypeIndex); + + pool.addConstantInfo(methodRefInfo); + } else if (tag == 12) { //NameAndType Info + int nameIndex = iter.nextU2toInt(); + int descriptorIndex = iter.nextU2toInt(); + NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(pool); + nameAndTypeInfo.setIndex1(nameIndex); + nameAndTypeInfo.setIndex2(descriptorIndex); + + pool.addConstantInfo(nameAndTypeInfo); + } + else { + throw new RuntimeException("The constant pool has not realized the tag:" + tag); + } + } + return pool; } 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 b33d202b69..a595370848 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 @@ -8,6 +8,12 @@ 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; @@ -26,7 +32,7 @@ public class ClassFileloaderTest { ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); String className = "com.coderising.jvm.test.EmployeeV1"; - + clzFile = loader.loadClass(className); clzFile.print(); } From 471e010fa8882ce16ad49623deb7fb5caf298188 Mon Sep 17 00:00:00 2001 From: onlyLYJ <382266293@qq.com> Date: Tue, 11 Apr 2017 09:35:31 +0800 Subject: [PATCH 208/287] week 5 begin --- group12/382266293/.classpath | 18 +++-- .../coding/basic/stack/expr/InfixExpr.java | 18 +++++ .../basic/stack/expr/InfixExprTest.java | 48 ++++++++++++ .../coderising/jvm/attr/AttributeInfo.java | 19 +++++ .../src/com/coderising/jvm/attr/CodeAttr.java | 56 ++++++++++++++ .../coderising/jvm/attr/LineNumberTable.java | 42 +++++++++++ .../jvm/attr/LocalVariableItem.java | 39 ++++++++++ .../jvm/attr/LocalVariableTable.java | 28 +++++++ .../coderising/jvm/attr/StackMapTable.java | 30 ++++++++ .../src/com/coderising/jvm/clz/ClassFile.java | 14 ++++ .../src/com/coderising/jvm/field/Field.java | 33 +++++++++ .../jvm/loader/ByteCodeIterator.java | 31 +++++++- .../jvm/loader/ClassFileParser.java | 34 ++++----- .../src/com/coderising/jvm/method/Method.java | 57 ++++++++++++++ .../jvm/test/ClassFileloaderTest.java | 74 +++++++++++++++++++ group12/382266293/src/litestruts/struts.xml | 16 ++-- 16 files changed, 521 insertions(+), 36 deletions(-) create mode 100644 group12/382266293/coding/basic/stack/expr/InfixExpr.java create mode 100644 group12/382266293/coding/basic/stack/expr/InfixExprTest.java create mode 100644 group12/382266293/src/com/coderising/jvm/attr/AttributeInfo.java create mode 100644 group12/382266293/src/com/coderising/jvm/attr/CodeAttr.java create mode 100644 group12/382266293/src/com/coderising/jvm/attr/LineNumberTable.java create mode 100644 group12/382266293/src/com/coderising/jvm/attr/LocalVariableItem.java create mode 100644 group12/382266293/src/com/coderising/jvm/attr/LocalVariableTable.java create mode 100644 group12/382266293/src/com/coderising/jvm/attr/StackMapTable.java create mode 100644 group12/382266293/src/com/coderising/jvm/field/Field.java create mode 100644 group12/382266293/src/com/coderising/jvm/method/Method.java diff --git a/group12/382266293/.classpath b/group12/382266293/.classpath index 248236a6c0..81755542a2 100644 --- a/group12/382266293/.classpath +++ b/group12/382266293/.classpath @@ -1,11 +1,13 @@ <?xml version="1.0" encoding="UTF-8"?> <classpath> - <classpathentry kind="src" path="src"/> - <classpathentry kind="src" path="coding/basic"/> - <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> - <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/> - <classpathentry kind="lib" path="lib/dom4j-1.6.1.jar"/> - <classpathentry kind="lib" path="lib/jaxen-1.1-beta-6.jar"/> - <classpathentry kind="lib" path="lib/jdom-2.0.6.jar"/> - <classpathentry kind="output" path="bin"/> + <classpathentry kind="src" path="src" /> + <classpathentry kind="src" path="coding/basic" /> + <classpathentry kind="con" + path="org.eclipse.jdt.launching.JRE_CONTAINER" /> + <classpathentry kind="con" + path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4" /> + <classpathentry kind="lib" path="lib/dom4j-1.6.1.jar" /> + <classpathentry kind="lib" path="lib/jaxen-1.1-beta-6.jar" /> + <classpathentry kind="lib" path="lib/jdom-2.0.6.jar" /> + <classpathentry kind="output" path="bin" /> </classpath> diff --git a/group12/382266293/coding/basic/stack/expr/InfixExpr.java b/group12/382266293/coding/basic/stack/expr/InfixExpr.java new file mode 100644 index 0000000000..eade1dc743 --- /dev/null +++ b/group12/382266293/coding/basic/stack/expr/InfixExpr.java @@ -0,0 +1,18 @@ +package stack.expr; + +public class InfixExpr { + String expr = null; + + public InfixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + + return 0.0f; + } + + + + +} diff --git a/group12/382266293/coding/basic/stack/expr/InfixExprTest.java b/group12/382266293/coding/basic/stack/expr/InfixExprTest.java new file mode 100644 index 0000000000..bb047629bd --- /dev/null +++ b/group12/382266293/coding/basic/stack/expr/InfixExprTest.java @@ -0,0 +1,48 @@ +package stack.expr; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class InfixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + //InfixExpr expr = new InfixExpr("300*20+12*5-20/4"); + { + InfixExpr expr = new InfixExpr("2+3*4+5"); + Assert.assertEquals(19.0, expr.evaluate(), 0.001f); + } + { + InfixExpr expr = new InfixExpr("3*20+12*5-40/2"); + Assert.assertEquals(100.0, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("3*20/2"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("20/2*3"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("10-30+50"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + } + +} diff --git a/group12/382266293/src/com/coderising/jvm/attr/AttributeInfo.java b/group12/382266293/src/com/coderising/jvm/attr/AttributeInfo.java new file mode 100644 index 0000000000..89fb53394e --- /dev/null +++ b/group12/382266293/src/com/coderising/jvm/attr/AttributeInfo.java @@ -0,0 +1,19 @@ +package com.coderising.jvm.attr; + +public abstract class AttributeInfo { + public static final String CODE = "Code"; + public static final String CONST_VALUE = "ConstantValue"; + public static final String EXCEPTIONS = "Exceptions"; + public static final String LINE_NUM_TABLE = "LineNumberTable"; + public static final String LOCAL_VAR_TABLE = "LocalVariableTable"; + public static final String STACK_MAP_TABLE = "StackMapTable"; + int attrNameIndex; + int attrLen ; + public AttributeInfo(int attrNameIndex, int attrLen) { + + this.attrNameIndex = attrNameIndex; + this.attrLen = attrLen; + } + + +} diff --git a/group12/382266293/src/com/coderising/jvm/attr/CodeAttr.java b/group12/382266293/src/com/coderising/jvm/attr/CodeAttr.java new file mode 100644 index 0000000000..b0c67b4b93 --- /dev/null +++ b/group12/382266293/src/com/coderising/jvm/attr/CodeAttr.java @@ -0,0 +1,56 @@ +package com.coderising.jvm.attr; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.loader.ByteCodeIterator; + + +public class CodeAttr extends AttributeInfo { + private int maxStack ; + private int maxLocals ; + private int codeLen ; + private String code; + public String getCode() { + return code; + } + + //private ByteCodeCommand[] cmds ; + //public ByteCodeCommand[] getCmds() { + // return cmds; + //} + private LineNumberTable lineNumTable; + private LocalVariableTable localVarTable; + private StackMapTable stackMapTable; + + public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen,String code /*ByteCodeCommand[] cmds*/) { + super(attrNameIndex, attrLen); + this.maxStack = maxStack; + this.maxLocals = maxLocals; + this.codeLen = codeLen; + this.code = code; + //this.cmds = cmds; + } + + public void setLineNumberTable(LineNumberTable t) { + this.lineNumTable = t; + } + + public void setLocalVariableTable(LocalVariableTable t) { + this.localVarTable = t; + } + + public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ + + + return null; + } + private void setStackMapTable(StackMapTable t) { + this.stackMapTable = t; + + } + + + + + +} diff --git a/group12/382266293/src/com/coderising/jvm/attr/LineNumberTable.java b/group12/382266293/src/com/coderising/jvm/attr/LineNumberTable.java new file mode 100644 index 0000000000..22941f83b1 --- /dev/null +++ b/group12/382266293/src/com/coderising/jvm/attr/LineNumberTable.java @@ -0,0 +1,42 @@ +package com.coderising.jvm.attr; + +import java.util.ArrayList; +import java.util.List; + +import com.coderising.jvm.loader.ByteCodeIterator; + +public class LineNumberTable extends AttributeInfo { + List<LineNumberItem> items = new ArrayList<LineNumberItem>(); + + private static class LineNumberItem{ + int startPC; + int lineNum; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLineNum() { + return lineNum; + } + public void setLineNum(int lineNum) { + this.lineNum = lineNum; + } + } + public void addLineNumberItem(LineNumberItem item){ + this.items.add(item); + } + public LineNumberTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + + } + + public static LineNumberTable parse(ByteCodeIterator iter){ + + return null; + } + + + +} diff --git a/group12/382266293/src/com/coderising/jvm/attr/LocalVariableItem.java b/group12/382266293/src/com/coderising/jvm/attr/LocalVariableItem.java new file mode 100644 index 0000000000..3eb2654e36 --- /dev/null +++ b/group12/382266293/src/com/coderising/jvm/attr/LocalVariableItem.java @@ -0,0 +1,39 @@ +package com.coderising.jvm.attr; + +public class LocalVariableItem { + private int startPC; + private int length; + private int nameIndex; + private int descIndex; + private int index; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getNameIndex() { + return nameIndex; + } + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + public int getDescIndex() { + return descIndex; + } + public void setDescIndex(int descIndex) { + this.descIndex = descIndex; + } + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } +} diff --git a/group12/382266293/src/com/coderising/jvm/attr/LocalVariableTable.java b/group12/382266293/src/com/coderising/jvm/attr/LocalVariableTable.java new file mode 100644 index 0000000000..fa69dc9bdb --- /dev/null +++ b/group12/382266293/src/com/coderising/jvm/attr/LocalVariableTable.java @@ -0,0 +1,28 @@ +package com.coderising.jvm.attr; + + +import java.util.ArrayList; +import java.util.List; + +import com.coderising.jvm.constant.ConstantPool; + +import com.coderising.jvm.loader.ByteCodeIterator; + +public class LocalVariableTable extends AttributeInfo{ + + List<LocalVariableItem> items = new ArrayList<LocalVariableItem>(); + + public LocalVariableTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static LocalVariableTable parse(ByteCodeIterator iter){ + + return null; + } + private void addLocalVariableItem(LocalVariableItem item) { + this.items.add(item); + } + + +} diff --git a/group12/382266293/src/com/coderising/jvm/attr/StackMapTable.java b/group12/382266293/src/com/coderising/jvm/attr/StackMapTable.java new file mode 100644 index 0000000000..44c5d90d46 --- /dev/null +++ b/group12/382266293/src/com/coderising/jvm/attr/StackMapTable.java @@ -0,0 +1,30 @@ +package com.coderising.jvm.attr; + + +import com.coderising.jvm.loader.ByteCodeIterator; + +public class StackMapTable extends AttributeInfo{ + + private String originalCode; + + public StackMapTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static StackMapTable parse(ByteCodeIterator iter){ + int index = iter.nextU2ToInt(); + int len = iter.nextU4ToInt(); + StackMapTable t = new StackMapTable(index,len); + + //后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 + String code = iter.nextUxToHexString(len); + t.setOriginalCode(code); + + return t; + } + + private void setOriginalCode(String code) { + this.originalCode = code; + + } +} diff --git a/group12/382266293/src/com/coderising/jvm/clz/ClassFile.java b/group12/382266293/src/com/coderising/jvm/clz/ClassFile.java index 359c477742..7038eec2e8 100644 --- a/group12/382266293/src/com/coderising/jvm/clz/ClassFile.java +++ b/group12/382266293/src/com/coderising/jvm/clz/ClassFile.java @@ -1,7 +1,11 @@ package com.coderising.jvm.clz; +import java.util.List; + import com.coderising.jvm.constant.ClassInfo; import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.field.Field; +import com.coderising.jvm.method.Method; public class ClassFile { @@ -74,4 +78,14 @@ private String getSuperClassName() { ClassInfo superClass = (ClassInfo) this.getConstantPool().getConstantInfo(this.clzIndex.getSuperClassIndex()); return superClass.getClassName(); } + + public List<Field> getFields() { + + return null; + } + + public List<Method> getMethods() { + + return null; + } } diff --git a/group12/382266293/src/com/coderising/jvm/field/Field.java b/group12/382266293/src/com/coderising/jvm/field/Field.java new file mode 100644 index 0000000000..09bae5a1ae --- /dev/null +++ b/group12/382266293/src/com/coderising/jvm/field/Field.java @@ -0,0 +1,33 @@ +package com.coderising.jvm.field; + +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.UTF8Info; +import com.coderising.jvm.loader.ByteCodeIterator; + + +public class Field { + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + + + private ConstantPool pool; + + public Field( int accessFlag, int nameIndex, int descriptorIndex,ConstantPool pool) { + + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + this.pool = pool; + } + + + + + public static Field parse(ConstantPool pool,ByteCodeIterator iter){ + + return null; + } + +} diff --git a/group12/382266293/src/com/coderising/jvm/loader/ByteCodeIterator.java b/group12/382266293/src/com/coderising/jvm/loader/ByteCodeIterator.java index a4f91e0876..bff24529f1 100644 --- a/group12/382266293/src/com/coderising/jvm/loader/ByteCodeIterator.java +++ b/group12/382266293/src/com/coderising/jvm/loader/ByteCodeIterator.java @@ -11,22 +11,28 @@ public ByteCodeIterator(byte[] codes) { this.codes = codes; } - public String nextU4toHexString() { + public String nextU4ToHexString() { byte[] u4 = new byte[] { codes[currPos++], codes[currPos++], codes[currPos++], codes[currPos++] }; return Util.byteToHexString(u4); } - public int nextU1toInt() { + public int nextU1ToInt() { byte[] u1 = new byte[] { codes[currPos++] }; return Util.byteToInt(u1); } - public int nextU2toInt() { + public int nextU2ToInt() { byte[] u2 = new byte[] { codes[currPos++], codes[currPos++] }; return Util.byteToInt(u2); } + public int nextU4ToInt() { + byte[] u4 = new byte[] { codes[currPos++], codes[currPos++], codes[currPos++], codes[currPos++] }; + return Util.byteToInt(u4); + } + + public byte[] nextNbytesToHexString(int length) { byte[] bytes = new byte[length]; int len = currPos + length; @@ -36,5 +42,24 @@ public byte[] nextNbytesToHexString(int length) { return bytes; } + + public String nextUxToHexString(int length) { + byte[] codes = nextNbytesToHexString(length); + return byteToHexString(codes); + } + + public 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/jvm/loader/ClassFileParser.java b/group12/382266293/src/com/coderising/jvm/loader/ClassFileParser.java index 2db5f6e085..367421b641 100644 --- a/group12/382266293/src/com/coderising/jvm/loader/ClassFileParser.java +++ b/group12/382266293/src/com/coderising/jvm/loader/ClassFileParser.java @@ -25,20 +25,20 @@ public ClassFile parse(byte[] codes) { ByteCodeIterator iter = new ByteCodeIterator(codes); - String magicNumber = iter.nextU4toHexString(); + String magicNumber = iter.nextU4ToHexString(); if ("cafebabe".equals(magicNumber) == false) { throw new RuntimeException("invalide class file!" + magicNumber); } - int minorVersion = iter.nextU2toInt(); + int minorVersion = iter.nextU2ToInt(); System.out.println("minorVersion is " + minorVersion); clzFile.setMinorVersion(minorVersion); - int majorVersion = iter.nextU2toInt(); + int majorVersion = iter.nextU2ToInt(); System.out.println("majorVersion is " + majorVersion); clzFile.setMajorVersion(majorVersion); - int constantsNum = iter.nextU2toInt(); + int constantsNum = iter.nextU2ToInt(); System.out.println("constantsNum is " + constantsNum); ConstantPool pool = new ConstantPool(); clzFile.setConstPool(pool); @@ -47,12 +47,12 @@ public ClassFile parse(byte[] codes) { for (int i = 1; i < constantsNum; i++) { - int tag = iter.nextU1toInt(); + int tag = iter.nextU1ToInt(); if (tag == 7) { // Class info ClassInfo classInfo = new ClassInfo(pool); - int utf8Index = iter.nextU2toInt(); + int utf8Index = iter.nextU2ToInt(); classInfo.setUtf8Index(utf8Index); @@ -60,7 +60,7 @@ public ClassFile parse(byte[] codes) { // utf8-info UTF8Info utf8Info = new UTF8Info(pool); - int length = iter.nextU2toInt(); + int length = iter.nextU2ToInt(); System.out.println("length is " + length); utf8Info.setLength(length); byte[] bytes = iter.nextNbytesToHexString(length); @@ -78,33 +78,33 @@ public ClassFile parse(byte[] codes) { // StringInfo StringInfo stringInfo = new StringInfo(pool); - int stringIndex = iter.nextU2toInt(); + int stringIndex = iter.nextU2ToInt(); stringInfo.setIndex(stringIndex); } else if (tag == 9) { // FieldRefInfo FieldRefInfo fieldRefInfo = new FieldRefInfo(pool); - int classIndex = iter.nextU2toInt(); + int classIndex = iter.nextU2ToInt(); fieldRefInfo.setClassInfoIndex(classIndex); - int nameAndTypeIndex = iter.nextU2toInt(); + int nameAndTypeIndex = iter.nextU2ToInt(); fieldRefInfo.setNameAndTypeIndex(nameAndTypeIndex); } else if (tag == 10) { // MethodRefInfo MethodRefInfo methodRefInfo = new MethodRefInfo(pool); - int classIndex = iter.nextU2toInt(); + int classIndex = iter.nextU2ToInt(); methodRefInfo.setClassInfoIndex(classIndex); - int nameAndTypeIndex = iter.nextU2toInt(); + int nameAndTypeIndex = iter.nextU2ToInt(); methodRefInfo.setNameAndTypeIndex(nameAndTypeIndex); } else if (tag == 12) { // NameAndTypeInfo NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(pool); - int index1 = iter.nextU2toInt(); + int index1 = iter.nextU2ToInt(); nameAndTypeInfo.setIndex1(index1); - int index2 = iter.nextU2toInt(); + int index2 = iter.nextU2ToInt(); nameAndTypeInfo.setIndex2(index2); } @@ -121,15 +121,15 @@ public ClassFile parse(byte[] codes) { } private AccessFlag parseAccessFlag(ByteCodeIterator iter) { - AccessFlag accessFlag = new AccessFlag(iter.nextU2toInt()); + AccessFlag accessFlag = new AccessFlag(iter.nextU2ToInt()); return accessFlag; } private ClassIndex parseClassIndex(ByteCodeIterator iter) { - int thisClassIndex = iter.nextU2toInt(); - int superClassIndex = iter.nextU2toInt(); + int thisClassIndex = iter.nextU2ToInt(); + int superClassIndex = iter.nextU2ToInt(); ClassIndex classIndex = new ClassIndex(); classIndex.setThisClassIndex(thisClassIndex); classIndex.setSuperClassIndex(superClassIndex); diff --git a/group12/382266293/src/com/coderising/jvm/method/Method.java b/group12/382266293/src/com/coderising/jvm/method/Method.java new file mode 100644 index 0000000000..ba5f7848d1 --- /dev/null +++ b/group12/382266293/src/com/coderising/jvm/method/Method.java @@ -0,0 +1,57 @@ +package com.coderising.jvm.method; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.attr.AttributeInfo; +import com.coderising.jvm.attr.CodeAttr; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.UTF8Info; +import com.coderising.jvm.loader.ByteCodeIterator; + + + +public class Method { + + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private CodeAttr codeAttr; + + private ClassFile clzFile; + + + public ClassFile getClzFile() { + return clzFile; + } + + public int getNameIndex() { + return nameIndex; + } + public int getDescriptorIndex() { + return descriptorIndex; + } + + public CodeAttr getCodeAttr() { + return codeAttr; + } + + public void setCodeAttr(CodeAttr code) { + this.codeAttr = code; + } + + public Method(ClassFile clzFile,int accessFlag, int nameIndex, int descriptorIndex) { + this.clzFile = clzFile; + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + } + + + + + + public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ + return null; + + } +} diff --git a/group12/382266293/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group12/382266293/src/com/coderising/jvm/test/ClassFileloaderTest.java index 2ae3072e35..7d110340a7 100644 --- a/group12/382266293/src/com/coderising/jvm/test/ClassFileloaderTest.java +++ b/group12/382266293/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -2,6 +2,7 @@ import java.io.UnsupportedEncodingException; import java.util.Arrays; +import java.util.List; import org.junit.After; import org.junit.Assert; @@ -11,7 +12,9 @@ import com.coderising.jvm.clz.ClassFile; import com.coderising.jvm.clz.ClassIndex; import com.coderising.jvm.constant.*; +import com.coderising.jvm.field.Field; import com.coderising.jvm.loader.ClassFileLoader; +import com.coderising.jvm.method.Method; public class ClassFileloaderTest { @@ -183,5 +186,76 @@ public void testClassIndex() { Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); } + + + @Test + public void testReadFields(){ + + List<Field> fields = clzFile.getFields(); + Assert.assertEquals(2, fields.size()); + { + Field f = fields.get(0); + Assert.assertEquals("name:Ljava/lang/String;", f.toString()); + } + { + Field f = fields.get(1); + Assert.assertEquals("age:I", f.toString()); + } + } + @Test + public void testMethods(){ + + List<Method> methods = clzFile.getMethods(); + ConstantPool pool = clzFile.getConstantPool(); + + { + Method m = methods.get(0); + assertMethodEquals(pool,m, + "<init>", + "(Ljava/lang/String;I)V", + "2ab7000c2a2bb5000f2a1cb50011b1"); + + } + { + Method m = methods.get(1); + assertMethodEquals(pool,m, + "setName", + "(Ljava/lang/String;)V", + "2a2bb5000fb1"); + + } + { + Method m = methods.get(2); + assertMethodEquals(pool,m, + "setAge", + "(I)V", + "2a1bb50011b1"); + } + { + Method m = methods.get(3); + assertMethodEquals(pool,m, + "sayHello", + "()V", + "b2001c1222b60024b1"); + + } + { + Method m = methods.get(4); + assertMethodEquals(pool,m, + "main", + "([Ljava/lang/String;)V", + "bb000159122b101db7002d4c2bb6002fb1"); + } + } + + private void assertMethodEquals(ConstantPool pool,Method m , String expectedName, String expectedDesc,String expectedCode){ + String methodName = pool.getUTF8String(m.getNameIndex()); + String methodDesc = pool.getUTF8String(m.getDescriptorIndex()); + String code = m.getCodeAttr().getCode(); + Assert.assertEquals(expectedName, methodName); + Assert.assertEquals(expectedDesc, methodDesc); + Assert.assertEquals(expectedCode, code); + } + } diff --git a/group12/382266293/src/litestruts/struts.xml b/group12/382266293/src/litestruts/struts.xml index 4c6eeabbd4..1370971a4b 100644 --- a/group12/382266293/src/litestruts/struts.xml +++ b/group12/382266293/src/litestruts/struts.xml @@ -1,11 +1,11 @@ <?xml version="1.0" encoding="UTF-8"?> <struts> - <action name="login" class="com.coderising.litestruts.LoginAction"> - <result name="success">/jsp/homepage.jsp</result> - <result name="fail">/jsp/showLogin.jsp</result> - </action> - <action name="logout" class="com.coderising.litestruts.LogoutAction"> - <result name="success">/jsp/welcome.jsp</result> - <result name="error">/jsp/error.jsp</result> - </action> + <action name="login" class="com.coderising.litestruts.LoginAction"> + <result name="success">/jsp/homepage.jsp</result> + <result name="fail">/jsp/showLogin.jsp</result> + </action> + <action name="logout" class="com.coderising.litestruts.LogoutAction"> + <result name="success">/jsp/welcome.jsp</result> + <result name="error">/jsp/error.jsp</result> + </action> </struts> \ No newline at end of file From 03aa137254c14d234f69fdbdf7e678b0750be6a1 Mon Sep 17 00:00:00 2001 From: onlyLYJ <382266293@qq.com> Date: Tue, 11 Apr 2017 11:48:59 +0800 Subject: [PATCH 209/287] paser half done --- .../src/com/coderising/jvm/attr/CodeAttr.java | 21 +++++++++++-- .../com/coderising/jvm/clz/AccessFlag.java | 6 ++++ .../src/com/coderising/jvm/clz/ClassFile.java | 19 ++++++++++-- .../coderising/jvm/constant/ConstantPool.java | 2 +- .../src/com/coderising/jvm/field/Field.java | 23 +++++++++++--- .../jvm/loader/ClassFileParser.java | 31 ++++++++++++++++--- .../src/com/coderising/jvm/method/Method.java | 27 +++++++++++++--- .../jvm/test/ClassFileloaderTest.java | 2 +- 8 files changed, 112 insertions(+), 19 deletions(-) diff --git a/group12/382266293/src/com/coderising/jvm/attr/CodeAttr.java b/group12/382266293/src/com/coderising/jvm/attr/CodeAttr.java index b0c67b4b93..e2bcf2fb36 100644 --- a/group12/382266293/src/com/coderising/jvm/attr/CodeAttr.java +++ b/group12/382266293/src/com/coderising/jvm/attr/CodeAttr.java @@ -2,6 +2,7 @@ import com.coderising.jvm.clz.ClassFile; import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.field.Field; import com.coderising.jvm.loader.ByteCodeIterator; @@ -40,9 +41,25 @@ public void setLocalVariableTable(LocalVariableTable t) { } public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ + int attrNameIndex = iter.nextU2ToInt(); + + int attrLen = iter.nextU4ToInt(); + + int maxStack = iter.nextU2ToInt(); + System.out.println("maxStack " + maxStack); + int maxLocals = iter.nextU2ToInt(); + + int codeLen = iter.nextU4ToInt(); + //System.out.println("Code is " + codeLen); + CodeAttr codeAttr = new CodeAttr(attrNameIndex, attrLen, maxStack, maxLocals, codeLen, "Code"); + String code = iter.nextUxToHexString(codeLen); - - return null; + + + + + + return null; } private void setStackMapTable(StackMapTable t) { this.stackMapTable = t; diff --git a/group12/382266293/src/com/coderising/jvm/clz/AccessFlag.java b/group12/382266293/src/com/coderising/jvm/clz/AccessFlag.java index 2cc6092de0..17dd61f8b6 100644 --- a/group12/382266293/src/com/coderising/jvm/clz/AccessFlag.java +++ b/group12/382266293/src/com/coderising/jvm/clz/AccessFlag.java @@ -1,5 +1,7 @@ package com.coderising.jvm.clz; +import com.coderising.jvm.loader.ByteCodeIterator; + public class AccessFlag { private int flagValue; @@ -23,4 +25,8 @@ public boolean isFinalClass() { return (this.flagValue & 0x0010) != 0; } + public static AccessFlag parseAccessFlag(ByteCodeIterator iter) { + AccessFlag accessFlag = new AccessFlag(iter.nextU2ToInt()); + return accessFlag; + } } \ 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 index 7038eec2e8..e9ae0b9bc8 100644 --- a/group12/382266293/src/com/coderising/jvm/clz/ClassFile.java +++ b/group12/382266293/src/com/coderising/jvm/clz/ClassFile.java @@ -1,5 +1,6 @@ package com.coderising.jvm.clz; +import java.util.ArrayList; import java.util.List; import com.coderising.jvm.constant.ClassInfo; @@ -15,6 +16,8 @@ public class ClassFile { private AccessFlag accessFlag; private ClassIndex clzIndex; private ConstantPool pool; + private List<Field> fields = new ArrayList<Field>(); + private List<Method> methods = new ArrayList<Method>(); public ClassIndex getClzIndex() { return clzIndex; @@ -81,11 +84,23 @@ private String getSuperClassName() { public List<Field> getFields() { - return null; + return fields; + } + + public void setFields(List<Field> fields) { + + this.fields = fields; + } public List<Method> getMethods() { - return null; + return methods; + } + + public void setMethods(List<Method> methods) { + + this.methods = methods; + } } diff --git a/group12/382266293/src/com/coderising/jvm/constant/ConstantPool.java b/group12/382266293/src/com/coderising/jvm/constant/ConstantPool.java index 8ed8bc229c..95c44dde8f 100644 --- a/group12/382266293/src/com/coderising/jvm/constant/ConstantPool.java +++ b/group12/382266293/src/com/coderising/jvm/constant/ConstantPool.java @@ -18,7 +18,7 @@ public void addConstantInfo(ConstantInfo info) { } public ConstantInfo getConstantInfo(int index) { - System.out.println("ok " + this.constantInfos.get(index)); + //System.out.println(this.constantInfos.get(index)); return this.constantInfos.get(index); } diff --git a/group12/382266293/src/com/coderising/jvm/field/Field.java b/group12/382266293/src/com/coderising/jvm/field/Field.java index 09bae5a1ae..2b0c549685 100644 --- a/group12/382266293/src/com/coderising/jvm/field/Field.java +++ b/group12/382266293/src/com/coderising/jvm/field/Field.java @@ -1,5 +1,6 @@ package com.coderising.jvm.field; +import com.coderising.jvm.clz.AccessFlag; import com.coderising.jvm.constant.ConstantPool; import com.coderising.jvm.constant.UTF8Info; import com.coderising.jvm.loader.ByteCodeIterator; @@ -9,9 +10,7 @@ public class Field { private int accessFlag; private int nameIndex; private int descriptorIndex; - - - + private ConstantPool pool; public Field( int accessFlag, int nameIndex, int descriptorIndex,ConstantPool pool) { @@ -25,9 +24,25 @@ public Field( int accessFlag, int nameIndex, int descriptorIndex,ConstantPool po + @Override + public String toString() { + return pool.getUTF8String(nameIndex) + ":" + pool.getUTF8String(descriptorIndex) ; + } + public static Field parse(ConstantPool pool,ByteCodeIterator iter){ - return null; + int access_flags = iter.nextU2ToInt(); + int name_index = iter.nextU2ToInt(); + int descriptor_index = iter.nextU2ToInt(); + int attrbutes_count = iter.nextU2ToInt(); + + if (attrbutes_count != 0) { + throw new RuntimeException("field attrbutes_count is " + attrbutes_count); + } + + Field field = new Field(access_flags,name_index,descriptor_index,pool); + + return field; } } diff --git a/group12/382266293/src/com/coderising/jvm/loader/ClassFileParser.java b/group12/382266293/src/com/coderising/jvm/loader/ClassFileParser.java index 367421b641..acaeb8e39d 100644 --- a/group12/382266293/src/com/coderising/jvm/loader/ClassFileParser.java +++ b/group12/382266293/src/com/coderising/jvm/loader/ClassFileParser.java @@ -1,6 +1,8 @@ package com.coderising.jvm.loader; import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.List; import org.junit.Assert; @@ -15,6 +17,8 @@ import com.coderising.jvm.constant.NullConstantInfo; import com.coderising.jvm.constant.StringInfo; import com.coderising.jvm.constant.UTF8Info; +import com.coderising.jvm.field.Field; +import com.coderising.jvm.method.Method; import com.coderising.jvm.util.Util; public class ClassFileParser { @@ -64,7 +68,6 @@ public ClassFile parse(byte[] codes) { 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"); @@ -116,14 +119,34 @@ public ClassFile parse(byte[] codes) { clzFile.setAccessFlag(accessFlag); clzFile.setClassIndex(classIndex); + + int interfaceNum = iter.nextU2ToInt(); + if (0 != interfaceNum) { + throw new RuntimeException("interface parser not finsihed yet, pls check!"); + } + + int fieldNum = iter.nextU2ToInt(); + List<Field> fields = new ArrayList<Field>(); + for (int i = 0; i < fieldNum; i++) { + Field field = Field.parse(pool,iter); + fields.add(field); + } + clzFile.setFields(fields); + + int methodNum = iter.nextU2ToInt(); + List<Method> methods = new ArrayList<Method>(); + for (int i = 0; i < methodNum; i++) { + Method method = Method.parse(clzFile,iter); + methods.add(method); + } + clzFile.setMethods(methods); return clzFile; } private AccessFlag parseAccessFlag(ByteCodeIterator iter) { - AccessFlag accessFlag = new AccessFlag(iter.nextU2ToInt()); - - return accessFlag; + + return AccessFlag.parseAccessFlag(iter); } private ClassIndex parseClassIndex(ByteCodeIterator iter) { diff --git a/group12/382266293/src/com/coderising/jvm/method/Method.java b/group12/382266293/src/com/coderising/jvm/method/Method.java index ba5f7848d1..a3075e1e58 100644 --- a/group12/382266293/src/com/coderising/jvm/method/Method.java +++ b/group12/382266293/src/com/coderising/jvm/method/Method.java @@ -5,7 +5,9 @@ import com.coderising.jvm.attr.CodeAttr; import com.coderising.jvm.constant.ConstantPool; import com.coderising.jvm.constant.UTF8Info; +import com.coderising.jvm.field.Field; import com.coderising.jvm.loader.ByteCodeIterator; +import com.sun.org.apache.bcel.internal.classfile.Code; @@ -46,12 +48,27 @@ public Method(ClassFile clzFile,int accessFlag, int nameIndex, int descriptorInd this.descriptorIndex = descriptorIndex; } - - - - + public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ - return null; + + int access_flags = iter.nextU2ToInt(); + int name_index = iter.nextU2ToInt(); + int descriptor_index = iter.nextU2ToInt(); + int attrbutes_count = iter.nextU2ToInt(); + System.out.println("count - = " + attrbutes_count); + Method method = new Method(clzFile, access_flags,name_index,descriptor_index); + + for (int i = 0; i < attrbutes_count; i++) { + int attr_name = iter.nextU2ToInt(); + if (clzFile.getConstantPool().getUTF8String(attr_name).equals("Code")) { + CodeAttr code = CodeAttr.parse(clzFile, iter); + } + + } + + + + return method; } } diff --git a/group12/382266293/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group12/382266293/src/com/coderising/jvm/test/ClassFileloaderTest.java index 7d110340a7..d4f255a763 100644 --- a/group12/382266293/src/com/coderising/jvm/test/ClassFileloaderTest.java +++ b/group12/382266293/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -34,7 +34,7 @@ public class ClassFileloaderTest { } catch (UnsupportedEncodingException e) { e.printStackTrace(); } - //clzFile.print(); + clzFile.print(); } @Before From 5d4cdce699b4ebc2d327e1e4439ad02a155d9810 Mon Sep 17 00:00:00 2001 From: ZhaoHongxin <zhaohongxin621@126.com> Date: Tue, 11 Apr 2017 14:05:37 +0800 Subject: [PATCH 210/287] little change --- .../src/com/coderising/jvm/loader/ClassFileParser.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 index 780adc0a51..0c58bff290 100644 --- a/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java @@ -44,8 +44,8 @@ private ClassIndex parseClassIndex(ByteCodeIterator iter) { ClassIndex classIndex = new ClassIndex(); classIndex.setThisClassIndex(iter.nextU2toInt()); classIndex.setSuperClassIndex(iter.nextU2toInt()); + return classIndex; - } private ConstantPool parseConstantPool(ByteCodeIterator iter) { @@ -107,7 +107,7 @@ private ConstantPool parseConstantPool(ByteCodeIterator iter) { pool.addConstantInfo(nameAndTypeInfo); } else { - throw new RuntimeException("The constant pool has not realized the tag:" + tag); + throw new RuntimeException("The constant pool has not realized at tag=" + tag); } } return pool; From 83a4a6fcb6e8b6ae85d7fb00ef56d25c0eef684d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BE=9A=E5=90=AF=E7=9B=BC?= <gongqipan@qipeipu.com> Date: Tue, 11 Apr 2017 16:38:30 +0800 Subject: [PATCH 211/287] modify --- .../src/main/java/com/pan/week01/{ => base}/Iterator.java | 2 +- .../src/main/java/com/pan/jvm/loader/ClassFileLoader.java | 2 +- group11/group11.md | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) rename group11/252308879/data-structure/src/main/java/com/pan/week01/{ => base}/Iterator.java (82%) delete mode 100644 group11/group11.md diff --git a/group11/252308879/data-structure/src/main/java/com/pan/week01/Iterator.java b/group11/252308879/data-structure/src/main/java/com/pan/week01/base/Iterator.java similarity index 82% rename from group11/252308879/data-structure/src/main/java/com/pan/week01/Iterator.java rename to group11/252308879/data-structure/src/main/java/com/pan/week01/base/Iterator.java index b59719cd2b..2f4317524e 100644 --- a/group11/252308879/data-structure/src/main/java/com/pan/week01/Iterator.java +++ b/group11/252308879/data-structure/src/main/java/com/pan/week01/base/Iterator.java @@ -1,4 +1,4 @@ -package com.pan.week01; +package com.pan.week01.base; /** * Created by QiPan on 2017/2/23. diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileLoader.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileLoader.java index 1418fa9b83..a21d246399 100644 --- a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileLoader.java +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileLoader.java @@ -15,7 +15,7 @@ public class ClassFileLoader { - private List<String> clzPaths = new ArrayList<String>(); + private List<String> clzPaths = new ArrayList(); public byte[] readBinaryCode(String className) { diff --git a/group11/group11.md b/group11/group11.md deleted file mode 100644 index 8b13789179..0000000000 --- a/group11/group11.md +++ /dev/null @@ -1 +0,0 @@ - From 6f1a4fcedc2f2081a0468ed64704b28500d42ff5 Mon Sep 17 00:00:00 2001 From: ZhaoHongxin <zhaohongxin621@126.com> Date: Tue, 11 Apr 2017 16:47:30 +0800 Subject: [PATCH 212/287] stackUtils v1 --- group05/1094051862/test01/.classpath | 1 + .../src/com/coding/basic/stack/Stack.java | 32 +++++++-- .../src/com/coding/basic/stack/StackUtil.java | 72 ++++++++++++++++++- 3 files changed, 96 insertions(+), 9 deletions(-) diff --git a/group05/1094051862/test01/.classpath b/group05/1094051862/test01/.classpath index 6f95a0c3bd..2ffae0aee1 100644 --- a/group05/1094051862/test01/.classpath +++ b/group05/1094051862/test01/.classpath @@ -4,5 +4,6 @@ <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="lib" path="lib/dom4j-1.6.1.jar"/> + <classpathentry kind="lib" path="lib/commons-lang3-3.5.jar"/> <classpathentry kind="output" path="bin"/> </classpath> diff --git a/group05/1094051862/test01/src/com/coding/basic/stack/Stack.java b/group05/1094051862/test01/src/com/coding/basic/stack/Stack.java index 4f4b9af52e..dd23c0c422 100644 --- a/group05/1094051862/test01/src/com/coding/basic/stack/Stack.java +++ b/group05/1094051862/test01/src/com/coding/basic/stack/Stack.java @@ -1,24 +1,42 @@ package com.coding.basic.stack; -import com.coding.basic.array.ArrayList; +import com.coding.basic.ArrayList; +import com.coding.basic.List; public class Stack { - private ArrayList elementData = new ArrayList(); - + private List elementData = new ArrayList(); + private int size = 0; public void push(Object o){ + elementData.add(o); + size ++; } public Object pop(){ - return null; + if (size == 0) + return null; + return elementData.remove(--size); } public Object peek(){ - return null; + if (size == 0) + return null; + return elementData.get(size - 1); } public boolean isEmpty(){ - return false; + return size == 0; } public int size(){ - return -1; + return size; + } + public String toString() { + StringBuffer join = new StringBuffer("["); + for(int i = 0; i < size; i++) { + join.append(elementData.get(i)); + if (i != size - 1) { + join.append(","); + } + } + join.append("]"); + return join.toString(); } } diff --git a/group05/1094051862/test01/src/com/coding/basic/stack/StackUtil.java b/group05/1094051862/test01/src/com/coding/basic/stack/StackUtil.java index 434d991447..7f834d55dd 100644 --- a/group05/1094051862/test01/src/com/coding/basic/stack/StackUtil.java +++ b/group05/1094051862/test01/src/com/coding/basic/stack/StackUtil.java @@ -8,7 +8,21 @@ public class StackUtil { * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 */ public static void reverse(Stack s) { + if (s == null || s.size() == 0) { + return; + } + Stack s1 = new Stack(); + Stack s2 = new Stack(); + + reverseTo(s, s1); + reverseTo(s1, s2); + reverseTo(s2, s); + } + private static void reverseTo(Stack s, Stack s1) { + while(!s.isEmpty()) { + s1.push(s.pop()); + } } /** @@ -17,7 +31,18 @@ public static void reverse(Stack s) { * @param o */ public static void remove(Stack s,Object o) { - + if (o == null || s == null || s.size() == 0) { + return; + } + Stack temp = new Stack(); + reverseTo(s,temp); + while(!temp.isEmpty()) { + if (temp.peek().equals(o)) { + temp.pop(); + continue; + } + s.push(temp.pop()); + } } /** @@ -27,7 +52,17 @@ public static void remove(Stack s,Object o) { * @return */ public static Object[] getTop(Stack s,int len) { - return null; + if (len <= 0 || s == null || s.size() < len) { + return null; + } + Object[] objs = new Object[len]; + for(int i = 0; i < len; i++) { + objs[i] = s.pop(); + } + for(int i = len-1; i >= 0; i--) { + s.push(objs[i]); + } + return objs; } /** * 字符串s 可能包含这些字符: ( ) [ ] { }, a,b,c... x,yz @@ -38,8 +73,41 @@ public static Object[] getTop(Stack s,int len) { * @return */ public static boolean isValidPairs(String s){ + char[] c = s.toCharArray(); + Stack headFirst = new Stack(); + Stack tailFirst = new Stack(); + int len=c.length; + for (int i = 0; i < len/2; i++) { + headFirst.push(c[i]); + tailFirst.push(c[len-1-i]); + } + return isValidPairsStack(headFirst, tailFirst); + } + + private static boolean isValidPairsStack(Stack headFirst, Stack tailFirst) { + + while (!headFirst.isEmpty() && !tailFirst.isEmpty()) { + char h = getMatchedTag(headFirst); + char t = getMatchedTag(tailFirst); + if (h == 0 || t == 0) { + return true; + } + if (!isValidPairsTag(h,t)) {// 只有此一种情况返回不匹配 + return false; + } + return isValidPairsStack(headFirst, tailFirst); + } + return true; + } + + private static boolean isValidPairsTag(char h, char t) { + // TODO Auto-generated method stub return false; } + + private static char getMatchedTag(Stack tailFirst) { + return 0; + } } From f92d3e31ec87abf06dc991cbb0fd29abe58a2b53 Mon Sep 17 00:00:00 2001 From: xmt <542194147@qq.com> Date: Tue, 11 Apr 2017 16:59:40 +0800 Subject: [PATCH 213/287] =?UTF-8?q?jvm=E8=AF=BB=E5=8F=96=E6=A8=A1=E6=95=B0?= =?UTF-8?q?=E4=BD=9C=E4=B8=9AV2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 优化完全类名的拼接方法(好吧,就是借鉴老刘的方法) --- .../jvm/loader/ClassFileLoader.java | 20 ++++- .../jvm/test/ClassFileloaderTest.java | 4 +- .../src/com/coding/basic/LRUPageFrame.java | 80 +++++++++++++++---- 3 files changed, 82 insertions(+), 22 deletions(-) diff --git a/group11/542194147/myDataStructure/src/com/coderising/jvm/loader/ClassFileLoader.java b/group11/542194147/myDataStructure/src/com/coderising/jvm/loader/ClassFileLoader.java index 7e19ae9c85..f6b93bfb41 100644 --- a/group11/542194147/myDataStructure/src/com/coderising/jvm/loader/ClassFileLoader.java +++ b/group11/542194147/myDataStructure/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -16,9 +16,20 @@ public class ClassFileLoader { 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(); + className=className.replace(".","\\")+".class"; + String absolutePath=null; + for(int i=0;i<clzPaths.size();i++){ + absolutePath=clzPaths.get(i)+"\\"+className; + byte[]codes=loadClassFile(absolutePath); + if(codes!=null){ + return codes; + } + } + return null; + } + + + private byte[] loadClassFile(String absolutePath) { File file=new File(absolutePath); FileInputStream fis = null; ByteArrayOutputStream baos=new ByteArrayOutputStream(); @@ -50,6 +61,9 @@ public byte[] readBinaryCode(String className) { public void addClassPath(String path) { + if(this.clzPaths.contains(path)){ + return; + } clzPaths.add(path); } diff --git a/group11/542194147/myDataStructure/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group11/542194147/myDataStructure/src/com/coderising/jvm/test/ClassFileloaderTest.java index 8adb2b2448..b7cf44707c 100644 --- a/group11/542194147/myDataStructure/src/com/coderising/jvm/test/ClassFileloaderTest.java +++ b/group11/542194147/myDataStructure/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -31,12 +31,12 @@ public void tearDown() throws Exception { public void testClassPath(){ ClassFileLoader loader = new ClassFileLoader(); - loader.addClassPath(path1); loader.addClassPath(path2); + loader.addClassPath(path1); String clzPath = loader.getClassPath(); - Assert.assertEquals(path1+";"+path2,clzPath); + Assert.assertEquals(path2+";"+path1,clzPath); } diff --git a/group11/542194147/myDataStructure/src/com/coding/basic/LRUPageFrame.java b/group11/542194147/myDataStructure/src/com/coding/basic/LRUPageFrame.java index d37f41e4e4..2c913ba154 100644 --- a/group11/542194147/myDataStructure/src/com/coding/basic/LRUPageFrame.java +++ b/group11/542194147/myDataStructure/src/com/coding/basic/LRUPageFrame.java @@ -2,7 +2,7 @@ /** * 用双向链表实现LRU算法 - * @author liuxin + * @author 小摩托 * */ public class LRUPageFrame { @@ -18,14 +18,14 @@ private static class Node { } private int capacity; - private int current; + private int currentSize; private Node first;// 链表头 private Node last;// 链表尾 public LRUPageFrame(int capacity) { - + this.currentSize = 0; this.capacity = capacity; } @@ -37,25 +37,71 @@ public LRUPageFrame(int capacity) { * @return */ public void access(int pageNum) { - if(current<capacity){ - current+=1; - if(current==0){ - Node node=new Node(); - node.pageNum=pageNum; - node.prev=null; - node.next=null; - first=node; - last=node; - }else{ - Node node=new Node(); - node.pageNum=pageNum; + //检查数据是否存在队列中 + Node node=findNode(pageNum); + if(node!=null){//如果存在,则提到队列头(LRU越活跃的数据越放在前面) + moveExistingNodeToHead(node); + }else{ + Node newNode=new Node(); + newNode.pageNum=pageNum; + if(currentSize>=capacity){//缓存已满删除最后的数据 + removeLastNode(); } + addNewNodeTOHead(newNode);//把新数据加到缓存头部 } - - } + private void addNewNodeTOHead(Node node) { + if(first==null&&last==null){ + first=node; + last=node; + node.next=null; + node.prev=null; + }else{ + first.prev=node; + node.prev=null; + node.next=first; + first=node; + } + currentSize++; + } + + private void removeLastNode() { + Node node=last.prev; + node.next=null; + last.prev=null; + last=node; + currentSize--; + } + + private void moveExistingNodeToHead(Node node) { + if(node==first){ + return; + }else if(node==last){ + Node prevNode=node.prev; + last=prevNode; + prevNode.next=null; + }else{ + node.prev.next=node.next; + node.next.prev=node.prev; + } + node.prev=null; + node.next=first; + first.prev=node; + first=node; + } + + private Node findNode(int data) { + Node node=first; + while(node!=null){ + if(node.pageNum==data){ + return node; + } + node=node.next; + } + return null; + } public String toString(){ StringBuilder buffer = new StringBuilder(); From 885ca6574e66dad9afec3509005e32c402e6a787 Mon Sep 17 00:00:00 2001 From: PanPan <gqp201210@qq.com> Date: Tue, 11 Apr 2017 16:59:43 +0800 Subject: [PATCH 214/287] Add files via upload --- group11/252308879/pom.xml | 140 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 group11/252308879/pom.xml diff --git a/group11/252308879/pom.xml b/group11/252308879/pom.xml new file mode 100644 index 0000000000..642387b95a --- /dev/null +++ b/group11/252308879/pom.xml @@ -0,0 +1,140 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + + <modules> + <module>data-structure</module> + <module>mini-jvm</module> + </modules> + + <groupId>com.pan</groupId> + <artifactId>252308879</artifactId> + <packaging>pom</packaging> + <version>1.0.0-SNAPSHOT</version> + + <modelVersion>4.0.0</modelVersion> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <java_source_version>1.8</java_source_version> + <java_target_version>1.8</java_target_version> + <maven_compiler_plugin_version>3.3</maven_compiler_plugin_version> + <maven_source_plugin_version>2.4</maven_source_plugin_version> + <maven_jar_plugin_version>2.5</maven_jar_plugin_version> + <maven_war_plugin_version>2.5</maven_war_plugin_version> + <maven_deploy_plugin_version>2.8.2</maven_deploy_plugin_version> + <findbugs_maven_plugin_version>2.3.1</findbugs_maven_plugin_version> + <maven_checkstyle_plugin_version>2.5</maven_checkstyle_plugin_version> + <maven_surefire_report_plugin>2.12.2</maven_surefire_report_plugin> + </properties> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>dom4j</groupId> + <artifactId>dom4j</artifactId> + <version>1.6.1</version> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + <version>3.4</version> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>2.4</version> + </dependency> + </dependencies> + </dependencyManagement> + + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>${maven_compiler_plugin_version}</version> + <configuration> + <source>${java_source_version}</source> + <target>${java_target_version}</target> + <encoding>${project.build.sourceEncoding}</encoding> + </configuration> + </plugin> + + <!-- 单元测试报告html --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-report-plugin</artifactId> + <version>${maven_surefire_report_plugin}</version> + <configuration> + <showSuccess>false</showSuccess> + </configuration> + </plugin> + + <!-- Jar package resource --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-source-plugin</artifactId> + <version>${maven_source_plugin_version}</version> + <executions> + <execution> + <id>attach-sources</id> + <goals> + <goal>jar-no-fork</goal> + </goals> + </execution> + </executions> + <configuration> + <attach>true</attach> + </configuration> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <version>${maven_jar_plugin_version}</version> + <configuration> + <archive> + <addMavenDescriptor>true</addMavenDescriptor> + </archive> + </configuration> + </plugin> + + <!-- 虽然暂时用不着 --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-war-plugin</artifactId> + <version>${maven_war_plugin_version}</version> + <configuration> + <archive> + <addMavenDescriptor>true</addMavenDescriptor> + </archive> + </configuration> + </plugin> + + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <version>${findbugs_maven_plugin_version}</version> + <configuration> + <xmlOutput>true</xmlOutput> + <xmlOutputDirectory>target/site</xmlOutputDirectory> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-checkstyle-plugin</artifactId> + <version>${maven_checkstyle_plugin_version}</version> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file From d214704ce93117fedf1465b5841f802d03c3d6a8 Mon Sep 17 00:00:00 2001 From: PanPan <gqp201210@qq.com> Date: Tue, 11 Apr 2017 17:02:20 +0800 Subject: [PATCH 215/287] Add files via upload --- group11/252308879/data-structure/pom.xml | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 group11/252308879/data-structure/pom.xml diff --git a/group11/252308879/data-structure/pom.xml b/group11/252308879/data-structure/pom.xml new file mode 100644 index 0000000000..6277256487 --- /dev/null +++ b/group11/252308879/data-structure/pom.xml @@ -0,0 +1,25 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>com.pan</groupId> + <artifactId>data-structure</artifactId> + <version>1.0.0-SNAPSHOT</version> + <packaging>jar</packaging> + + <name>data-structure</name> + <url>http://maven.apache.org</url> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>3.8.1</version> + <scope>test</scope> + </dependency> + </dependencies> +</project> From 00c2662a25e75846fb001cf5bf958ad7b287310b Mon Sep 17 00:00:00 2001 From: PanPan <gqp201210@qq.com> Date: Tue, 11 Apr 2017 17:03:33 +0800 Subject: [PATCH 216/287] Create pom.xml --- group11/252308879/mini-jvm/pom.xml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 group11/252308879/mini-jvm/pom.xml diff --git a/group11/252308879/mini-jvm/pom.xml b/group11/252308879/mini-jvm/pom.xml new file mode 100644 index 0000000000..687a89a5dc --- /dev/null +++ b/group11/252308879/mini-jvm/pom.xml @@ -0,0 +1,25 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>com.pan</groupId> + <artifactId>data-structure</artifactId> + <version>1.0.0-SNAPSHOT</version> + <packaging>jar</packaging> + + <name>data-structure</name> + <url>http://maven.apache.org</url> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>3.8.1</version> + <scope>test</scope> + </dependency> + </dependencies> +</project> From e02f4fa762e6b45c0006cdfb0849bf383173a186 Mon Sep 17 00:00:00 2001 From: ZhaoHongxin <zhaohongxin621@126.com> Date: Tue, 11 Apr 2017 17:06:03 +0800 Subject: [PATCH 217/287] =?UTF-8?q?StackUtil=20=20=20=20=20=E7=94=A8?= =?UTF-8?q?=E6=A0=88=E5=AE=8C=E6=88=90=E5=AD=97=E7=AC=A6=E4=B8=B2=E7=AC=A6?= =?UTF-8?q?=E5=8F=B7=E9=85=8D=E5=AF=B9=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/com/coding/basic/stack/StackUtil.java | 59 +++++++++---------- 1 file changed, 27 insertions(+), 32 deletions(-) diff --git a/group05/1094051862/test01/src/com/coding/basic/stack/StackUtil.java b/group05/1094051862/test01/src/com/coding/basic/stack/StackUtil.java index 7f834d55dd..cdb09886fa 100644 --- a/group05/1094051862/test01/src/com/coding/basic/stack/StackUtil.java +++ b/group05/1094051862/test01/src/com/coding/basic/stack/StackUtil.java @@ -72,42 +72,37 @@ public static Object[] getTop(Stack s,int len) { * @param s * @return */ - public static boolean isValidPairs(String s){ + public static boolean isValidPairs(String s) { char[] c = s.toCharArray(); - Stack headFirst = new Stack(); - Stack tailFirst = new Stack(); - int len=c.length; - for (int i = 0; i < len/2; i++) { - headFirst.push(c[i]); - tailFirst.push(c[len-1-i]); - } - return isValidPairsStack(headFirst, tailFirst); - } - - private static boolean isValidPairsStack(Stack headFirst, Stack tailFirst) { - - while (!headFirst.isEmpty() && !tailFirst.isEmpty()) { - char h = getMatchedTag(headFirst); - char t = getMatchedTag(tailFirst); - if (h == 0 || t == 0) { - return true; - } - if (!isValidPairsTag(h,t)) {// 只有此一种情况返回不匹配 - return false; + Stack tag = new Stack(); + for (int i = 0; i < c.length; i++) { + switch(c[i]) { + case '(': + case '[': + case '{': + tag.push(c[i]); + break; + case ')': + if (tag.isEmpty() || '(' != (char)tag.pop()) { + return false; + } + break; + case '}': + if (tag.isEmpty() || '{' != (char)tag.pop()) { + return false; + } + break; + case ']': + if (tag.isEmpty() || '[' != (char)tag.pop()) { + return false; + } + break; } - return isValidPairsStack(headFirst, tailFirst); + } + if (!tag.isEmpty()) { + return false; } return true; } - - private static boolean isValidPairsTag(char h, char t) { - // TODO Auto-generated method stub - return false; - } - - private static char getMatchedTag(Stack tailFirst) { - return 0; - } - } From af7160b85b1a7489f866d700fb71429046f29c9c Mon Sep 17 00:00:00 2001 From: ZhaoHongxin <zhaohongxin621@126.com> Date: Tue, 11 Apr 2017 17:07:20 +0800 Subject: [PATCH 218/287] StackUtilTest --- .../com/coding/basic/stack/StackUtilTest.java | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 group05/1094051862/test01/src/com/coding/basic/stack/StackUtilTest.java diff --git a/group05/1094051862/test01/src/com/coding/basic/stack/StackUtilTest.java b/group05/1094051862/test01/src/com/coding/basic/stack/StackUtilTest.java new file mode 100644 index 0000000000..31c0d72dc1 --- /dev/null +++ b/group05/1094051862/test01/src/com/coding/basic/stack/StackUtilTest.java @@ -0,0 +1,61 @@ +package com.coding.basic.stack; + +import static org.junit.Assert.*; + +import org.apache.commons.lang3.ArrayUtils; +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); + System.out.println(stack.toString()); + StackUtil.reverse(stack); + System.out.println(stack.toString()); + } + + @Test + public void testRemove() { + Stack stack = new Stack(); + stack.push(1); + stack.push(2); + stack.push(3); + stack.push(4); + stack.push(5); + System.out.println(stack.toString()); + StackUtil.remove(stack, 5); + System.out.println(stack.toString()); + StackUtil.remove(stack, 2); + System.out.println(stack.toString()); + } + + @Test + public void testGetTop() { + Stack stack = new Stack(); + stack.push(1); + stack.push(2); + stack.push(3); + stack.push(4); + stack.push(5); + System.out.println(stack.toString()); + Object[] top = StackUtil.getTop(stack, 3); + System.out.println(ArrayUtils.toString(top, null)); + System.out.println(stack.toString()); + } + + @Test + public void testIsValidPairs() { + String str = "sdf{sdf[sdf]sdfsdff}"; + String str2 = "[sdf(sdf{sdf]}sdf)"; + Assert.assertTrue(StackUtil.isValidPairs(str)); + Assert.assertTrue(!StackUtil.isValidPairs(str2)); + } + +} From c75c75d865cbd67227e0ed8042c6464b5f74411f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BE=9A=E5=90=AF=E7=9B=BC?= <gongqipan@qipeipu.com> Date: Tue, 11 Apr 2017 17:14:28 +0800 Subject: [PATCH 219/287] parent --- group11/252308879/data-structure/pom.xml | 46 ++++++++++++--------- group11/252308879/mini-jvm/pom.xml | 51 +++++++++++++++--------- 2 files changed, 59 insertions(+), 38 deletions(-) diff --git a/group11/252308879/data-structure/pom.xml b/group11/252308879/data-structure/pom.xml index 6277256487..8725d8517b 100644 --- a/group11/252308879/data-structure/pom.xml +++ b/group11/252308879/data-structure/pom.xml @@ -1,25 +1,33 @@ <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> - <groupId>com.pan</groupId> - <artifactId>data-structure</artifactId> - <version>1.0.0-SNAPSHOT</version> - <packaging>jar</packaging> + <parent> + <groupId>com.pan</groupId> + <artifactId>252308879</artifactId> + <version>1.0.0-SNAPSHOT</version> + </parent> - <name>data-structure</name> - <url>http://maven.apache.org</url> + <groupId>com.pan</groupId> + <artifactId>data-structure</artifactId> + <version>1.0.0-SNAPSHOT</version> + <packaging>jar</packaging> - <properties> - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - </properties> + <name>data-structure</name> + <url>http://maven.apache.org</url> - <dependencies> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <version>3.8.1</version> - <scope>test</scope> - </dependency> - </dependencies> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </dependency> + <dependency> + <groupId>dom4j</groupId> + <artifactId>dom4j</artifactId> + </dependency> + </dependencies> </project> diff --git a/group11/252308879/mini-jvm/pom.xml b/group11/252308879/mini-jvm/pom.xml index 687a89a5dc..d1bd424bc7 100644 --- a/group11/252308879/mini-jvm/pom.xml +++ b/group11/252308879/mini-jvm/pom.xml @@ -1,25 +1,38 @@ <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> - <groupId>com.pan</groupId> - <artifactId>data-structure</artifactId> - <version>1.0.0-SNAPSHOT</version> - <packaging>jar</packaging> + <parent> + <groupId>com.pan</groupId> + <artifactId>252308879</artifactId> + <version>1.0.0-SNAPSHOT</version> + </parent> - <name>data-structure</name> - <url>http://maven.apache.org</url> + <groupId>com.pan</groupId> + <artifactId>mini-jvm</artifactId> + <version>1.0.0-SNAPSHOT</version> + <packaging>jar</packaging> - <properties> - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - </properties> + <name>mini-jvm</name> + <url>http://maven.apache.org</url> - <dependencies> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <version>3.8.1</version> - <scope>test</scope> - </dependency> - </dependencies> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + </dependency> + </dependencies> </project> From 8afbe08dcf65dcbc45b4dbe56acadd5e52e65290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BE=9A=E5=90=AF=E7=9B=BC?= <gongqipan@qipeipu.com> Date: Tue, 11 Apr 2017 17:19:40 +0800 Subject: [PATCH 220/287] clean and compile --- group11/252308879/data-structure/pom.xml | 36 ++++++++++++++++++++++++ group11/252308879/mini-jvm/pom.xml | 35 +++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/group11/252308879/data-structure/pom.xml b/group11/252308879/data-structure/pom.xml index 8725d8517b..445ba45741 100644 --- a/group11/252308879/data-structure/pom.xml +++ b/group11/252308879/data-structure/pom.xml @@ -30,4 +30,40 @@ <artifactId>dom4j</artifactId> </dependency> </dependencies> + + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + </plugin> + + <!-- 单元测试报告html --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-report-plugin</artifactId> + </plugin> + + <!-- Jar package resource --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-source-plugin</artifactId> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + </plugin> + + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-checkstyle-plugin</artifactId> + </plugin> + </plugins> + </build> </project> diff --git a/group11/252308879/mini-jvm/pom.xml b/group11/252308879/mini-jvm/pom.xml index d1bd424bc7..9487a16199 100644 --- a/group11/252308879/mini-jvm/pom.xml +++ b/group11/252308879/mini-jvm/pom.xml @@ -35,4 +35,39 @@ <artifactId>commons-io</artifactId> </dependency> </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + </plugin> + + <!-- 单元测试报告html --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-report-plugin</artifactId> + </plugin> + + <!-- Jar package resource --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-source-plugin</artifactId> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + </plugin> + + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-checkstyle-plugin</artifactId> + </plugin> + </plugins> + </build> </project> From 8d670e65341038f06f2ff71a5d10ad3084c7523b Mon Sep 17 00:00:00 2001 From: x_zhaohu <x_zhaohu@163.com> Date: Tue, 11 Apr 2017 18:20:54 +0800 Subject: [PATCH 221/287] update error --- group11/1178243325/week03/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/group11/1178243325/week03/readme.md b/group11/1178243325/week03/readme.md index e418f46fd6..5de5dada98 100644 --- a/group11/1178243325/week03/readme.md +++ b/group11/1178243325/week03/readme.md @@ -3,7 +3,7 @@ - 17-03-09:TDD和第二次作业讲解 - 17-03-12:职场15年 -## 第二周作业(3-6 至 3-12) +## 第三周作业(3-6 至 3-12) - 实现第二个大作业:多线程下载文件,支持断点续传 - 5道数据结构习题 From 2c7a3cfe00d7fa16e6ba171aa76fa0f0ae7ad5e4 Mon Sep 17 00:00:00 2001 From: x_zhaohu <x_zhaohu@163.com> Date: Tue, 11 Apr 2017 18:21:14 +0800 Subject: [PATCH 222/287] =?UTF-8?q?=E7=AC=AC=E5=9B=9B=E6=AC=A1=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group11/1178243325/week06/readme.md | 13 +- .../java/com/sprint/basic/LRUPageFrame.java | 117 ++++++++++++++++++ .../java/com/sprint/jvm/clz/AccessFlag.java | 25 ---- .../java/com/sprint/jvm/clz/ClassFile.java | 70 +---------- .../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 | 12 ++ .../sprint/jvm/loader/ClassFileLoader.java | 39 +++--- .../sprint/jvm/loader/ClassFileParser.java | 25 ++-- .../main/java/com/sprint/jvm/util/Util.java | 17 +++ .../com/sprint/basic/LRUPageFrameTest.java | 33 +++++ .../jvm/loader/ClassFileLoaderTest.java | 11 +- 15 files changed, 224 insertions(+), 280 deletions(-) create mode 100644 group11/1178243325/week06/src/main/java/com/sprint/basic/LRUPageFrame.java delete mode 100644 group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/AccessFlag.java delete mode 100644 group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/ClassIndex.java delete mode 100644 group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/ClassInfo.java delete mode 100644 group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/ConstantInfo.java delete mode 100644 group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/ConstantPool.java delete 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/util/Util.java create mode 100644 group11/1178243325/week06/src/test/java/com/sprint/basic/LRUPageFrameTest.java diff --git a/group11/1178243325/week06/readme.md b/group11/1178243325/week06/readme.md index d32158bcdf..d89a5c904e 100644 --- a/group11/1178243325/week06/readme.md +++ b/group11/1178243325/week06/readme.md @@ -1,11 +1,16 @@ ## 讲课内容: -- 17-03-29 :JVM之classLoader +- 17-03-27:JVM第一周 +- 17-03-29:JVM之classLoader ## 第六周作业(3-27 至 04-02) -读取常量池 +- 完成对一个.class文件的读取和对.class文件开头四个字节的魔数的判断需要实现ClassLoader.java +- 实现LRU算法 +- 一篇文章 ## 完成情况: -未补 +- ClassLoader.java已完 +- LRU已完 +- [文章](http://www.jianshu.com/p/02a8b4ee4596) ## 我的收获: - +使用开源工具读取文件,并利用工作类进行字符转换.LRU算法(双链表操作),但是更重要的抽象化思想. diff --git a/group11/1178243325/week06/src/main/java/com/sprint/basic/LRUPageFrame.java b/group11/1178243325/week06/src/main/java/com/sprint/basic/LRUPageFrame.java new file mode 100644 index 0000000000..0a2febd715 --- /dev/null +++ b/group11/1178243325/week06/src/main/java/com/sprint/basic/LRUPageFrame.java @@ -0,0 +1,117 @@ +package com.sprint.basic; + +public class LRUPageFrame { + + /** + * 用双向链表实现LRU算法 + */ + + 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; + } + + /** + * + */ + 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 Node find(int pageNum) { + Node node = first; + while (node != null) { + if (node.pageNum == pageNum) { + return node; + } + node = node.next; + } + return null; + } + + 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 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 void removeLast() { + Node prev = last.prev; + prev.next = null; + last.prev = null; + last = prev; + this.currentSize--; + } + + 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 boolean isEmpty() { + return (first == null) && (last == null); + } + @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/group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/AccessFlag.java b/group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/AccessFlag.java deleted file mode 100644 index e74740aa3e..0000000000 --- a/group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/AccessFlag.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.sprint.jvm.clz; - -public class AccessFlag { - private int flagValue; - - public AccessFlag(int value) { - this.flagValue = value; - } - - public int getFlagValue() { - return flagValue; - } - - public void setFlagValue(int flagValue) { - this.flagValue = flagValue; - } - - public boolean isPublicClass() { - return (this.flagValue & 0x0001) != 0; - } - - public boolean isFinalClass() { - return (this.flagValue & 0x0010) != 0; - } -} diff --git a/group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/ClassFile.java b/group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/ClassFile.java index 637cd63592..c40c88b183 100644 --- a/group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/ClassFile.java +++ b/group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/ClassFile.java @@ -1,71 +1,9 @@ package com.sprint.jvm.clz; -import com.sprint.jvm.constant.ConstantPool; -import com.sprint.jvm.constant.ClassInfo; public class ClassFile { - private int minorVersion; - private int majorVersion; - - private AccessFlag accessFlag; - private ClassIndex clzIndex; - private ConstantPool 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 AccessFlag getAccessFlag() { - return accessFlag; - } - - public void setAccessFlag(AccessFlag accessFlag) { - this.accessFlag = accessFlag; - } - - public ClassIndex getClzIndex() { - return clzIndex; - } - - public void setClzIndex(ClassIndex clzIndex) { - this.clzIndex = clzIndex; - } - - public ConstantPool getConstantPool() { - return 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("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(); + private final String cafebabe = "cafebabe"; + + public String getCafebabe() { + return cafebabe; } } diff --git a/group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/ClassIndex.java b/group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/ClassIndex.java deleted file mode 100644 index 46e7443d90..0000000000 --- a/group11/1178243325/week06/src/main/java/com/sprint/jvm/clz/ClassIndex.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.sprint.jvm.clz; - -public class ClassIndex { - private int thisClassIndex; - private int superClassIndex; - - public int getThisClassIndex() { - return thisClassIndex; - } - - public void setThisClassIndex(int index) { - this.thisClassIndex = index; - } - - public int getSuperClassIndex() { - return superClassIndex; - } - - public void setSuperClassIndex(int index) { - this.superClassIndex = index; - } -} diff --git a/group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/ClassInfo.java b/group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/ClassInfo.java deleted file mode 100644 index b8da3c656d..0000000000 --- a/group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/ClassInfo.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.sprint.jvm.constant; - -public class ClassInfo extends ConstantInfo { - private int type = ConstantInfo.CLASS_INFO; - private int utf8Index; - - public ClassInfo(ConstantPool pool) { - super(pool); - } - - public void setUtf8Index(int index) { - this.utf8Index = index; - } - - public int getUtf8Index() { - return utf8Index; - } - - public int getType() { - return type; - } - - public String getClassName() { - int index = getUtf8Index(); - UTF8Info utf8Info = (UTF8Info)constantPool.getConstantInfo(index); - return utf8Info.getValue(); - } -} diff --git a/group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/ConstantInfo.java b/group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/ConstantInfo.java deleted file mode 100644 index a8db82689e..0000000000 --- a/group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/ConstantInfo.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.sprint.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/group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/ConstantPool.java b/group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/ConstantPool.java deleted file mode 100644 index 3a35c22ce0..0000000000 --- a/group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/ConstantPool.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.sprint.jvm.constant; - -import java.util.ArrayList; -import java.util.List; - -public class ConstantPool { - private List<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); - - 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 deleted file mode 100644 index 5516999c0e..0000000000 --- a/group11/1178243325/week06/src/main/java/com/sprint/jvm/constant/UTF8Info.java +++ /dev/null @@ -1,35 +0,0 @@ -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 index 3144d5828d..445519b3be 100644 --- 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 @@ -1,5 +1,17 @@ package com.sprint.jvm.loader; +import com.sprint.jvm.util.Util; +import java.util.Arrays; public class ByteCodeIterator { + byte[] codes; + int pos = 0; + ByteCodeIterator(byte[] codes) { + this.codes = codes; + } + + public String nextU4ToHexString() { + return Util.byteToHexString(new byte[] {codes[pos++], codes[pos++], codes[pos++], codes[pos++]}); + } + } 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 index f190f54915..1191be47eb 100644 --- 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 @@ -10,10 +10,24 @@ import org.apache.commons.lang3.StringUtils; public class ClassFileLoader { - private List<String> clzPaths = new ArrayList<String>(); - public byte[] readBinaryCode(String className) { + List<String> clzPaths = new ArrayList<>(); + + public ClassFile loadClass(String className) { + byte[] codes = this.readBinaryCode(className); + ClassFileParser parser = new ClassFileParser(); + return parser.parse(codes); + } + + public void addClassPath(String clzPath) { + if (this.clzPaths.contains(clzPath)) { + return; + } + this.clzPaths.add(clzPath); + } + + private byte[] readBinaryCode(String className) { className = className.replace('.', File.separatorChar) + ".class"; - for (String path : this.clzPaths) { + for (String path : clzPaths) { String clzFileName = path + File.separatorChar + className; byte[] codes = loadClassFile(clzFileName); if (codes != null) { @@ -27,26 +41,9 @@ private byte[] loadClassFile(String clzFileName) { File f = new File(clzFileName); try { return IOUtils.toByteArray(new FileInputStream(f)); - } catch(IOException e) { + } 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 index 4c32858fa4..229e7db360 100644 --- 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 @@ -1,25 +1,14 @@ 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; + ClassFile clzFile = new ClassFile(); + ByteCodeIterator iter = new ByteCodeIterator(codes); + String magicNumber = iter.nextU4ToHexString(); + if (!"cafebabe".equals(magicNumber)) { + return null; + } + return clzFile; } - - 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/main/java/com/sprint/jvm/util/Util.java b/group11/1178243325/week06/src/main/java/com/sprint/jvm/util/Util.java new file mode 100644 index 0000000000..6081635316 --- /dev/null +++ b/group11/1178243325/week06/src/main/java/com/sprint/jvm/util/Util.java @@ -0,0 +1,17 @@ +package com.sprint.jvm.util; + +public class Util { + 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/group11/1178243325/week06/src/test/java/com/sprint/basic/LRUPageFrameTest.java b/group11/1178243325/week06/src/test/java/com/sprint/basic/LRUPageFrameTest.java new file mode 100644 index 0000000000..ac28668dbe --- /dev/null +++ b/group11/1178243325/week06/src/test/java/com/sprint/basic/LRUPageFrameTest.java @@ -0,0 +1,33 @@ +package com.sprint.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()); + + } + +} 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 index 6795595e89..d3d84b414f 100644 --- 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 @@ -7,14 +7,17 @@ public class ClassFileLoaderTest { private static final String FULL_QUALTFIED_CLASS_NAME = "com/sprint/jvm/EmployeeV1"; - static String path1 = ""; - static String path2 = ""; + static String path1 = "/home/sprint/java/code/coding2017/group11/1178243325/week06/build/classes/test"; static ClassFile clzFile = null; static { ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); - String className = "com.sprint.jvm.EmployeeV1"; + String className = "com.sprint.jvm.loader.EmployeeV1"; clzFile = loader.loadClass(className); - clzFile.print(); + } + + @Test + public void test() { + Assert.assertEquals("cafebabe", clzFile.getCafebabe()); } } From a260cd7a7f7c141fe312dd9f0ce8558415507f88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BE=9A=E5=90=AF=E7=9B=BC?= <gongqipan@qipeipu.com> Date: Tue, 11 Apr 2017 19:15:04 +0800 Subject: [PATCH 223/287] jvm --- ...ileLoader.java => ClassFileLoaderTmp.java} | 2 +- .../src/main/java/com/pan/jvm/EmployeeV1.java | 31 +++++++++++++++++ .../com/pan/jvm/loader/ClassFileLoader.java | 26 -------------- .../java/com/pan/alg/LRUPageFrameTest.java | 34 +++++++++++++++++++ .../src/test/java/com/pan/jvm/EmployeeV1.java | 31 +++++++++++++++++ .../test/java/com/pan/jvm/TestReadCFBB.java | 31 +++++++++++++++++ 6 files changed, 128 insertions(+), 27 deletions(-) rename group11/252308879/mini-jvm/src/main/java/com/pan/jvm/{ClassFileLoader.java => ClassFileLoaderTmp.java} (97%) create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/jvm/EmployeeV1.java create mode 100644 group11/252308879/mini-jvm/src/test/java/com/pan/alg/LRUPageFrameTest.java create mode 100644 group11/252308879/mini-jvm/src/test/java/com/pan/jvm/EmployeeV1.java diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/ClassFileLoader.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/ClassFileLoaderTmp.java similarity index 97% rename from group11/252308879/mini-jvm/src/main/java/com/pan/jvm/ClassFileLoader.java rename to group11/252308879/mini-jvm/src/main/java/com/pan/jvm/ClassFileLoaderTmp.java index 0961c5ddd5..340f6599c6 100644 --- a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/ClassFileLoader.java +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/ClassFileLoaderTmp.java @@ -7,7 +7,7 @@ import java.util.ArrayList; import java.util.List; -public class ClassFileLoader { +public class ClassFileLoaderTmp { private List<String> clzPaths = new ArrayList<String>(); int countForClassPath = 0; int countForReadBinaryCode = 0; diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/EmployeeV1.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/EmployeeV1.java new file mode 100644 index 0000000000..92b5b403ca --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/EmployeeV1.java @@ -0,0 +1,31 @@ +package com.pan.jvm; + +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/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileLoader.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileLoader.java index a21d246399..c1d0553522 100644 --- a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileLoader.java +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileLoader.java @@ -18,31 +18,21 @@ public class ClassFileLoader { private List<String> 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; @@ -54,9 +44,7 @@ public void addClassPath(String path) { if (this.clzPaths.contains(path)) { return; } - this.clzPaths.add(path); - } @@ -74,7 +62,6 @@ public ClassFile loadClass(String className) { // ------------------------------backup------------------------ public String getClassPath_V1() { - StringBuffer buffer = new StringBuffer(); for (int i = 0; i < this.clzPaths.size(); i++) { buffer.append(this.clzPaths.get(i)); @@ -88,31 +75,19 @@ public String getClassPath_V1() { 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 { @@ -123,7 +98,6 @@ private byte[] loadClassFile_V1(String clzFileName) { } } return null; - } diff --git a/group11/252308879/mini-jvm/src/test/java/com/pan/alg/LRUPageFrameTest.java b/group11/252308879/mini-jvm/src/test/java/com/pan/alg/LRUPageFrameTest.java new file mode 100644 index 0000000000..8f6803c11f --- /dev/null +++ b/group11/252308879/mini-jvm/src/test/java/com/pan/alg/LRUPageFrameTest.java @@ -0,0 +1,34 @@ +package com.pan.alg; + +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()); + + } + +} diff --git a/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/EmployeeV1.java b/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/EmployeeV1.java new file mode 100644 index 0000000000..92b5b403ca --- /dev/null +++ b/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/EmployeeV1.java @@ -0,0 +1,31 @@ +package com.pan.jvm; + +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/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/TestReadCFBB.java b/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/TestReadCFBB.java index 5523fa7696..8590e78c09 100644 --- a/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/TestReadCFBB.java +++ b/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/TestReadCFBB.java @@ -1,10 +1,41 @@ package com.pan.jvm; +import com.pan.jvm.loader.ClassFileLoader; +import org.junit.Test; + +import java.io.IOException; + /** * 用于测试第一次JVM作业,读取.class作业 和 魔幻数字 */ public class TestReadCFBB { + @Test + public void testClassPath(){ + ClassFileLoader classFileLoader = new ClassFileLoader(); + String path = ClassFileLoader.class.getClassLoader().getResource("").getPath(); + path = path.replace("test-classes", "classes"); + classFileLoader.addClassPath(path); + classFileLoader.addClassPath("d://tmp"); + + String clzPath = classFileLoader.getClassPath(); + System.out.println(clzPath); + } + + + + @Test + public void testReadCFBB() throws IOException { + ClassFileLoader classFileLoader = new ClassFileLoader(); + String path = ClassFileLoader.class.getClassLoader().getResource("").getPath(); + path = path.replace("test-classes", "classes"); + classFileLoader.addClassPath(path); + byte[] bytes = classFileLoader.readBinaryCode("com.pan.jvm.loader.ClassFileLoader"); + for (byte b : bytes) { + String toHexString = Integer.toHexString(b & 0xFF).toUpperCase(); + System.out.print(toHexString + " "); + } + } } From c9e1a1f774c5d87b306a1a41dfce61a5064bf183 Mon Sep 17 00:00:00 2001 From: DonaldY <448641125@qq.com> Date: Tue, 11 Apr 2017 19:25:20 +0800 Subject: [PATCH 224/287] expr finished whithout encapsulation --- .../src/com/donaldy/basic/ArrayList.java | 2 +- .../src/com/donaldy/basic/Stack.java | 8 +- .../src/com/donaldy/basic/expr/InfixExpr.java | 140 ++++++++++++++++++ .../com/donaldy/basic/expr/InfixExprTest.java | 48 ++++++ .../donaldy/jvm/loader/ClassFileParser.java | 4 +- 5 files changed, 195 insertions(+), 7 deletions(-) create mode 100644 group24/448641125/src/com/donaldy/basic/expr/InfixExpr.java create mode 100644 group24/448641125/src/com/donaldy/basic/expr/InfixExprTest.java diff --git a/group24/448641125/src/com/donaldy/basic/ArrayList.java b/group24/448641125/src/com/donaldy/basic/ArrayList.java index b4528176c1..859ebaf75f 100644 --- a/group24/448641125/src/com/donaldy/basic/ArrayList.java +++ b/group24/448641125/src/com/donaldy/basic/ArrayList.java @@ -27,7 +27,7 @@ public void add(int index, Object o){ private void ensureCupacity(int capacitySize){ if (capacitySize >= MAXNSIZE) - throw new RuntimeException(); + throw new RuntimeException("capacitySize : " + capacitySize); } public void clear() { diff --git a/group24/448641125/src/com/donaldy/basic/Stack.java b/group24/448641125/src/com/donaldy/basic/Stack.java index 22fcbbf4bd..ed500638d1 100644 --- a/group24/448641125/src/com/donaldy/basic/Stack.java +++ b/group24/448641125/src/com/donaldy/basic/Stack.java @@ -4,15 +4,15 @@ public class Stack { private ArrayList elementData = new ArrayList(); public void push(Object o) { - elementData.add(o); + this.elementData.add(o); } public Object pop() { - return elementData.remove(size() - 1); + return this.elementData.remove(size() - 1); } public Object peek() { - return elementData.get(size() - 1); + return this.elementData.get(size() - 1); } public boolean isEmpty() { @@ -20,6 +20,6 @@ public boolean isEmpty() { } public int size(){ - return elementData.size(); + return this.elementData.size(); } } diff --git a/group24/448641125/src/com/donaldy/basic/expr/InfixExpr.java b/group24/448641125/src/com/donaldy/basic/expr/InfixExpr.java new file mode 100644 index 0000000000..dfd901febb --- /dev/null +++ b/group24/448641125/src/com/donaldy/basic/expr/InfixExpr.java @@ -0,0 +1,140 @@ +package com.donaldy.basic.expr; + +import com.donaldy.basic.Stack; + +/** + * 针对最后一个用例,expr: 10 - 30 + 50; + * 负数,直接对后面的数进行取反(实际上计算机就是这样做的,组原有提。) + * 即:expr: 10 - 30 + 50 + * 处理后: 10 + -30 + 50 + */ +public class InfixExpr { + + String expr = null; + + Stack numStack = new Stack(); + Stack symbolStack = new Stack(); + + public InfixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + + if (!this.numStack.isEmpty()) + return (float) this.numStack.peek(); + + char [] arr = this.expr.toCharArray(); + + parseCharArray(arr); + + remainOperate(); + + return (float) this.numStack.peek(); + } + + private void parseCharArray(char [] arr) { + + for (int i = 0; i < arr.length; ) { + + i = parseNumberReturnIndex(i, arr); + + if (i >= arr.length) + break; + + i = parseSymbolReturnIndex(i, arr); + } + } + + private int parseNumberReturnIndex(int index, char [] arr) { + if (arr[index] <= '9' && arr[index] >= '0' ) { + + float value = arr[index ++] - '0'; + + while (index < arr.length && arr[index] <= '9' && arr[index] >= '0' ) { + value *= 10; + value += arr[index] - '0'; + index ++; + } + this.numStack.push(value); + } + + return index; + } + + private int parseSymbolReturnIndex(int index, char[] arr) { + + if ("+-*/".contains(arr[index] + "")) { + + char operator = arr[index ++]; + + if (operator == '+') { + this.symbolStack.push('+'); + } + + if (operator == '-') { + + this.symbolStack.push('+'); + + float value = arr[index ++] - '0'; + + while (index < arr.length && arr[index] <= '9' && arr[index] >= '0') { + value *= 10; + value += arr[index] - '0'; + index ++; + } + + this.numStack.push(-value); + } + + if (operator == '*' || operator == '/') { + + float value1 = (float) this.numStack.pop(); + float value2 = arr[index ++] - '0'; + + while (index < arr.length && arr[index] <= '9' && arr[index] >= '0') { + value2 *= 10; + value2 += arr[index] - '0'; + index ++; + } + + this.numStack.push(operate(value2, value1, operator)); + + } + + } + + return index; + } + + private void remainOperate() { + while (!this.symbolStack.isEmpty()) { + if (this.numStack.size() < 2 || this.symbolStack.size() < 1) + throw new IndexOutOfBoundsException("numStack.size : " + this.numStack.size() + + " symbolStack.size : " + this.symbolStack.size()); + + float value1 = (float) this.numStack.pop(); + float value2 = (float) this.numStack.pop(); + char cSymbol = (char) this.symbolStack.pop(); + + this.numStack.push(operate(value1, value2, cSymbol)); + } + } + + + private float operate (float value1, float value2, char operator) { + + if (operator == '+') { + return value2 + value1; + } else if (operator == '*') { + return value2 * value1; + } else if (operator == '/') { + return value2 / value1; + } else { + throw new RuntimeException("No this operator : " + operator); + } + + } + + +} diff --git a/group24/448641125/src/com/donaldy/basic/expr/InfixExprTest.java b/group24/448641125/src/com/donaldy/basic/expr/InfixExprTest.java new file mode 100644 index 0000000000..47afcec569 --- /dev/null +++ b/group24/448641125/src/com/donaldy/basic/expr/InfixExprTest.java @@ -0,0 +1,48 @@ +package com.donaldy.basic.expr; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class InfixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + //InfixExpr expr = new InfixExpr("300*20+12*5-20/4"); + { + InfixExpr expr = new InfixExpr("2+3*4+5"); + Assert.assertEquals(19.0, expr.evaluate(), 0.001f); + } + { + InfixExpr expr = new InfixExpr("3*20+12*5-40/2"); + Assert.assertEquals(100.0, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("3*20/2"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("20/2*3"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("10-30+50"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + } + +} diff --git a/group24/448641125/src/com/donaldy/jvm/loader/ClassFileParser.java b/group24/448641125/src/com/donaldy/jvm/loader/ClassFileParser.java index 395e989426..dffafe3834 100644 --- a/group24/448641125/src/com/donaldy/jvm/loader/ClassFileParser.java +++ b/group24/448641125/src/com/donaldy/jvm/loader/ClassFileParser.java @@ -5,9 +5,7 @@ import com.donaldy.jvm.clz.ClassIndex; import com.donaldy.jvm.constant.*; -import javax.lang.model.element.Name; import java.io.UnsupportedEncodingException; -import java.lang.reflect.Method; public class ClassFileParser { @@ -46,11 +44,13 @@ private AccessFlag parseAccessFlag(ByteCodeIterator iter) { private ClassIndex parseClassIndex(ByteCodeIterator iter) { int thisClassIndex = iter.nextU2ToInt(); + int superClassIndex = iter.nextU2ToInt(); ClassIndex clzIndex = new ClassIndex(); clzIndex.setThisClassIndex(thisClassIndex); + clzIndex.setSuperClassIndex(superClassIndex); return clzIndex; From 89980b6e07fa54772cbc72c70a2ba34b5c90682a Mon Sep 17 00:00:00 2001 From: HuiZhou-Xmu <1814014897@qq.com> Date: Tue, 11 Apr 2017 19:57:28 +0800 Subject: [PATCH 225/287] =?UTF-8?q?=E7=AC=AC=E4=BA=94=E5=91=A8=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group01/1814014897/zhouhui/.classpath | 2 + .../src/week05/jvm/clz/AccessFlag.java | 25 +++ .../zhouhui/src/week05/jvm/clz/ClassFile.java | 75 +++++++ .../src/week05/jvm/clz/ClassIndex.java | 19 ++ .../src/week05/jvm/constant/ClassInfo.java | 24 +++ .../src/week05/jvm/constant/ConstantInfo.java | 29 +++ .../src/week05/jvm/constant/ConstantPool.java | 29 +++ .../src/week05/jvm/constant/FieldRefInfo.java | 54 +++++ .../week05/jvm/constant/MethodRefInfo.java | 55 +++++ .../week05/jvm/constant/NameAndTypeInfo.java | 45 ++++ .../week05/jvm/constant/NullConstantInfo.java | 13 ++ .../src/week05/jvm/constant/StringInfo.java | 26 +++ .../src/week05/jvm/constant/UTF8Info.java | 32 +++ .../week05/jvm/loader/ByteCodeIterator.java | 37 ++++ .../week05/jvm/loader/ClassFileLoader.java | 134 ++++++++++++ .../week05/jvm/loader/ClassFileParser.java | 132 ++++++++++++ .../week05/jvm/test/ClassFileloaderTest.java | 199 ++++++++++++++++++ .../src/week05/jvm/test/EmployeeV1.java | 28 +++ .../zhouhui/src/week05/jvm/util/Util.java | 24 +++ .../zhouhui/src/week05/stack/Stack.java | 27 +++ .../zhouhui/src/week05/stack/StackUtil.java | 114 ++++++++++ .../src/week05/stack/StackUtilTest.java | 62 ++++++ 22 files changed, 1185 insertions(+) create mode 100644 group01/1814014897/zhouhui/src/week05/jvm/clz/AccessFlag.java create mode 100644 group01/1814014897/zhouhui/src/week05/jvm/clz/ClassFile.java create mode 100644 group01/1814014897/zhouhui/src/week05/jvm/clz/ClassIndex.java create mode 100644 group01/1814014897/zhouhui/src/week05/jvm/constant/ClassInfo.java create mode 100644 group01/1814014897/zhouhui/src/week05/jvm/constant/ConstantInfo.java create mode 100644 group01/1814014897/zhouhui/src/week05/jvm/constant/ConstantPool.java create mode 100644 group01/1814014897/zhouhui/src/week05/jvm/constant/FieldRefInfo.java create mode 100644 group01/1814014897/zhouhui/src/week05/jvm/constant/MethodRefInfo.java create mode 100644 group01/1814014897/zhouhui/src/week05/jvm/constant/NameAndTypeInfo.java create mode 100644 group01/1814014897/zhouhui/src/week05/jvm/constant/NullConstantInfo.java create mode 100644 group01/1814014897/zhouhui/src/week05/jvm/constant/StringInfo.java create mode 100644 group01/1814014897/zhouhui/src/week05/jvm/constant/UTF8Info.java create mode 100644 group01/1814014897/zhouhui/src/week05/jvm/loader/ByteCodeIterator.java create mode 100644 group01/1814014897/zhouhui/src/week05/jvm/loader/ClassFileLoader.java create mode 100644 group01/1814014897/zhouhui/src/week05/jvm/loader/ClassFileParser.java create mode 100644 group01/1814014897/zhouhui/src/week05/jvm/test/ClassFileloaderTest.java create mode 100644 group01/1814014897/zhouhui/src/week05/jvm/test/EmployeeV1.java create mode 100644 group01/1814014897/zhouhui/src/week05/jvm/util/Util.java create mode 100644 group01/1814014897/zhouhui/src/week05/stack/Stack.java create mode 100644 group01/1814014897/zhouhui/src/week05/stack/StackUtil.java create mode 100644 group01/1814014897/zhouhui/src/week05/stack/StackUtilTest.java diff --git a/group01/1814014897/zhouhui/.classpath b/group01/1814014897/zhouhui/.classpath index 373dce4005..fd40ed3fdb 100644 --- a/group01/1814014897/zhouhui/.classpath +++ b/group01/1814014897/zhouhui/.classpath @@ -3,5 +3,7 @@ <classpathentry kind="src" path="src"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/> + <classpathentry kind="lib" path="D:/Program Files/Java/jdk1.8.0_74/lib/commons-io-2.5.jar"/> + <classpathentry kind="lib" path="D:/Program Files/Java/jdk1.8.0_74/lib/commons-lang3-3.5.jar"/> <classpathentry kind="output" path="bin"/> </classpath> diff --git a/group01/1814014897/zhouhui/src/week05/jvm/clz/AccessFlag.java b/group01/1814014897/zhouhui/src/week05/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..b843c8917e --- /dev/null +++ b/group01/1814014897/zhouhui/src/week05/jvm/clz/AccessFlag.java @@ -0,0 +1,25 @@ +package week05.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/group01/1814014897/zhouhui/src/week05/jvm/clz/ClassFile.java b/group01/1814014897/zhouhui/src/week05/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..3969967b24 --- /dev/null +++ b/group01/1814014897/zhouhui/src/week05/jvm/clz/ClassFile.java @@ -0,0 +1,75 @@ +package week05.jvm.clz; + +import week05.jvm.constant.ClassInfo; +import week05.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/group01/1814014897/zhouhui/src/week05/jvm/clz/ClassIndex.java b/group01/1814014897/zhouhui/src/week05/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..31fb6f9eea --- /dev/null +++ b/group01/1814014897/zhouhui/src/week05/jvm/clz/ClassIndex.java @@ -0,0 +1,19 @@ +package week05.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/group01/1814014897/zhouhui/src/week05/jvm/constant/ClassInfo.java b/group01/1814014897/zhouhui/src/week05/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..6756c37efa --- /dev/null +++ b/group01/1814014897/zhouhui/src/week05/jvm/constant/ClassInfo.java @@ -0,0 +1,24 @@ +package week05.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/group01/1814014897/zhouhui/src/week05/jvm/constant/ConstantInfo.java b/group01/1814014897/zhouhui/src/week05/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..91db6cd7ee --- /dev/null +++ b/group01/1814014897/zhouhui/src/week05/jvm/constant/ConstantInfo.java @@ -0,0 +1,29 @@ +package week05.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/group01/1814014897/zhouhui/src/week05/jvm/constant/ConstantPool.java b/group01/1814014897/zhouhui/src/week05/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..352b55bc23 --- /dev/null +++ b/group01/1814014897/zhouhui/src/week05/jvm/constant/ConstantPool.java @@ -0,0 +1,29 @@ +package week05.jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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/1814014897/zhouhui/src/week05/jvm/constant/FieldRefInfo.java b/group01/1814014897/zhouhui/src/week05/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..4827d6d90a --- /dev/null +++ b/group01/1814014897/zhouhui/src/week05/jvm/constant/FieldRefInfo.java @@ -0,0 +1,54 @@ +package week05.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/group01/1814014897/zhouhui/src/week05/jvm/constant/MethodRefInfo.java b/group01/1814014897/zhouhui/src/week05/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..d310854127 --- /dev/null +++ b/group01/1814014897/zhouhui/src/week05/jvm/constant/MethodRefInfo.java @@ -0,0 +1,55 @@ +package week05.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/group01/1814014897/zhouhui/src/week05/jvm/constant/NameAndTypeInfo.java b/group01/1814014897/zhouhui/src/week05/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..aaa5022dc3 --- /dev/null +++ b/group01/1814014897/zhouhui/src/week05/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,45 @@ +package week05.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/group01/1814014897/zhouhui/src/week05/jvm/constant/NullConstantInfo.java b/group01/1814014897/zhouhui/src/week05/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..d2ec4edcee --- /dev/null +++ b/group01/1814014897/zhouhui/src/week05/jvm/constant/NullConstantInfo.java @@ -0,0 +1,13 @@ +package week05.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo(){ + + } + @Override + public int getType() { + return -1; + } + +} diff --git a/group01/1814014897/zhouhui/src/week05/jvm/constant/StringInfo.java b/group01/1814014897/zhouhui/src/week05/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..602a2948b1 --- /dev/null +++ b/group01/1814014897/zhouhui/src/week05/jvm/constant/StringInfo.java @@ -0,0 +1,26 @@ +package week05.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/group01/1814014897/zhouhui/src/week05/jvm/constant/UTF8Info.java b/group01/1814014897/zhouhui/src/week05/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..d3fc7f9303 --- /dev/null +++ b/group01/1814014897/zhouhui/src/week05/jvm/constant/UTF8Info.java @@ -0,0 +1,32 @@ +package week05.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/group01/1814014897/zhouhui/src/week05/jvm/loader/ByteCodeIterator.java b/group01/1814014897/zhouhui/src/week05/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..76a6adeb8b --- /dev/null +++ b/group01/1814014897/zhouhui/src/week05/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,37 @@ +package week05.jvm.loader; + +import java.util.Arrays; + +import week05.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 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/group01/1814014897/zhouhui/src/week05/jvm/loader/ClassFileLoader.java b/group01/1814014897/zhouhui/src/week05/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..f4561d2603 --- /dev/null +++ b/group01/1814014897/zhouhui/src/week05/jvm/loader/ClassFileLoader.java @@ -0,0 +1,134 @@ +package week05.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 week05.jvm.clz.ClassFile; + + +public class ClassFileLoader { + + private List<String> clzPaths = new ArrayList<String>(); + + 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/group01/1814014897/zhouhui/src/week05/jvm/loader/ClassFileParser.java b/group01/1814014897/zhouhui/src/week05/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..9e27a1ad41 --- /dev/null +++ b/group01/1814014897/zhouhui/src/week05/jvm/loader/ClassFileParser.java @@ -0,0 +1,132 @@ +package week05.jvm.loader; + +import java.io.UnsupportedEncodingException; + +import week05.jvm.clz.AccessFlag; +import week05.jvm.clz.ClassFile; +import week05.jvm.clz.ClassIndex; +import week05.jvm.constant.ClassInfo; +import week05.jvm.constant.ConstantPool; +import week05.jvm.constant.FieldRefInfo; +import week05.jvm.constant.MethodRefInfo; +import week05.jvm.constant.NameAndTypeInfo; +import week05.jvm.constant.NullConstantInfo; +import week05.jvm.constant.StringInfo; +import week05.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); + + AccessFlag flag = parseAccessFlag(iter); + clzFile.setAccessFlag(flag); + + ClassIndex clzIndex = parseClassInfex(iter); + clzFile.setClassIndex(clzIndex); + + return clzFile; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + int flagValue = iter.nextU2ToInt(); + AccessFlag accessFlag = new AccessFlag(flagValue); + return accessFlag; + } + + private ClassIndex parseClassInfex(ByteCodeIterator iter) { + ClassIndex classIndex = new ClassIndex(); + int thisClassIndex = iter.nextU2ToInt(); + int thisSuperIndex = iter.nextU2ToInt(); + + classIndex.setThisClassIndex(thisClassIndex); + classIndex.setSuperClassIndex(thisSuperIndex); + + return classIndex; + + } + + private ConstantPool parseConstantPool(ByteCodeIterator iter) { + int constPoolCount = iter.nextU2ToInt(); + + System.out.println("Constant Pool Counts:" + constPoolCount); + + ConstantPool pool = new ConstantPool(); + + 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); + + pool.addConstantInfo(clzInfo); + } else if (tag == 1) { + // UTF-8 String + int len = iter.nextU2ToInt(); + byte[] data = iter.getBytes(len); + String value = null; + try { + value = new String(data, "UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + UTF8Info utf8Str = new UTF8Info(pool); + utf8Str.setLength(len); + utf8Str.setValue(value); + pool.addConstantInfo(utf8Str); + } else if (tag == 8) { + //String + StringInfo info = new StringInfo(pool); + info.setIndex(iter.nextU2ToInt()); + pool.addConstantInfo(info); + } else if (tag == 9) { + //FieldRef + FieldRefInfo field = new FieldRefInfo(pool); + field.setClassInfoIndex(iter.nextU2ToInt()); + field.setNameAndTypeIndex(iter.nextU2ToInt()); + pool.addConstantInfo(field); + } else if (tag == 10) { + // MethodRef + MethodRefInfo method = new MethodRefInfo(pool); + method.setClassInfoIndex(iter.nextU2ToInt()); + method.setNameAndTypeIndex(iter.nextU2ToInt()); + pool.addConstantInfo(method); + } else if (tag == 12) { + // Name and Type Info + NameAndTypeInfo nameType = new NameAndTypeInfo(pool); + nameType.setIndex1(iter.nextU2ToInt()); + nameType.setIndex2(iter.nextU2ToInt()); + pool.addConstantInfo(nameType); + } else { + throw new RuntimeException("the constant pool tag " + tag + "has not been implemented yet."); + } + + } + + return pool; + + } + +} diff --git a/group01/1814014897/zhouhui/src/week05/jvm/test/ClassFileloaderTest.java b/group01/1814014897/zhouhui/src/week05/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..1fb3f412b9 --- /dev/null +++ b/group01/1814014897/zhouhui/src/week05/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,199 @@ +package week05.jvm.test; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import week05.jvm.clz.ClassFile; +import week05.jvm.clz.ClassIndex; +import week05.jvm.constant.ClassInfo; +import week05.jvm.constant.ConstantPool; +import week05.jvm.constant.MethodRefInfo; +import week05.jvm.constant.NameAndTypeInfo; +import week05.jvm.constant.UTF8Info; +import week05.jvm.loader.ClassFileLoader; + + +public class ClassFileloaderTest { + + + private static final String FULL_QUALIFIED_CLASS_NAME = "week05/jvm/test/EmployeeV1"; + + static String path1 = (""+ClassLoader.getSystemResource("")).replaceAll("file:/" , ""); + static String path2 = "C:\temp"; + + static ClassFile clzFile = null; + static { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "week05.jvm.test.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 = "week05.jvm.test.EmployeeV1"; + + byte[] byteCodes = loader.readBinaryCode(className); + + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + Assert.assertEquals(1040, byteCodes.length); + + } + + + @Test + public void testMagicNumber(){ + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "week05.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(); + } + + /** + * ---------------------------------------------------------------------- + */ + + + @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("<init>", 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/1814014897/zhouhui/src/week05/jvm/test/EmployeeV1.java b/group01/1814014897/zhouhui/src/week05/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..e86ea0ce81 --- /dev/null +++ b/group01/1814014897/zhouhui/src/week05/jvm/test/EmployeeV1.java @@ -0,0 +1,28 @@ +package week05.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/group01/1814014897/zhouhui/src/week05/jvm/util/Util.java b/group01/1814014897/zhouhui/src/week05/jvm/util/Util.java new file mode 100644 index 0000000000..830e6bc26d --- /dev/null +++ b/group01/1814014897/zhouhui/src/week05/jvm/util/Util.java @@ -0,0 +1,24 @@ +package week05.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/group01/1814014897/zhouhui/src/week05/stack/Stack.java b/group01/1814014897/zhouhui/src/week05/stack/Stack.java new file mode 100644 index 0000000000..f69adae35e --- /dev/null +++ b/group01/1814014897/zhouhui/src/week05/stack/Stack.java @@ -0,0 +1,27 @@ +package week05.stack; + +import week01.datastructure.ArrayList; + +public class Stack { + private ArrayList elementData = new ArrayList(); + private int size = 0; + + public void push(Object o){ + elementData.add(o); + size++; + } + + public Object pop(){ + return elementData.remove(--size); + } + + public Object peek(){ + return elementData.get(size - 1); + } + public boolean isEmpty(){ + return elementData.size() == 0; + } + public int size(){ + return elementData.size(); + } +} diff --git a/group01/1814014897/zhouhui/src/week05/stack/StackUtil.java b/group01/1814014897/zhouhui/src/week05/stack/StackUtil.java new file mode 100644 index 0000000000..0ed0edc51b --- /dev/null +++ b/group01/1814014897/zhouhui/src/week05/stack/StackUtil.java @@ -0,0 +1,114 @@ +package week05.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; + + Stack sRev = new Stack(); + int nums = s.size(); + for (int i = 0; i < nums; i++) { + sRev.push(s.pop()); + } + + Stack sRevTrans = new Stack(); + for (int i = 0; i < nums; i++) { + sRevTrans.push(sRev.pop()); + } + + for (int i = 0; i < nums; i++) { + s.push(sRevTrans.pop()); + } + } + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s, Object o) { + if (s.isEmpty()) return; + + Stack sRem = new Stack(); + int nums = s.size(); + for (int i = 0; i < nums; i++) { + if (!s.peek().equals(o)) { + sRem.push(s.pop()); + } else { + s.pop(); + } + } + + int numsOfsRem = sRem.size(); + + if (numsOfsRem == nums) return; + + for (int i = 0; i < numsOfsRem; i++) { + s.push(sRem.pop()); + } + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, + * 可以使用另外一个栈来辅助 + * + * @param len + * @return + */ + public static Object[] getTop(Stack s, int len) { + if(len > s.size() || len <= 0) return null; + + Object[] result = new Object[len]; + for(int i=0;i<len;i++){ + result[i] = s.pop(); + } + + for(int i=len-1;i>=0;i--){ + 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) { + char[] arr = s.toCharArray(); + + Stack s1 = new Stack(); + Stack s2 = new Stack(); + + for(int i=arr.length-1;i>=0;i--){ + s1.push(arr[i]); + } + + for(int i=0;i<arr.length;i++){ + s2.push(arr[i]); + } + + int nums = arr.length; + for(int i=0;i<nums/2;i++){ + Object left = s1.pop(); + Object right = s2.pop(); + + if( (left.equals('(') && !right.equals(')')) + || (left.equals('[') && !right.equals(']')) + || (left.equals('{') && !right.equals('}')) ){ + return false; + } + } + + return true; + } + +} diff --git a/group01/1814014897/zhouhui/src/week05/stack/StackUtilTest.java b/group01/1814014897/zhouhui/src/week05/stack/StackUtilTest.java new file mode 100644 index 0000000000..4f5e710a87 --- /dev/null +++ b/group01/1814014897/zhouhui/src/week05/stack/StackUtilTest.java @@ -0,0 +1,62 @@ +package week05.stack; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class StackUtilTest { + + Stack s = new Stack(); + + @Before + public void setUp() throws Exception { + for(int i=1;i<=5;i++){ + s.push(i); + } + } + + @Test + public void testReverse() { + StackUtil.reverse(s); + + for(int i=1;i<=5;i++){ + Assert.assertEquals(i,s.pop()); + } + } + + @Test + public void testRemove() { + StackUtil.remove(s, 3); + + Assert.assertEquals(4,s.size()); + + Assert.assertEquals(5,s.pop()); + Assert.assertEquals(4,s.pop()); + Assert.assertEquals(2,s.pop()); + Assert.assertEquals(1,s.pop()); + + Assert.assertEquals(0,s.size()); + } + + @Test + public void testGetTop() { + Object[] result = StackUtil.getTop(s, 3); + + Assert.assertArrayEquals(new Object[]{5,4,3},result); + + for(int i=5;i>=1;i--){ + Assert.assertEquals(i, s.pop()); + } + } + + @Test + public void testIsValidPairs() { + String s1 = "([e{d}f])"; + String s2 = "([b{x]y})"; + + Assert.assertTrue(StackUtil.isValidPairs(s1)); + Assert.assertFalse(StackUtil.isValidPairs(s2)); + } + +} From f8e5fb284f90436a1553a7ddebba3f58956f3ee6 Mon Sep 17 00:00:00 2001 From: x_zhaohu <x_zhaohu@163.com> Date: Tue, 11 Apr 2017 21:41:00 +0800 Subject: [PATCH 226/287] =?UTF-8?q?=E7=AC=AC=E4=BA=94=E6=AC=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group11/1178243325/week07/.readme.md.swp | Bin 0 -> 12288 bytes group11/1178243325/week07/build.gradle | 13 ++ group11/1178243325/week07/readme.md | 12 ++ .../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/FieldRefInfo.java | 52 +++++ .../sprint/jvm/constant/MethodRefInfo.java | 55 ++++++ .../sprint/jvm/constant/NameAndTypeInfo.java | 52 +++++ .../sprint/jvm/constant/NullConstantInfo.java | 12 ++ .../com/sprint/jvm/constant/StringInfo.java | 26 +++ .../com/sprint/jvm/constant/UTF8Info.java | 35 ++++ .../sprint/jvm/loader/ByteCodeIterator.java | 50 +++++ .../sprint/jvm/loader/ClassFileLoader.java | 52 +++++ .../sprint/jvm/loader/ClassFileParser.java | 107 +++++++++++ .../main/java/com/sprint/jvm/util/Util.java | 22 +++ .../jvm/loader/ClassFileLoaderTest.java | 181 ++++++++++++++++++ .../com/sprint/jvm/loader/EmployeeV1.java | 28 +++ 21 files changed, 900 insertions(+) create mode 100644 group11/1178243325/week07/.readme.md.swp create mode 100644 group11/1178243325/week07/build.gradle create mode 100644 group11/1178243325/week07/readme.md create mode 100644 group11/1178243325/week07/src/main/java/com/sprint/jvm/clz/AccessFlag.java create mode 100644 group11/1178243325/week07/src/main/java/com/sprint/jvm/clz/ClassFile.java create mode 100644 group11/1178243325/week07/src/main/java/com/sprint/jvm/clz/ClassIndex.java create mode 100644 group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/ClassInfo.java create mode 100644 group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/ConstantInfo.java create mode 100644 group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/ConstantPool.java create mode 100644 group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/FieldRefInfo.java create mode 100644 group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/MethodRefInfo.java create mode 100644 group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/NameAndTypeInfo.java create mode 100644 group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/NullConstantInfo.java create mode 100644 group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/StringInfo.java create mode 100644 group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/UTF8Info.java create mode 100644 group11/1178243325/week07/src/main/java/com/sprint/jvm/loader/ByteCodeIterator.java create mode 100644 group11/1178243325/week07/src/main/java/com/sprint/jvm/loader/ClassFileLoader.java create mode 100644 group11/1178243325/week07/src/main/java/com/sprint/jvm/loader/ClassFileParser.java create mode 100644 group11/1178243325/week07/src/main/java/com/sprint/jvm/util/Util.java create mode 100644 group11/1178243325/week07/src/test/java/com/sprint/jvm/loader/ClassFileLoaderTest.java create mode 100644 group11/1178243325/week07/src/test/java/com/sprint/jvm/loader/EmployeeV1.java diff --git a/group11/1178243325/week07/.readme.md.swp b/group11/1178243325/week07/.readme.md.swp new file mode 100644 index 0000000000000000000000000000000000000000..3d7e4464a84ed43e0b59dc8f2f80c33ee769a7a0 GIT binary patch literal 12288 zcmeI&J#W)M7zgkx8;Cd2nPTbzI>cu?iQMoFTG0tLLP89OZQ3+VVkJ(q@uI#Y5~!sT z>JTB+2_dKwUPN)!mQMg98>7!L5~yE+#}F8hS}_9ppY->|cjwb{zs+)P==q5$#nLj2 z+G)l<e)@9tZgGSS=NYSc)k4`%CJt|Zy6)DGg?vsd2yRy#H@OtbGp24>e5P8ddxpUc z!x}d;>9m>U4c9H|7O%R(DY;t7IlKzYLI45>3e^3ZsqqsmZ5n#AMjbt`44;`ka5*L* z009U<00Izz00bZaf&Wjy_lDSQI@XcF(T)%Lq2Kz!EjkE500Izz00bZa0SG_<0uX=z z1pYw*L0{GPPBM1%6ctb3|9`&!f2I2ml=qY;lm&`IF)8OLBb2k0W0d6C3lua6KmY;| zfB*y_009U<00Izzz~3yOs!XMS#HvcvTJN`)qKDh@>f8O@Hq}gnvU5LbJ%|>U<;t66 zFr{3JHk$qCo7XSS`o4FG^G2hg%@stsHe1*1N{M?stDCmrW^EyI))+k@JCFOTFRu8) zE>8P}`ClWl+Y5s`Vem||=S8hX`-VH)RDukG&&{>y<!0R7k!u@C8U3xTFj$o9Ps6=O zVbI>+ZRwemo>t=KYbE)W8)LMsVbNI1%qdjqWPU2_-TS`r<%)3JYO+n-c@=lx$(3c< I=_RN624bkC)c^nh literal 0 HcmV?d00001 diff --git a/group11/1178243325/week07/build.gradle b/group11/1178243325/week07/build.gradle new file mode 100644 index 0000000000..128f6fda07 --- /dev/null +++ b/group11/1178243325/week07/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/week07/readme.md b/group11/1178243325/week07/readme.md new file mode 100644 index 0000000000..cc9d7c6f3c --- /dev/null +++ b/group11/1178243325/week07/readme.md @@ -0,0 +1,12 @@ +## 讲课内容: +- 17-03-29 :JVM之classLoader + +## 第七周作业(04-03 至 04-09) +- 实现对一个.class文件的常量池读取 +- 实现StackUtil +- [文章](http://www.jianshu.com/p/502c1e5caa97) +## 完成情况: + + +## 我的收获: + diff --git a/group11/1178243325/week07/src/main/java/com/sprint/jvm/clz/AccessFlag.java b/group11/1178243325/week07/src/main/java/com/sprint/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..e74740aa3e --- /dev/null +++ b/group11/1178243325/week07/src/main/java/com/sprint/jvm/clz/AccessFlag.java @@ -0,0 +1,25 @@ +package com.sprint.jvm.clz; + +public class AccessFlag { + private int flagValue; + + public AccessFlag(int value) { + this.flagValue = value; + } + + public int getFlagValue() { + return flagValue; + } + + public void setFlagValue(int flagValue) { + this.flagValue = flagValue; + } + + public boolean isPublicClass() { + return (this.flagValue & 0x0001) != 0; + } + + public boolean isFinalClass() { + return (this.flagValue & 0x0010) != 0; + } +} diff --git a/group11/1178243325/week07/src/main/java/com/sprint/jvm/clz/ClassFile.java b/group11/1178243325/week07/src/main/java/com/sprint/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..4e5aad16f9 --- /dev/null +++ b/group11/1178243325/week07/src/main/java/com/sprint/jvm/clz/ClassFile.java @@ -0,0 +1,71 @@ +package com.sprint.jvm.clz; + +import com.sprint.jvm.constant.ConstantPool; +import com.sprint.jvm.constant.ClassInfo; +public class ClassFile { + private int minorVersion; + private int majorVersion; + + private AccessFlag accessFlag; + private ClassIndex clzIndex; + private ConstantPool 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 AccessFlag getAccessFlag() { + return accessFlag; + } + + public void setAccessFlag(AccessFlag accessFlag) { + this.accessFlag = accessFlag; + } + + public ClassIndex getClassIndex() { + return clzIndex; + } + + public void setClassIndex(ClassIndex clzIndex) { + this.clzIndex = clzIndex; + } + + public ConstantPool getConstantPool() { + return 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("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/group11/1178243325/week07/src/main/java/com/sprint/jvm/clz/ClassIndex.java b/group11/1178243325/week07/src/main/java/com/sprint/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..46e7443d90 --- /dev/null +++ b/group11/1178243325/week07/src/main/java/com/sprint/jvm/clz/ClassIndex.java @@ -0,0 +1,22 @@ +package com.sprint.jvm.clz; + +public class ClassIndex { + private int thisClassIndex; + private int superClassIndex; + + public int getThisClassIndex() { + return thisClassIndex; + } + + public void setThisClassIndex(int index) { + this.thisClassIndex = index; + } + + public int getSuperClassIndex() { + return superClassIndex; + } + + public void setSuperClassIndex(int index) { + this.superClassIndex = index; + } +} diff --git a/group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/ClassInfo.java b/group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..b8da3c656d --- /dev/null +++ b/group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/ClassInfo.java @@ -0,0 +1,28 @@ +package com.sprint.jvm.constant; + +public class ClassInfo extends ConstantInfo { + private int type = ConstantInfo.CLASS_INFO; + private int utf8Index; + + public ClassInfo(ConstantPool pool) { + super(pool); + } + + public void setUtf8Index(int index) { + this.utf8Index = index; + } + + public int getUtf8Index() { + return utf8Index; + } + + public int getType() { + return type; + } + + public String getClassName() { + int index = getUtf8Index(); + UTF8Info utf8Info = (UTF8Info)constantPool.getConstantInfo(index); + return utf8Info.getValue(); + } +} diff --git a/group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/ConstantInfo.java b/group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..a8db82689e --- /dev/null +++ b/group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/ConstantInfo.java @@ -0,0 +1,29 @@ +package com.sprint.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/group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/ConstantPool.java b/group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..3a35c22ce0 --- /dev/null +++ b/group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/ConstantPool.java @@ -0,0 +1,28 @@ +package com.sprint.jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + private List<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + 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/week07/src/main/java/com/sprint/jvm/constant/FieldRefInfo.java b/group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..c0eb449085 --- /dev/null +++ b/group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/FieldRefInfo.java @@ -0,0 +1,52 @@ +package com.sprint.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/group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/MethodRefInfo.java b/group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..85bb5c4934 --- /dev/null +++ b/group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/MethodRefInfo.java @@ -0,0 +1,55 @@ +package com.sprint.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/group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/NameAndTypeInfo.java b/group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..492fd6e0db --- /dev/null +++ b/group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,52 @@ +package com.sprint.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 getType() { + return type; + } + + 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 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/group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/NullConstantInfo.java b/group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..f257cea240 --- /dev/null +++ b/group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/NullConstantInfo.java @@ -0,0 +1,12 @@ +package com.sprint.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + public NullConstantInfo() { + + } + + @Override + public int getType() { + return -1; + } +} diff --git a/group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/StringInfo.java b/group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..73c58a5e71 --- /dev/null +++ b/group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/StringInfo.java @@ -0,0 +1,26 @@ +package com.sprint.jvm.constant; + +public class StringInfo extends ConstantInfo { + private int type = ConstantInfo.STRING_INFO; + private int index; + + public StringInfo(ConstantPool constantPool) { + super(constantPool); + } + + 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/1178243325/week07/src/main/java/com/sprint/jvm/constant/UTF8Info.java b/group11/1178243325/week07/src/main/java/com/sprint/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..5516999c0e --- /dev/null +++ b/group11/1178243325/week07/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/week07/src/main/java/com/sprint/jvm/loader/ByteCodeIterator.java b/group11/1178243325/week07/src/main/java/com/sprint/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..fc5d1b2ac2 --- /dev/null +++ b/group11/1178243325/week07/src/main/java/com/sprint/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,50 @@ +package com.sprint.jvm.loader; + +import com.sprint.jvm.util.Util; +import java.util.Arrays; +public class ByteCodeIterator { + byte[] codes; + int pos = 0; + ByteCodeIterator(byte[] codes) { + this.codes = codes; + } + + 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; + } + + 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 nextUxToHexString(int len) { + byte[] tmp = new byte[len]; + for (int i = 0; i < len; i++) { + tmp[i] = codes[pos++]; + } + return Util.byteToHexString(tmp).toLowerCase(); + } + + public void back(int n) { + this.pos -= n; + } + + +} diff --git a/group11/1178243325/week07/src/main/java/com/sprint/jvm/loader/ClassFileLoader.java b/group11/1178243325/week07/src/main/java/com/sprint/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..f190f54915 --- /dev/null +++ b/group11/1178243325/week07/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<String> clzPaths = new ArrayList<String>(); + 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/week07/src/main/java/com/sprint/jvm/loader/ClassFileParser.java b/group11/1178243325/week07/src/main/java/com/sprint/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..4b77190a04 --- /dev/null +++ b/group11/1178243325/week07/src/main/java/com/sprint/jvm/loader/ClassFileParser.java @@ -0,0 +1,107 @@ +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.ClassInfo; +import com.sprint.jvm.constant.ConstantPool; +import com.sprint.jvm.constant.FieldRefInfo; +import com.sprint.jvm.constant.NameAndTypeInfo; +import com.sprint.jvm.constant.NullConstantInfo; +import com.sprint.jvm.constant.MethodRefInfo; +import com.sprint.jvm.constant.StringInfo; +import com.sprint.jvm.constant.UTF8Info; +import java.io.UnsupportedEncodingException; +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()); + System.out.println("minor:" + clzFile.getMinorVersion()); + clzFile.setMajorVersion(iter.nextU2ToInt()); + System.out.println("marjor:" + clzFile.getMajorVersion()); + ConstantPool pool = parseConstantPool(iter); + clzFile.setConstantPool(pool); + + AccessFlag flag = parseAccessFlag(iter); + clzFile.setAccessFlag(flag); + + ClassIndex clzIndex = parseClassIndex(iter); + clzFile.setClassIndex(clzIndex); + return clzFile; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + AccessFlag flag = new AccessFlag(iter.nextU2ToInt()); + return flag; + } + + private ClassIndex parseClassIndex(ByteCodeIterator iter) { + int thisClassIndex = iter.nextU2ToInt(); + int superClassIndex = iter.nextU2ToInt(); + + ClassIndex clzIndex = new ClassIndex(); + clzIndex.setThisClassIndex(thisClassIndex); + clzIndex.setSuperClassIndex(superClassIndex); + return clzIndex; + } + + private ConstantPool parseConstantPool(ByteCodeIterator iter) { + int constPoolCount = iter.nextU2ToInt(); + System.out.println("Constant Pool Count :" + constPoolCount); + ConstantPool pool = new ConstantPool(); + pool.addConstantInfo(new NullConstantInfo()); + for (int i = 1; i <= constPoolCount - 1; i++) { + int tag = iter.nextU1ToInt(); + if (tag == 7) { + int utf8Index = iter.nextU2ToInt(); + ClassInfo clzInfo = new ClassInfo(pool); + clzInfo.setUtf8Index(utf8Index); + 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) { + 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 RuntimeException("the constant pool tag:" + tag + "has no been implemented yet."); + } + } + System.out.println("Finished reading Constant Pool"); + return pool; + } + + +} diff --git a/group11/1178243325/week07/src/main/java/com/sprint/jvm/util/Util.java b/group11/1178243325/week07/src/main/java/com/sprint/jvm/util/Util.java new file mode 100644 index 0000000000..0f5dc89626 --- /dev/null +++ b/group11/1178243325/week07/src/main/java/com/sprint/jvm/util/Util.java @@ -0,0 +1,22 @@ +package com.sprint.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/group11/1178243325/week07/src/test/java/com/sprint/jvm/loader/ClassFileLoaderTest.java b/group11/1178243325/week07/src/test/java/com/sprint/jvm/loader/ClassFileLoaderTest.java new file mode 100644 index 0000000000..5cbc24577e --- /dev/null +++ b/group11/1178243325/week07/src/test/java/com/sprint/jvm/loader/ClassFileLoaderTest.java @@ -0,0 +1,181 @@ +package com.sprint.jvm.loader; + + +import com.sprint.jvm.clz.ClassFile; +import com.sprint.jvm.clz.ClassIndex; +import com.sprint.jvm.constant.*; +import org.junit.Test; +import org.junit.Assert; +public class ClassFileLoaderTest { + + private static final String FULL_QUALIFIED_CLASS_NAME = "com/sprint/jvm/loader/EmployeeV1"; + static String path1 = "/home/sprint/java/code/coding2017/group11/1178243325/week07/build/classes/test"; + static String path2 = "/home/sprint/xxx"; + static ClassFile clzFile = null; + static { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "com.sprint.jvm.loader.EmployeeV1"; + clzFile = loader.loadClass(className); + clzFile.print(); + } + + + @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.sprint.jvm.loader.EmployeeV1"; + + byte[] byteCodes = loader.readBinaryCode(className); + + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + Assert.assertEquals(1050, byteCodes.length); + + } + + + @Test + public void testMagicNumber(){ + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "com.sprint.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<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()); + + for (int i = 0; i < 54; i++) { + System.out.println(pool.getConstantInfo(i)); + } + + { + 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("<init>", 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.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/group11/1178243325/week07/src/test/java/com/sprint/jvm/loader/EmployeeV1.java b/group11/1178243325/week07/src/test/java/com/sprint/jvm/loader/EmployeeV1.java new file mode 100644 index 0000000000..6b8532842b --- /dev/null +++ b/group11/1178243325/week07/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 f62dd151fcd2d8acc346944da62822732807a877 Mon Sep 17 00:00:00 2001 From: Pan <gqp201210@gmail.com> Date: Tue, 11 Apr 2017 22:37:29 +0800 Subject: [PATCH 227/287] jvm --- .../java/com/pan/jvm/attr/AttributeInfo.java | 19 ++ .../main/java/com/pan/jvm/attr/CodeAttr.java | 56 ++++ .../com/pan/jvm/attr/LineNumberTable.java | 42 +++ .../com/pan/jvm/attr/LocalVariableItem.java | 39 +++ .../com/pan/jvm/attr/LocalVariableTable.java | 28 ++ .../java/com/pan/jvm/attr/StackMapTable.java | 30 ++ .../main/java/com/pan/jvm/clz/AccessFlag.java | 37 ++- .../main/java/com/pan/jvm/clz/ClassFile.java | 158 ++++++----- .../main/java/com/pan/jvm/clz/ClassIndex.java | 33 +-- .../main/java/com/pan/jvm/field/Field.java | 32 +++ .../com/pan/jvm/loader/ByteCodeIterator.java | 54 +++- .../main/java/com/pan/jvm/method/Method.java | 53 ++++ .../java/com/pan/jvm/ClassFileloaderTest.java | 260 ++++++++++++++++++ 13 files changed, 729 insertions(+), 112 deletions(-) create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/AttributeInfo.java create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/CodeAttr.java create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/LineNumberTable.java create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/LocalVariableItem.java create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/LocalVariableTable.java create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/StackMapTable.java create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/jvm/field/Field.java create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/jvm/method/Method.java create mode 100644 group11/252308879/mini-jvm/src/test/java/com/pan/jvm/ClassFileloaderTest.java diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/AttributeInfo.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/AttributeInfo.java new file mode 100644 index 0000000000..1a81e8b473 --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/AttributeInfo.java @@ -0,0 +1,19 @@ +package com.pan.jvm.attr; + +public abstract class AttributeInfo { + public static final String CODE = "Code"; + public static final String CONST_VALUE = "ConstantValue"; + public static final String EXCEPTIONS = "Exceptions"; + public static final String LINE_NUM_TABLE = "LineNumberTable"; + public static final String LOCAL_VAR_TABLE = "LocalVariableTable"; + public static final String STACK_MAP_TABLE = "StackMapTable"; + int attrNameIndex; + int attrLen ; + public AttributeInfo(int attrNameIndex, int attrLen) { + + this.attrNameIndex = attrNameIndex; + this.attrLen = attrLen; + } + + +} diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/CodeAttr.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/CodeAttr.java new file mode 100644 index 0000000000..08bfa18f85 --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/CodeAttr.java @@ -0,0 +1,56 @@ +package com.pan.jvm.attr; + +import com.pan.jvm.clz.ClassFile; +import com.pan.jvm.constant.ConstantPool; +import com.pan.jvm.loader.ByteCodeIterator; + + +public class CodeAttr extends AttributeInfo { + private int maxStack ; + private int maxLocals ; + private int codeLen ; + private String code; + public String getCode() { + return code; + } + + //private ByteCodeCommand[] cmds ; + //public ByteCodeCommand[] getCmds() { + // return cmds; + //} + private LineNumberTable lineNumTable; + private LocalVariableTable localVarTable; + private StackMapTable stackMapTable; + + public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen,String code /*ByteCodeCommand[] cmds*/) { + super(attrNameIndex, attrLen); + this.maxStack = maxStack; + this.maxLocals = maxLocals; + this.codeLen = codeLen; + this.code = code; + //this.cmds = cmds; + } + + public void setLineNumberTable(LineNumberTable t) { + this.lineNumTable = t; + } + + public void setLocalVariableTable(LocalVariableTable t) { + this.localVarTable = t; + } + + public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ + + + return null; + } + private void setStackMapTable(StackMapTable t) { + this.stackMapTable = t; + + } + + + + + +} diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/LineNumberTable.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/LineNumberTable.java new file mode 100644 index 0000000000..31d2ab3d7e --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/LineNumberTable.java @@ -0,0 +1,42 @@ +package com.pan.jvm.attr; + +import java.util.ArrayList; +import java.util.List; + +import com.pan.jvm.loader.ByteCodeIterator; + +public class LineNumberTable extends AttributeInfo { + List<LineNumberItem> items = new ArrayList<LineNumberItem>(); + + private static class LineNumberItem{ + int startPC; + int lineNum; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLineNum() { + return lineNum; + } + public void setLineNum(int lineNum) { + this.lineNum = lineNum; + } + } + public void addLineNumberItem(LineNumberItem item){ + this.items.add(item); + } + public LineNumberTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + + } + + public static LineNumberTable parse(ByteCodeIterator iter){ + + return null; + } + + + +} diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/LocalVariableItem.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/LocalVariableItem.java new file mode 100644 index 0000000000..7e202a3931 --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/LocalVariableItem.java @@ -0,0 +1,39 @@ +package com.pan.jvm.attr; + +public class LocalVariableItem { + private int startPC; + private int length; + private int nameIndex; + private int descIndex; + private int index; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getNameIndex() { + return nameIndex; + } + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + public int getDescIndex() { + return descIndex; + } + public void setDescIndex(int descIndex) { + this.descIndex = descIndex; + } + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } +} diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/LocalVariableTable.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/LocalVariableTable.java new file mode 100644 index 0000000000..745f1e77d2 --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/LocalVariableTable.java @@ -0,0 +1,28 @@ +package com.pan.jvm.attr; + + +import java.util.ArrayList; +import java.util.List; + +import com.pan.jvm.constant.ConstantPool; + +import com.pan.jvm.loader.ByteCodeIterator; + +public class LocalVariableTable extends AttributeInfo{ + + List<LocalVariableItem> items = new ArrayList<LocalVariableItem>(); + + public LocalVariableTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static LocalVariableTable parse(ByteCodeIterator iter){ + + return null; + } + private void addLocalVariableItem(LocalVariableItem item) { + this.items.add(item); + } + + +} diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/StackMapTable.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/StackMapTable.java new file mode 100644 index 0000000000..8d7c32b4bd --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/StackMapTable.java @@ -0,0 +1,30 @@ +package com.pan.jvm.attr; + + +import com.pan.jvm.loader.ByteCodeIterator; + +public class StackMapTable extends AttributeInfo{ + + private String originalCode; + + public StackMapTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static StackMapTable parse(ByteCodeIterator iter){ + int index = iter.nextU2ToInt(); + int len = iter.nextU4ToInt(); + StackMapTable t = new StackMapTable(index,len); + + //后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 + String code = iter.nextUxToHexString(len); + t.setOriginalCode(code); + + return t; + } + + private void setOriginalCode(String code) { + this.originalCode = code; + + } +} diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/AccessFlag.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/AccessFlag.java index 8c253df200..045741bd1e 100644 --- a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/AccessFlag.java +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/AccessFlag.java @@ -1,26 +1,25 @@ package com.pan.jvm.clz; public class AccessFlag { - private int flagValue; + private int flagValue; - public AccessFlag(int value) { - this.flagValue = value; - } + 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; - } + 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/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/ClassFile.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/ClassFile.java index a192ad0c82..2b3a185ac6 100644 --- a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/ClassFile.java +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/ClassFile.java @@ -1,82 +1,92 @@ package com.pan.jvm.clz; +import java.util.ArrayList; +import java.util.List; import com.pan.jvm.constant.ClassInfo; import com.pan.jvm.constant.ConstantPool; +import com.pan.jvm.field.Field; +import com.pan.jvm.method.Method; 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(); - } + + private int minorVersion; + private int majorVersion; + + private AccessFlag accessFlag; + private ClassIndex clzIndex; + private ConstantPool pool; + private List<Field> fields = new ArrayList<Field>(); + private List<Method> methods = new ArrayList<Method>(); + + 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 addField(Field f){ + this.fields.add(f); + } + public List<Field> getFields(){ + return this.fields; + } + public void addMethod(Method m){ + this.methods.add(m); + } + public List<Method> getMethods() { + return methods; + } + + + 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/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/ClassIndex.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/ClassIndex.java index 563592ac47..e09d6f0076 100644 --- a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/ClassIndex.java +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/ClassIndex.java @@ -1,22 +1,19 @@ package com.pan.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; - } + 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/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/field/Field.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/field/Field.java new file mode 100644 index 0000000000..3fc8da4cdf --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/field/Field.java @@ -0,0 +1,32 @@ +package com.pan.jvm.field; + + +import com.pan.jvm.constant.ConstantPool; +import com.pan.jvm.loader.ByteCodeIterator; + +public class Field { + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + + + private ConstantPool pool; + + public Field( int accessFlag, int nameIndex, int descriptorIndex,ConstantPool pool) { + + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + this.pool = pool; + } + + + + + public static Field parse(ConstantPool pool,ByteCodeIterator iter){ + + return null; + } + +} diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ByteCodeIterator.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ByteCodeIterator.java index f808720ef9..c0f9a6eaa5 100644 --- a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ByteCodeIterator.java +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ByteCodeIterator.java @@ -1,5 +1,57 @@ package com.pan.jvm.loader; -public class ByteCodeIterator { +import java.util.Arrays; +import com.pan.jvm.util.Util; + +public class ByteCodeIterator { + byte[] codes; + int pos = 0; + + ByteCodeIterator(byte[] codes) { + this.codes = codes; + } + + + + 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; + } + + 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 nextUxToHexString(int len) { + byte[] tmp = new byte[len]; + + for (int i = 0; i < len; i++) { + tmp[i] = codes[pos++]; + } + return Util.byteToHexString(tmp).toLowerCase(); + + } + + public void back(int n) { + this.pos -= n; + } } diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/method/Method.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/method/Method.java new file mode 100644 index 0000000000..ec3561a566 --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/method/Method.java @@ -0,0 +1,53 @@ +package com.pan.jvm.method; + + +import com.pan.jvm.attr.CodeAttr; +import com.pan.jvm.clz.ClassFile; +import com.pan.jvm.loader.ByteCodeIterator; + +public class Method { + + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private CodeAttr codeAttr; + + private ClassFile clzFile; + + + public ClassFile getClzFile() { + return clzFile; + } + + public int getNameIndex() { + return nameIndex; + } + public int getDescriptorIndex() { + return descriptorIndex; + } + + public CodeAttr getCodeAttr() { + return codeAttr; + } + + public void setCodeAttr(CodeAttr code) { + this.codeAttr = code; + } + + public Method(ClassFile clzFile,int accessFlag, int nameIndex, int descriptorIndex) { + this.clzFile = clzFile; + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + } + + + + + + public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ + return null; + + } +} diff --git a/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/ClassFileloaderTest.java b/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/ClassFileloaderTest.java new file mode 100644 index 0000000000..4bcb38e917 --- /dev/null +++ b/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/ClassFileloaderTest.java @@ -0,0 +1,260 @@ +package com.pan.jvm; + +import java.util.List; + +import com.pan.jvm.clz.ClassFile; +import com.pan.jvm.clz.ClassIndex; +import com.pan.jvm.constant.*; +import com.pan.jvm.field.Field; +import com.pan.jvm.loader.ClassFileLoader; +import com.pan.jvm.method.Method; +import com.pan.jvm.util.Util; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + + + + + +public class ClassFileloaderTest { + + + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + + static String path1 = EmployeeV1.class.getClassLoader().getResource("").getPath() + .replace("test-classes", "classes"); + static String path2 = "C:\temp"; + +// static ClassFile clzFile = null; +// static { +// ClassFileLoader loader = new ClassFileLoader(); +// loader.addClassPath(path1); +// String className = "com.pan.jvm.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 = "com.pan.jvm.EmployeeV1"; + + byte[] byteCodes = loader.readBinaryCode(className); + + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + Assert.assertEquals(1032, byteCodes.length); + + } + + + @Test + public void testMagicNumber(){ + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "com.pan.jvm.EmployeeV1"; + byte[] byteCodes = loader.readBinaryCode(className); + byte[] codes = new byte[]{byteCodes[0],byteCodes[1],byteCodes[2],byteCodes[3]}; + + + String acctualValue = Util.byteToHexString(codes); + + Assert.assertEquals("cafebabe", acctualValue); + } + + + /** + * ---------------------------------------------------------------------- + */ +// +// +// @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("<init>", 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()); +// } +// +// /** +// * 下面是第三次JVM课应实现的测试用例 +// */ +// @Test +// public void testReadFields(){ +// +// List<Field> fields = clzFile.getFields(); +// Assert.assertEquals(2, fields.size()); +// { +// Field f = fields.get(0); +// Assert.assertEquals("name:Ljava/lang/String;", f.toString()); +// } +// { +// Field f = fields.get(1); +// Assert.assertEquals("age:I", f.toString()); +// } +// } +// @Test +// public void testMethods(){ +// +// List<Method> methods = clzFile.getMethods(); +// ConstantPool pool = clzFile.getConstantPool(); +// +// { +// Method m = methods.get(0); +// assertMethodEquals(pool,m, +// "<init>", +// "(Ljava/lang/String;I)V", +// "2ab7000c2a2bb5000f2a1cb50011b1"); +// +// } +// { +// Method m = methods.get(1); +// assertMethodEquals(pool,m, +// "setName", +// "(Ljava/lang/String;)V", +// "2a2bb5000fb1"); +// +// } +// { +// Method m = methods.get(2); +// assertMethodEquals(pool,m, +// "setAge", +// "(I)V", +// "2a1bb50011b1"); +// } +// { +// Method m = methods.get(3); +// assertMethodEquals(pool,m, +// "sayHello", +// "()V", +// "b2001c1222b60024b1"); +// +// } +// { +// Method m = methods.get(4); +// assertMethodEquals(pool,m, +// "main", +// "([Ljava/lang/String;)V", +// "bb000159122b101db7002d4c2bb6002fb1"); +// } +// } +// +// private void assertMethodEquals(ConstantPool pool,Method m , String expectedName, String expectedDesc,String expectedCode){ +// String methodName = pool.getUTF8String(m.getNameIndex()); +// String methodDesc = pool.getUTF8String(m.getDescriptorIndex()); +// String code = m.getCodeAttr().getCode(); +// Assert.assertEquals(expectedName, methodName); +// Assert.assertEquals(expectedDesc, methodDesc); +// Assert.assertEquals(expectedCode, code); +// } + + +} From 59007c7fa3600a4e4a86abea3540892f04a652cc Mon Sep 17 00:00:00 2001 From: Alvin <conf1102@163.com> Date: Tue, 11 Apr 2017 23:15:57 -0800 Subject: [PATCH 228/287] Homework April 5th --- .../com/coderising/jvm/clz/AccessFlag.java | 25 ++++ .../src/com/coderising/jvm/clz/ClassFile.java | 79 +++++++++++ .../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 | 55 ++++++++ .../jvm/constant/NullConstantInfo.java | 13 ++ .../coderising/jvm/constant/StringInfo.java | 26 ++++ .../com/coderising/jvm/constant/UTF8Info.java | 32 +++++ .../jvm/loader/ByteCodeIterator.java | 47 +++++++ .../jvm/loader/ClassFileLoader.java | 114 ++++++++++----- .../jvm/loader/ClassFileParser.java | 132 ++++++++++++++++++ .../jvm/test/ClassFileloaderTest.java | 113 ++++++++++++++- .../jvm/util/ClassFileLoaderUtil.java | 14 -- .../src/com/coderising/jvm/util/Util.java | 24 ++++ 18 files changed, 833 insertions(+), 51 deletions(-) create mode 100644 group20/404130810/src/com/coderising/jvm/clz/AccessFlag.java create mode 100644 group20/404130810/src/com/coderising/jvm/clz/ClassFile.java create mode 100644 group20/404130810/src/com/coderising/jvm/clz/ClassIndex.java create mode 100644 group20/404130810/src/com/coderising/jvm/constant/ClassInfo.java create mode 100644 group20/404130810/src/com/coderising/jvm/constant/ConstantInfo.java create mode 100644 group20/404130810/src/com/coderising/jvm/constant/ConstantPool.java create mode 100644 group20/404130810/src/com/coderising/jvm/constant/FieldRefInfo.java create mode 100644 group20/404130810/src/com/coderising/jvm/constant/MethodRefInfo.java create mode 100644 group20/404130810/src/com/coderising/jvm/constant/NameAndTypeInfo.java create mode 100644 group20/404130810/src/com/coderising/jvm/constant/NullConstantInfo.java create mode 100644 group20/404130810/src/com/coderising/jvm/constant/StringInfo.java create mode 100644 group20/404130810/src/com/coderising/jvm/constant/UTF8Info.java create mode 100644 group20/404130810/src/com/coderising/jvm/loader/ByteCodeIterator.java create mode 100644 group20/404130810/src/com/coderising/jvm/loader/ClassFileParser.java delete mode 100644 group20/404130810/src/com/coderising/jvm/util/ClassFileLoaderUtil.java create mode 100644 group20/404130810/src/com/coderising/jvm/util/Util.java diff --git a/group20/404130810/src/com/coderising/jvm/clz/AccessFlag.java b/group20/404130810/src/com/coderising/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..cdb8f8859a --- /dev/null +++ b/group20/404130810/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/group20/404130810/src/com/coderising/jvm/clz/ClassFile.java b/group20/404130810/src/com/coderising/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..43378d0dd6 --- /dev/null +++ b/group20/404130810/src/com/coderising/jvm/clz/ClassFile.java @@ -0,0 +1,79 @@ +package com.coderising.jvm.clz; + +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantPool; + +public class ClassFile { + private String magicNumer; + + private int minorVersion; + private int majorVersion; + + private AccessFlag accessFlag; + private ClassIndex clzIndex; + private ConstantPool pool; + + + + public String getMagicNumer() { + return magicNumer; + } + public void setMagicNumer(String magicNumer) { + this.magicNumer = magicNumer; + } + 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 AccessFlag getAccessFlag() { + return accessFlag; + } + public void setAccessFlag(AccessFlag accessFlag) { + this.accessFlag = accessFlag; + } + public ClassIndex getClzIndex() { + return clzIndex; + } + public void setClassIndex(ClassIndex clzIndex) { + this.clzIndex = clzIndex; + } + + public ConstantPool getPool() { + return pool; + } + public void setPool(ConstantPool pool) { + this.pool = pool; + } + + 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.getPool().getConstantInfo(thisClassIndex); + return thisClass.getClassName(); + } + private String getSuperClassName(){ + ClassInfo superClass = (ClassInfo)this.getPool().getConstantInfo(this.clzIndex.getSuperClassIndex()); + return superClass.getClassName(); + } + + +} diff --git a/group20/404130810/src/com/coderising/jvm/clz/ClassIndex.java b/group20/404130810/src/com/coderising/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..df22981441 --- /dev/null +++ b/group20/404130810/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/group20/404130810/src/com/coderising/jvm/constant/ClassInfo.java b/group20/404130810/src/com/coderising/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..e12b3e164e --- /dev/null +++ b/group20/404130810/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/group20/404130810/src/com/coderising/jvm/constant/ConstantInfo.java b/group20/404130810/src/com/coderising/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..c8035ae876 --- /dev/null +++ b/group20/404130810/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/group20/404130810/src/com/coderising/jvm/constant/ConstantPool.java b/group20/404130810/src/com/coderising/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..0e940b78d0 --- /dev/null +++ b/group20/404130810/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<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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/404130810/src/com/coderising/jvm/constant/FieldRefInfo.java b/group20/404130810/src/com/coderising/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..7ff9d5fb77 --- /dev/null +++ b/group20/404130810/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/group20/404130810/src/com/coderising/jvm/constant/MethodRefInfo.java b/group20/404130810/src/com/coderising/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..0feffa65b5 --- /dev/null +++ b/group20/404130810/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/group20/404130810/src/com/coderising/jvm/constant/NameAndTypeInfo.java b/group20/404130810/src/com/coderising/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..1785dc3b33 --- /dev/null +++ b/group20/404130810/src/com/coderising/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,55 @@ +package com.coderising.jvm.constant; + +public class NameAndTypeInfo extends ConstantInfo{ + public int type = ConstantInfo.NAME_AND_TYPE_INFO; + + + + private int index_Name; + private int index_Describe; + + public int getIndex_Name() { + return index_Name; + } + + + public void setIndex_Name(int index_Name) { + this.index_Name = index_Name; + } + + + public int getIndex_Describe() { + return index_Describe; + } + + + public void setIndex_Describe(int index_Describe) { + this.index_Describe = index_Describe; + } + + public NameAndTypeInfo(ConstantPool pool) { + super(pool); + } + + + public int getType() { + return type; + } + + + public String getName(){ + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info1 = (UTF8Info)pool.getConstantInfo(index_Name); + return utf8Info1.getValue(); + } + + public String getTypeInfo(){ + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info2 = (UTF8Info)pool.getConstantInfo(index_Describe); + return utf8Info2.getValue(); + } + + public String toString(){ + return "(" + getName() + "," + getTypeInfo()+")"; + } +} diff --git a/group20/404130810/src/com/coderising/jvm/constant/NullConstantInfo.java b/group20/404130810/src/com/coderising/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..fa90d110fe --- /dev/null +++ b/group20/404130810/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/404130810/src/com/coderising/jvm/constant/StringInfo.java b/group20/404130810/src/com/coderising/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..d01065fd53 --- /dev/null +++ b/group20/404130810/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/404130810/src/com/coderising/jvm/constant/UTF8Info.java b/group20/404130810/src/com/coderising/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..b7407d146f --- /dev/null +++ b/group20/404130810/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/group20/404130810/src/com/coderising/jvm/loader/ByteCodeIterator.java b/group20/404130810/src/com/coderising/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..1ded13d243 --- /dev/null +++ b/group20/404130810/src/com/coderising/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,47 @@ +package com.coderising.jvm.loader; + +import com.coderising.jvm.util.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.byteToInt(new byte[]{codes[pos++]}); + } + return -1; + } + public int next2BytesToInt(){ + if (pos < this.codes.length) { + return Util.byteToInt(new byte[]{codes[pos++],codes[pos++]}); + } + return -1; + } + public String next2BytesToHexString(){ + if (pos < this.codes.length) { + return Util.byteToHexString(new byte[]{codes[pos++],codes[pos++]}); + } + return null; + } + public String next4BytesToString(){ + if (pos < this.codes.length) { + return Util.byteToHexString(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/404130810/src/com/coderising/jvm/loader/ClassFileLoader.java b/group20/404130810/src/com/coderising/jvm/loader/ClassFileLoader.java index db46e7312b..73a21d0157 100644 --- a/group20/404130810/src/com/coderising/jvm/loader/ClassFileLoader.java +++ b/group20/404130810/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -1,62 +1,106 @@ package com.coderising.jvm.loader; -import java.io.ByteArrayOutputStream; +import java.io.File; 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; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; + +import com.coderising.jvm.clz.ClassFile; public class ClassFileLoader { private List<String> clzPaths = new ArrayList<String>(); public byte[] readBinaryCode(String className) { - 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(); - } + + 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 baos.toByteArray(); + 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) { - clzPaths.add(path); + if (this.clzPaths.contains(path)) { + return; + } + this.clzPaths.add(path); } public String getClassPath() { - StringBuilder sb = new StringBuilder(); + return StringUtils.join(this.clzPaths, ";"); + } - 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(); + 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/group20/404130810/src/com/coderising/jvm/loader/ClassFileParser.java b/group20/404130810/src/com/coderising/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..c2673fff41 --- /dev/null +++ b/group20/404130810/src/com/coderising/jvm/loader/ClassFileParser.java @@ -0,0 +1,132 @@ +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) { + + ClassFile clzFile = new ClassFile(); + + ByteCodeIterator iterator = new ByteCodeIterator(codes); + // Magic Number + String magicNumber = iterator.next4BytesToString(); + clzFile.setMagicNumer(magicNumber); + // 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) { + int flagValue = iterator.next2BytesToInt(); + AccessFlag accessFlag = new AccessFlag(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){ + MethodRefInfo methofInfo = new MethodRefInfo(pool); + int index_ClassInfo = iterator.next2BytesToInt(); + int index_NameAndType = iterator.next2BytesToInt(); + + methofInfo.setClassInfoIndex(index_ClassInfo); + methofInfo.setNameAndTypeIndex(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.setClassInfoIndex(index_ClassInfo); + fieldRefInfo.setNameAndTypeIndex(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/404130810/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group20/404130810/src/com/coderising/jvm/test/ClassFileloaderTest.java index 886ce0f25a..abcf44ae36 100644 --- a/group20/404130810/src/com/coderising/jvm/test/ClassFileloaderTest.java +++ b/group20/404130810/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -5,13 +5,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.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; public class ClassFileloaderTest { - static String path1 = "E:\\MyDev\\mygit\\coding2017\\group20\\404130810\\bin\\"; + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + + static String path1 = "E:\\MyDev\\mygit\\coding2017\\group20\\404130810\\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 { } @@ -75,4 +93,95 @@ private String byteToHexString(byte[] codes) { return buffer.toString(); } -} \ No newline at end of file + /** + * ---------------------------------------------------------------------- + */ + + @Test + public void testVersion() { + + Assert.assertEquals(0, clzFile.getMinorVersion()); + Assert.assertEquals(52, clzFile.getMajorVersion()); + + } + + @Test + public void testConstantPool() { + + ConstantPool pool = clzFile.getPool(); + + 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("<init>", 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.getIndex_Name()); + Assert.assertEquals(14, nameAndType.getIndex_Describe()); + } + // 鼸 + { + 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.getPool().getConstantInfo(clzIndex.getThisClassIndex()); + ClassInfo superClassInfo = (ClassInfo) clzFile.getPool().getConstantInfo(clzIndex.getSuperClassIndex()); + + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); + Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); + } + +} diff --git a/group20/404130810/src/com/coderising/jvm/util/ClassFileLoaderUtil.java b/group20/404130810/src/com/coderising/jvm/util/ClassFileLoaderUtil.java deleted file mode 100644 index 62bb72a3ec..0000000000 --- a/group20/404130810/src/com/coderising/jvm/util/ClassFileLoaderUtil.java +++ /dev/null @@ -1,14 +0,0 @@ -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(); - } - -} diff --git a/group20/404130810/src/com/coderising/jvm/util/Util.java b/group20/404130810/src/com/coderising/jvm/util/Util.java new file mode 100644 index 0000000000..176f70d002 --- /dev/null +++ b/group20/404130810/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<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 8aafd6a0b95fa06f4a933c59ceef332212330f90 Mon Sep 17 00:00:00 2001 From: GZ-RXP <283091182@qq.com> Date: Tue, 11 Apr 2017 23:35:12 +0800 Subject: [PATCH 229/287] Jvm first week - Magical Number Data Structure - LRU --- .../jvm/loader/ClassFileLoader.java | 93 ++++++++++++ .../jvm/test/ClassFileloaderTest.java | 92 ++++++++++++ .../com/coderising/jvm/test/EmployeeV1.java | 28 ++++ .../coding/basic/linklist/LRUPageFrame.java | 141 ++++++++++++++++++ .../basic/linklist/LRUPageFrameTest.java | 31 ++++ 5 files changed, 385 insertions(+) create mode 100644 group11/283091182/mini-jvm/com/coderising/jvm/loader/ClassFileLoader.java create mode 100644 group11/283091182/mini-jvm/com/coderising/jvm/test/ClassFileloaderTest.java create mode 100644 group11/283091182/mini-jvm/com/coderising/jvm/test/EmployeeV1.java create mode 100644 group11/283091182/src/com/coding/basic/linklist/LRUPageFrame.java create mode 100644 group11/283091182/src/com/coding/basic/linklist/LRUPageFrameTest.java diff --git a/group11/283091182/mini-jvm/com/coderising/jvm/loader/ClassFileLoader.java b/group11/283091182/mini-jvm/com/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..527e2f14d8 --- /dev/null +++ b/group11/283091182/mini-jvm/com/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,93 @@ +package com.coderising.jvm.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.Iterator; +import java.util.List; + + + +public class ClassFileLoader { + + private List<String> clzPaths = new ArrayList<String>(); + + public byte[] readBinaryCode(String className) { + + File classFile = getClassFileFromPath(className); + + byte[] buffer = new byte[1024]; + try { + FileInputStream fis = new FileInputStream(classFile); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + int readLen; + while((readLen = fis.read(buffer))>-1){ + baos.write(buffer, 0, readLen); + } + + return baos.toByteArray(); + + } catch (FileNotFoundException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } catch (IOException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + + public void addClassPath(String path) { + File clzPath = new File(path); + if(clzPath.exists() && clzPath.isDirectory()){ + this.clzPaths.add(path); + }else{ + System.out.println("Invalid path:"+ path); + } + } + + + + public String getClassPath(){ + StringBuilder sb = new StringBuilder(); + Iterator it = this.clzPaths.iterator(); + while(it.hasNext()){ + if(sb.length()>0){ + sb.append(";"); + } + sb.append(it.next()); + } + return sb.toString(); + } + + public File getClassFileFromPath(String className) { + Iterator it = this.clzPaths.iterator(); + + //replace "." with "\\" in windows + String fullclassPath = className.replaceAll("\\.", (File.separatorChar=='\\')?"\\\\":"/")+".class"; + + while(it.hasNext()){ + File clzFile; + String path = (String)it.next(); + if(path.endsWith(String.valueOf(File.separatorChar))){ + clzFile = new File(path+fullclassPath); + }else{ + clzFile = new File(path+File.separatorChar+fullclassPath); + } + + //Check file before further proceed + if(clzFile.exists()&&clzFile.isFile()){ + return clzFile; + } + } + + throw new RuntimeException("Class not found:"+className); + } + + + +} diff --git a/group11/283091182/mini-jvm/com/coderising/jvm/test/ClassFileloaderTest.java b/group11/283091182/mini-jvm/com/coderising/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..21d7e97074 --- /dev/null +++ b/group11/283091182/mini-jvm/com/coderising/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,92 @@ +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\\Administrator\\mygit\\coding2017\\liuxin\\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/group11/283091182/mini-jvm/com/coderising/jvm/test/EmployeeV1.java b/group11/283091182/mini-jvm/com/coderising/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..9a36573dd3 --- /dev/null +++ b/group11/283091182/mini-jvm/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/group11/283091182/src/com/coding/basic/linklist/LRUPageFrame.java b/group11/283091182/src/com/coding/basic/linklist/LRUPageFrame.java new file mode 100644 index 0000000000..9f6edbcb66 --- /dev/null +++ b/group11/283091182/src/com/coding/basic/linklist/LRUPageFrame.java @@ -0,0 +1,141 @@ +package com.coding.basic.linklist; + +/** + * 用双向链表实现LRU算法 + * @author liuxin + * + */ +public class LRUPageFrame { + + private static class Node { + + Node prev; + Node next; + int pageNum; + + Node() { + } + + Node(int pageNum, Node prev, Node next){ + this.pageNum = pageNum; + this.next = next; + this.prev = prev; + } + } + + private int capacity; + + private int size; + + + private Node first;// 链表头 + private Node last;// 链表尾 + + + public LRUPageFrame(int capacity) { + + this.capacity = capacity; + + } + + /** + * 获取缓存中对象 + * + * @param key + * @return + */ + public void access(int pageNum) { + System.out.println("CurrentList= "+this.toString()+"; accessing - "+pageNum); + Node target = find(pageNum); + if(target==null){ + createNewNodeAsHead(pageNum); + }else{ + moveExistingNodeToHead(target); + } + + } + + private void removeLast(){ + Node secToLast = last.prev; + last = null; + secToLast.next = null; + last = secToLast; + size--; + } + + private void moveExistingNodeToHead(Node node){ + + Node prev = node.prev; + Node next = node.next; + + if(prev==null){ + //already in the head,do nothing; + return; + } + + if(next==null){ + //currently in the tail + last = prev; + } + + //in the middle + prev.next = next; + if(next!=null){ + next.prev = prev; + } + node.prev = null; + node.next = first; + first = node; + } + + private void createNewNodeAsHead(int value){ + Node node = new Node(value,null,null); + //first node + if(size==0){ + this.first = node; + this.last = node; + this.size ++; + }else{ + //linklist already exists + this.first.prev = node; + node.next = this.first; + this.first = node; + this.size++; + + if(size>capacity){ + removeLast(); + } + } + + } + + private Node find(int value){ + if(size==0){ + return null; + } + Node temp = first; + while(temp!=null){ + if(temp.pageNum==value){ + return temp; + }else{ + temp = temp.next; + } + } + 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/group11/283091182/src/com/coding/basic/linklist/LRUPageFrameTest.java b/group11/283091182/src/com/coding/basic/linklist/LRUPageFrameTest.java new file mode 100644 index 0000000000..4070f1f2b3 --- /dev/null +++ b/group11/283091182/src/com/coding/basic/linklist/LRUPageFrameTest.java @@ -0,0 +1,31 @@ +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()); + } + +} From 3193fe0615ae8992107acd9fcb786c31f3c54961 Mon Sep 17 00:00:00 2001 From: Admin <Admin@DESKTOP-8UCBO6T> Date: Wed, 12 Apr 2017 07:57:13 +0800 Subject: [PATCH 230/287] 2 --- .../src/com/coderising/jvm/attr/CodeAttr.java | 55 +++++++- .../src/com/coderising/jvm/clz/ClassFile.java | 12 ++ .../jvm/loader/ByteCodeIterator.java | 4 + .../jvm/loader/ClassFileParser.java | 123 ++++++++++-------- .../src/com/coderising/jvm/method/Method.java | 15 ++- 5 files changed, 149 insertions(+), 60 deletions(-) diff --git a/group12/382266293/src/com/coderising/jvm/attr/CodeAttr.java b/group12/382266293/src/com/coderising/jvm/attr/CodeAttr.java index e2bcf2fb36..68a628ec61 100644 --- a/group12/382266293/src/com/coderising/jvm/attr/CodeAttr.java +++ b/group12/382266293/src/com/coderising/jvm/attr/CodeAttr.java @@ -1,5 +1,7 @@ package com.coderising.jvm.attr; +import java.io.UnsupportedEncodingException; + import com.coderising.jvm.clz.ClassFile; import com.coderising.jvm.constant.ConstantPool; import com.coderising.jvm.field.Field; @@ -43,24 +45,67 @@ public void setLocalVariableTable(LocalVariableTable t) { public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ int attrNameIndex = iter.nextU2ToInt(); + System.out.println("attrIndex " + attrNameIndex); + int attrLen = iter.nextU4ToInt(); int maxStack = iter.nextU2ToInt(); - System.out.println("maxStack " + maxStack); + int maxLocals = iter.nextU2ToInt(); int codeLen = iter.nextU4ToInt(); - //System.out.println("Code is " + codeLen); + + System.out.println("codeLen " + codeLen); + CodeAttr codeAttr = new CodeAttr(attrNameIndex, attrLen, maxStack, maxLocals, codeLen, "Code"); + String code = iter.nextUxToHexString(codeLen); - - + System.out.println("Code is " + code); + int exceptionTableLen = iter.nextU2ToInt(); + if (exceptionTableLen > 0) { + + String exTable = iter.nextUxToHexString(exceptionTableLen); + + System.out.println("exception encounted " + exTable); + } + + int sub_attrNum = iter.nextU2ToInt(); - return null; + for (int i = 0; i < sub_attrNum; i++) { + + int subAttrNameIndex = iter.nextU2ToInt(); + String subAttrName = clzFile.getConstantPool().getUTF8String(subAttrNameIndex); + System.out.println("subAttrNameIndex is " + subAttrName); + iter.back(2); + + if (AttributeInfo.LINE_NUM_TABLE.equalsIgnoreCase(subAttrName)) { + + LineNumberTable lnt = LineNumberTable.parse(iter); + codeAttr.setLineNumberTable(lnt); + + } else if (AttributeInfo.LOCAL_VAR_TABLE.equalsIgnoreCase(subAttrName)) { + + LocalVariableTable lvt = LocalVariableTable.parse(iter); + codeAttr.setLocalVariableTable(lvt); + + } else if (AttributeInfo.STACK_MAP_TABLE.equalsIgnoreCase(subAttrName)) { + + StackMapTable smt = StackMapTable.parse(iter); + codeAttr.setStackMapTable(smt); + + } else { + throw new RuntimeException(subAttrName + "not implemented yet"); + } + + } + + return codeAttr; } + + private void setStackMapTable(StackMapTable t) { this.stackMapTable = t; diff --git a/group12/382266293/src/com/coderising/jvm/clz/ClassFile.java b/group12/382266293/src/com/coderising/jvm/clz/ClassFile.java index e9ae0b9bc8..6e37d03643 100644 --- a/group12/382266293/src/com/coderising/jvm/clz/ClassFile.java +++ b/group12/382266293/src/com/coderising/jvm/clz/ClassFile.java @@ -92,6 +92,12 @@ public void setFields(List<Field> fields) { this.fields = fields; } + + public void addField(Field field) { + + this.fields.add(field); + + } public List<Method> getMethods() { @@ -103,4 +109,10 @@ public void setMethods(List<Method> methods) { this.methods = methods; } + + public void addMethod(Method method) { + + this.methods.add(method); + + } } diff --git a/group12/382266293/src/com/coderising/jvm/loader/ByteCodeIterator.java b/group12/382266293/src/com/coderising/jvm/loader/ByteCodeIterator.java index bff24529f1..4b554a434a 100644 --- a/group12/382266293/src/com/coderising/jvm/loader/ByteCodeIterator.java +++ b/group12/382266293/src/com/coderising/jvm/loader/ByteCodeIterator.java @@ -62,4 +62,8 @@ public String byteToHexString(byte[] codes) { return buffer.toString(); } + public void back(int i) { + currPos = currPos - 2; + } + } diff --git a/group12/382266293/src/com/coderising/jvm/loader/ClassFileParser.java b/group12/382266293/src/com/coderising/jvm/loader/ClassFileParser.java index acaeb8e39d..e1c997d3d0 100644 --- a/group12/382266293/src/com/coderising/jvm/loader/ClassFileParser.java +++ b/group12/382266293/src/com/coderising/jvm/loader/ClassFileParser.java @@ -42,10 +42,81 @@ public ClassFile parse(byte[] codes) { System.out.println("majorVersion is " + majorVersion); clzFile.setMajorVersion(majorVersion); + + ConstantPool pool = parseConstantPool(iter); + clzFile.setConstPool(pool); + + + AccessFlag accessFlag = parseAccessFlag(iter); + clzFile.setAccessFlag(accessFlag); + + ClassIndex classIndex = parseClassIndex(iter); + clzFile.setClassIndex(classIndex); + + parseInterfaces(iter); + + parseFields(clzFile, iter); + + parseMethods(clzFile, iter); + + return clzFile; + } + + private void parseMethods(ClassFile clzFile, ByteCodeIterator iter) { + + int methodNum = iter.nextU2ToInt(); + + ConstantPool pool = clzFile.getConstantPool(); + for (int i = 0; i < methodNum; i++) { + Method method = Method.parse(clzFile,iter); + clzFile.addMethod(method); + } + + } + + private void parseFields(ClassFile clzFile, ByteCodeIterator iter) { + + int fieldNum = iter.nextU2ToInt(); + + ConstantPool pool = clzFile.getConstantPool(); + for (int i = 0; i < fieldNum; i++) { + Field field = Field.parse(pool,iter); + clzFile.addField(field); + } + + } + + private void parseInterfaces(ByteCodeIterator iter) { + int interfaceNum = iter.nextU2ToInt(); + + if (0 != interfaceNum) { + throw new RuntimeException("interface parser not finsihed yet, pls check!"); + } + + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + + return AccessFlag.parseAccessFlag(iter); + } + + 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 constantsNum = iter.nextU2ToInt(); System.out.println("constantsNum is " + constantsNum); + ConstantPool pool = new ConstantPool(); - clzFile.setConstPool(pool); pool.addConstantInfo(new NullConstantInfo()); @@ -113,56 +184,6 @@ public ClassFile parse(byte[] codes) { } } - - AccessFlag accessFlag = parseAccessFlag(iter); - ClassIndex classIndex = parseClassIndex(iter); - - clzFile.setAccessFlag(accessFlag); - clzFile.setClassIndex(classIndex); - - int interfaceNum = iter.nextU2ToInt(); - if (0 != interfaceNum) { - throw new RuntimeException("interface parser not finsihed yet, pls check!"); - } - - int fieldNum = iter.nextU2ToInt(); - List<Field> fields = new ArrayList<Field>(); - for (int i = 0; i < fieldNum; i++) { - Field field = Field.parse(pool,iter); - fields.add(field); - } - clzFile.setFields(fields); - - int methodNum = iter.nextU2ToInt(); - List<Method> methods = new ArrayList<Method>(); - for (int i = 0; i < methodNum; i++) { - Method method = Method.parse(clzFile,iter); - methods.add(method); - } - clzFile.setMethods(methods); - - return clzFile; - } - - private AccessFlag parseAccessFlag(ByteCodeIterator iter) { - - return AccessFlag.parseAccessFlag(iter); - } - - 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/method/Method.java b/group12/382266293/src/com/coderising/jvm/method/Method.java index a3075e1e58..3c3e026a40 100644 --- a/group12/382266293/src/com/coderising/jvm/method/Method.java +++ b/group12/382266293/src/com/coderising/jvm/method/Method.java @@ -55,13 +55,20 @@ public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ int name_index = iter.nextU2ToInt(); int descriptor_index = iter.nextU2ToInt(); int attrbutes_count = iter.nextU2ToInt(); - System.out.println("count - = " + attrbutes_count); + System.out.println("count1 = " + attrbutes_count); + Method method = new Method(clzFile, access_flags,name_index,descriptor_index); for (int i = 0; i < attrbutes_count; i++) { - int attr_name = iter.nextU2ToInt(); - if (clzFile.getConstantPool().getUTF8String(attr_name).equals("Code")) { - CodeAttr code = CodeAttr.parse(clzFile, iter); + int attr_nameIndex = iter.nextU2ToInt(); + String att_name = clzFile.getConstantPool().getUTF8String(attr_nameIndex); + iter.back(2); + + if (AttributeInfo.CODE.equalsIgnoreCase("Code")) { + CodeAttr codeAttr = CodeAttr.parse(clzFile, iter); + method.setCodeAttr(codeAttr); + } else { + throw new RuntimeException(att_name + "has not been implemented"); } } From 9562ceef8c5429a9b787362ecb5681635759d39d Mon Sep 17 00:00:00 2001 From: GUK0 <1685605435@qq.com> Date: Wed, 12 Apr 2017 10:28:46 +0800 Subject: [PATCH 231/287] =?UTF-8?q?=E9=87=8D=E6=9E=84=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{ => structure}/week1/ArrayList.java | 28 +-- .../{ => structure}/week1/BinaryTreeNode.java | 2 +- .../{ => structure}/week1/Iterator.java | 2 +- .../{ => structure}/week1/LinkedList.java | 13 +- .../247565311/{ => structure}/week1/List.java | 4 +- .../{ => structure}/week1/Queue.java | 2 +- .../{ => structure}/week1/Stack.java | 4 +- .../{ => structure}/week2/ArrayUtil.java | 4 +- .../{ => structure}/week2/ArrayUtilTest.java | 2 +- .../{ => structure}/week3/LinkedList.java | 6 +- .../{ => structure}/week3/LinkedListTest.java | 2 +- .../{ => structure}/week5/LRUPageFrame.java | 6 +- .../week5/LRUPageFrameTest.java | 2 +- .../247565311/structure/week6/StackUtil.java | 133 +++++++++++ .../structure/week6/StackUtilTest.java | 78 +++++++ .../{week6 => structure/week7}/InfixExpr.java | 38 ++-- .../week7}/InfixExprTest.java | 31 ++- group12/247565311/week2/struts.xml | 11 - .../LoginAction.java | 2 +- .../{week2 => week2_miniStruts}/Struts.java | 2 +- .../StrutsTest.java | 2 +- .../{week2 => week2_miniStruts}/View.java | 2 +- group12/247565311/week3/FileDownloader.java | 77 ------- group12/247565311/week3/api/Connection.java | 24 -- .../DownloadThread.java | 10 +- .../week3_fileDownloader/FileDownloader.java | 78 +++++++ .../FileDownloaderTest.java | 12 +- .../week3_fileDownloader/api/Connection.java | 23 ++ .../api/ConnectionException.java | 2 +- .../api/ConnectionManager.java | 4 +- .../api/DownloadListener.java | 2 +- .../impl/ConnectionImpl.java | 4 +- .../impl/ConnectionManagerImpl.java | 8 +- .../247565311/week5/ClassFileLoaderTest.java | 72 ------ .../week567_miniJVM/attr/AttributeInfo.java | 24 ++ .../week567_miniJVM/attr/CodeAttr.java | 63 ++++++ .../week567_miniJVM/attr/LineNumberTable.java | 51 +++++ .../attr/LocalVariableItem.java | 47 ++++ .../attr/LocalVariableTable.java | 37 +++ .../week567_miniJVM/attr/StackMapTable.java | 44 ++++ .../clz/AccessFlag.java | 2 +- .../clz/ClassFile.java | 15 +- .../clz/ClassIndex.java | 2 +- .../constant/ClassInfo.java | 2 +- .../constant/ConstantInfo.java | 2 +- .../constant/ConstantPool.java | 2 +- .../constant/FieldRefInfo.java | 2 +- .../constant/MethodRefInfo.java | 2 +- .../constant/NameAndTypeInfo.java | 2 +- .../constant/NullConstantInfo.java | 2 +- .../constant/StringInfo.java | 2 +- .../constant/UTF8Info.java | 2 +- .../week567_miniJVM/field/Field.java | 33 +++ .../loader/ByteCodeIterator.java | 20 ++ .../loader}/ClassFileLoader.java | 18 +- .../loader/ClassFileParser.java | 44 ++++ .../week567_miniJVM/method/Method.java | 58 +++++ .../test/ClassFileLoaderTest.java} | 212 ++++++++++-------- .../test}/EmployeeV1.java | 2 +- .../{week6 => week567_miniJVM}/util/Util.java | 2 +- .../week6/loader/ByteCodeIterator.java | 5 - .../week6/loader/ClassFileLoader.java | 136 ----------- .../week6/loader/ClassFileParser.java | 44 ---- group12/247565311/week6/test/EmployeeV1.java | 28 --- 64 files changed, 976 insertions(+), 621 deletions(-) rename group12/247565311/{ => structure}/week1/ArrayList.java (90%) rename group12/247565311/{ => structure}/week1/BinaryTreeNode.java (95%) rename group12/247565311/{ => structure}/week1/Iterator.java (75%) rename group12/247565311/{ => structure}/week1/LinkedList.java (97%) rename group12/247565311/{ => structure}/week1/List.java (73%) rename group12/247565311/{ => structure}/week1/Queue.java (94%) rename group12/247565311/{ => structure}/week1/Stack.java (91%) rename group12/247565311/{ => structure}/week2/ArrayUtil.java (98%) rename group12/247565311/{ => structure}/week2/ArrayUtilTest.java (99%) rename group12/247565311/{ => structure}/week3/LinkedList.java (98%) rename group12/247565311/{ => structure}/week3/LinkedListTest.java (99%) rename group12/247565311/{ => structure}/week5/LRUPageFrame.java (94%) rename group12/247565311/{ => structure}/week5/LRUPageFrameTest.java (96%) create mode 100644 group12/247565311/structure/week6/StackUtil.java create mode 100644 group12/247565311/structure/week6/StackUtilTest.java rename group12/247565311/{week6 => structure/week7}/InfixExpr.java (78%) rename group12/247565311/{week6 => structure/week7}/InfixExprTest.java (50%) delete mode 100644 group12/247565311/week2/struts.xml rename group12/247565311/{week2 => week2_miniStruts}/LoginAction.java (96%) rename group12/247565311/{week2 => week2_miniStruts}/Struts.java (99%) rename group12/247565311/{week2 => week2_miniStruts}/StrutsTest.java (97%) rename group12/247565311/{week2 => week2_miniStruts}/View.java (94%) delete mode 100644 group12/247565311/week3/FileDownloader.java delete mode 100644 group12/247565311/week3/api/Connection.java rename group12/247565311/{week3 => week3_fileDownloader}/DownloadThread.java (85%) create mode 100644 group12/247565311/week3_fileDownloader/FileDownloader.java rename group12/247565311/{week3 => week3_fileDownloader}/FileDownloaderTest.java (74%) create mode 100644 group12/247565311/week3_fileDownloader/api/Connection.java rename group12/247565311/{week3 => week3_fileDownloader}/api/ConnectionException.java (73%) rename group12/247565311/{week3 => week3_fileDownloader}/api/ConnectionManager.java (61%) rename group12/247565311/{week3 => week3_fileDownloader}/api/DownloadListener.java (67%) rename group12/247565311/{week3 => week3_fileDownloader}/impl/ConnectionImpl.java (95%) rename group12/247565311/{week3 => week3_fileDownloader}/impl/ConnectionManagerImpl.java (64%) delete mode 100644 group12/247565311/week5/ClassFileLoaderTest.java create mode 100644 group12/247565311/week567_miniJVM/attr/AttributeInfo.java create mode 100644 group12/247565311/week567_miniJVM/attr/CodeAttr.java create mode 100644 group12/247565311/week567_miniJVM/attr/LineNumberTable.java create mode 100644 group12/247565311/week567_miniJVM/attr/LocalVariableItem.java create mode 100644 group12/247565311/week567_miniJVM/attr/LocalVariableTable.java create mode 100644 group12/247565311/week567_miniJVM/attr/StackMapTable.java rename group12/247565311/{week6 => week567_miniJVM}/clz/AccessFlag.java (93%) rename group12/247565311/{week6 => week567_miniJVM}/clz/ClassFile.java (82%) rename group12/247565311/{week6 => week567_miniJVM}/clz/ClassIndex.java (93%) rename group12/247565311/{week6 => week567_miniJVM}/constant/ClassInfo.java (93%) rename group12/247565311/{week6 => week567_miniJVM}/constant/ConstantInfo.java (95%) rename group12/247565311/{week6 => week567_miniJVM}/constant/ConstantPool.java (94%) rename group12/247565311/{week6 => week567_miniJVM}/constant/FieldRefInfo.java (97%) rename group12/247565311/{week6 => week567_miniJVM}/constant/MethodRefInfo.java (97%) rename group12/247565311/{week6 => week567_miniJVM}/constant/NameAndTypeInfo.java (96%) rename group12/247565311/{week6 => week567_miniJVM}/constant/NullConstantInfo.java (81%) rename group12/247565311/{week6 => week567_miniJVM}/constant/StringInfo.java (92%) rename group12/247565311/{week6 => week567_miniJVM}/constant/UTF8Info.java (94%) create mode 100644 group12/247565311/week567_miniJVM/field/Field.java create mode 100644 group12/247565311/week567_miniJVM/loader/ByteCodeIterator.java rename group12/247565311/{week5 => week567_miniJVM/loader}/ClassFileLoader.java (86%) create mode 100644 group12/247565311/week567_miniJVM/loader/ClassFileParser.java create mode 100644 group12/247565311/week567_miniJVM/method/Method.java rename group12/247565311/{week6/test/ClassFileloaderTest.java => week567_miniJVM/test/ClassFileLoaderTest.java} (52%) rename group12/247565311/{week5 => week567_miniJVM/test}/EmployeeV1.java (50%) rename group12/247565311/{week6 => week567_miniJVM}/util/Util.java (94%) delete mode 100644 group12/247565311/week6/loader/ByteCodeIterator.java delete mode 100644 group12/247565311/week6/loader/ClassFileLoader.java delete mode 100644 group12/247565311/week6/loader/ClassFileParser.java delete mode 100644 group12/247565311/week6/test/EmployeeV1.java diff --git a/group12/247565311/week1/ArrayList.java b/group12/247565311/structure/week1/ArrayList.java similarity index 90% rename from group12/247565311/week1/ArrayList.java rename to group12/247565311/structure/week1/ArrayList.java index 794630a76c..a16c32e05c 100644 --- a/group12/247565311/week1/ArrayList.java +++ b/group12/247565311/structure/week1/ArrayList.java @@ -1,8 +1,10 @@ -package week1; +package structure.week1; import java.util.Collection; -public class ArrayList<E> implements List<E> { +import structure.week1.List; + +public class ArrayList<E>{ private int size=0,offset=10; private Object[] data = null; public ArrayList(){ @@ -13,7 +15,7 @@ public ArrayList(int arg0){ size = arg0; data = new Object[size]; } - @Override + public void add(Object arg0) { size += 1; int leng = data.length; @@ -27,8 +29,7 @@ public void add(Object arg0) { data[size-1] = arg0; } - @Override - public void add(int arg0, E arg1) { + public void add(int arg0, E arg1) { if( arg0>size || 0<arg0) return ; size += 1; int leng = data.length; @@ -106,7 +107,6 @@ public boolean containsAll(Collection<?> arg0) { return true; } - @Override public E get(int arg0) { if(arg0 >-1 && arg0<this.size) return (E)data[arg0]; return null; @@ -145,7 +145,6 @@ public boolean remove(Object arg0) { return false; } - @Override public E remove(int arg0) { if(arg0<0 ||arg0>this.size-1) return null; E res = (E)data[arg0]; @@ -174,22 +173,9 @@ public E set(int arg0, E arg1) { return arg1; } - @Override public int size() { return this.size; } - - public List<E> subList(int arg0, int arg1) { - if(arg0>=arg1 || arg0<0 || arg1>this.size-1) return null; - List<E> res = new ArrayList<E>(); - for(int i=arg0;i<arg1;i++){ - // λȡ - - - } - - return null; - } ////////////////////////////////////////////// public Object[] toArray() { if(this.size == 0) return null; @@ -207,12 +193,10 @@ public <T> T[] toArray(T[] arg0) { } return res; } - @Override public boolean hasNext() { // TODO Զɵķ return false; } - @Override public Object next() { // TODO Զɵķ return null; diff --git a/group12/247565311/week1/BinaryTreeNode.java b/group12/247565311/structure/week1/BinaryTreeNode.java similarity index 95% rename from group12/247565311/week1/BinaryTreeNode.java rename to group12/247565311/structure/week1/BinaryTreeNode.java index 617ca84348..87f74f86d9 100644 --- a/group12/247565311/week1/BinaryTreeNode.java +++ b/group12/247565311/structure/week1/BinaryTreeNode.java @@ -1,4 +1,4 @@ -package week1; +package structure.week1; public class BinaryTreeNode { diff --git a/group12/247565311/week1/Iterator.java b/group12/247565311/structure/week1/Iterator.java similarity index 75% rename from group12/247565311/week1/Iterator.java rename to group12/247565311/structure/week1/Iterator.java index 7967f1827e..0b6d47c931 100644 --- a/group12/247565311/week1/Iterator.java +++ b/group12/247565311/structure/week1/Iterator.java @@ -1,4 +1,4 @@ -package week1; +package structure.week1; public interface Iterator <E>{ public boolean hasNext(); diff --git a/group12/247565311/week1/LinkedList.java b/group12/247565311/structure/week1/LinkedList.java similarity index 97% rename from group12/247565311/week1/LinkedList.java rename to group12/247565311/structure/week1/LinkedList.java index 0b74925cbe..362959879b 100644 --- a/group12/247565311/week1/LinkedList.java +++ b/group12/247565311/structure/week1/LinkedList.java @@ -1,8 +1,8 @@ -package week1; +package structure.week1; import java.util.Collection; -public class LinkedList<E> implements List<E> { +public class LinkedList<E> { private Node head = null; private Node tail = null; private int size = 0; @@ -36,7 +36,6 @@ public Object clone(){ } return clone; } - @Override public void add(Object val) { Node n = new Node(val); n.next = tail; @@ -46,7 +45,6 @@ public void add(Object val) { size += 1; } - @Override public void add(int arg0, E arg1) { if(arg0<0 || arg0>size) arg0=0; Node n=new Node(arg1),p=head; @@ -104,7 +102,6 @@ public boolean containsAll(Collection<?> arg0) { return true; } - @Override public E get(int arg0) { E res = null; if(arg0>-1 && arg0 < size){ @@ -167,7 +164,6 @@ public boolean remove(Object arg0) { return true; } - @Override public E remove(int arg0) { Node n = head; if(arg0 <0 || arg0>size-1) return null; @@ -202,7 +198,6 @@ public E set(int arg0, E arg1) { return (E)(n.next.val); } - @Override public int size() { return size; } @@ -231,11 +226,11 @@ private static class Node{ Node next = null,ahead=null; public Node(Object arg0){val = arg0;} } - @Override + public boolean hasNext() { return false; } - @Override + public Object next() { return null; } diff --git a/group12/247565311/week1/List.java b/group12/247565311/structure/week1/List.java similarity index 73% rename from group12/247565311/week1/List.java rename to group12/247565311/structure/week1/List.java index a669a6169d..489ba4d6fe 100644 --- a/group12/247565311/week1/List.java +++ b/group12/247565311/structure/week1/List.java @@ -1,9 +1,9 @@ -package week1; +package structure.week1; public interface List<E> extends Iterator{ public void add(Object o); - public void add(int index, E o); public E get(int index); public E remove(int index); public int size(); + void add(int arg0, E arg1); } diff --git a/group12/247565311/week1/Queue.java b/group12/247565311/structure/week1/Queue.java similarity index 94% rename from group12/247565311/week1/Queue.java rename to group12/247565311/structure/week1/Queue.java index 78f25cb826..ec96650332 100644 --- a/group12/247565311/week1/Queue.java +++ b/group12/247565311/structure/week1/Queue.java @@ -1,4 +1,4 @@ -package week1; +package structure.week1; public class Queue<E> { private LinkedList<E> data = new LinkedList<E>(); public void enQueue(E arg0){ diff --git a/group12/247565311/week1/Stack.java b/group12/247565311/structure/week1/Stack.java similarity index 91% rename from group12/247565311/week1/Stack.java rename to group12/247565311/structure/week1/Stack.java index 5dcccc5fca..582f5d0eac 100644 --- a/group12/247565311/week1/Stack.java +++ b/group12/247565311/structure/week1/Stack.java @@ -1,6 +1,6 @@ -package week1; +package structure.week1; -import week1.List; +import structure.week1.List; public class Stack<E> { private ArrayList<E> data = new ArrayList<E>(); diff --git a/group12/247565311/week2/ArrayUtil.java b/group12/247565311/structure/week2/ArrayUtil.java similarity index 98% rename from group12/247565311/week2/ArrayUtil.java rename to group12/247565311/structure/week2/ArrayUtil.java index 00bab36625..4c29f58e7e 100644 --- a/group12/247565311/week2/ArrayUtil.java +++ b/group12/247565311/structure/week2/ArrayUtil.java @@ -1,5 +1,5 @@ -package week2; -import week1.ArrayList; +package structure.week2; +import structure.week1.ArrayList; public class ArrayUtil { diff --git a/group12/247565311/week2/ArrayUtilTest.java b/group12/247565311/structure/week2/ArrayUtilTest.java similarity index 99% rename from group12/247565311/week2/ArrayUtilTest.java rename to group12/247565311/structure/week2/ArrayUtilTest.java index b59b14dfe3..c1b414d725 100644 --- a/group12/247565311/week2/ArrayUtilTest.java +++ b/group12/247565311/structure/week2/ArrayUtilTest.java @@ -1,4 +1,4 @@ -package week2; +package structure.week2; import org.junit.After; import org.junit.Assert; import org.junit.Before; diff --git a/group12/247565311/week3/LinkedList.java b/group12/247565311/structure/week3/LinkedList.java similarity index 98% rename from group12/247565311/week3/LinkedList.java rename to group12/247565311/structure/week3/LinkedList.java index dbf9465386..af7f26ead0 100644 --- a/group12/247565311/week3/LinkedList.java +++ b/group12/247565311/structure/week3/LinkedList.java @@ -1,10 +1,10 @@ -package week3; +package structure.week3; import java.util.NoSuchElementException; -import week1.Iterator; -import week1.List; +import structure.week1.Iterator; +import structure.week1.List; public class LinkedList implements List { private Node head = new Node(); diff --git a/group12/247565311/week3/LinkedListTest.java b/group12/247565311/structure/week3/LinkedListTest.java similarity index 99% rename from group12/247565311/week3/LinkedListTest.java rename to group12/247565311/structure/week3/LinkedListTest.java index ef9388bf55..e189d729ea 100644 --- a/group12/247565311/week3/LinkedListTest.java +++ b/group12/247565311/structure/week3/LinkedListTest.java @@ -1,4 +1,4 @@ -package week3; +package structure.week3; import static org.junit.Assert.*; diff --git a/group12/247565311/week5/LRUPageFrame.java b/group12/247565311/structure/week5/LRUPageFrame.java similarity index 94% rename from group12/247565311/week5/LRUPageFrame.java rename to group12/247565311/structure/week5/LRUPageFrame.java index a3b99870e3..a114fdf768 100644 --- a/group12/247565311/week5/LRUPageFrame.java +++ b/group12/247565311/structure/week5/LRUPageFrame.java @@ -1,7 +1,7 @@ -package week5; +package structure.week5; import java.util.HashSet; -import week1.ArrayList; +import structure.week1.ArrayList; public class LRUPageFrame { int size; Node head = new Node(0); @@ -14,7 +14,7 @@ public Node(int _val){ next = null; } } - public LRU(int _size){ + public LRUPageFrame(int _size){ if(_size>0) { this.size = _size; } diff --git a/group12/247565311/week5/LRUPageFrameTest.java b/group12/247565311/structure/week5/LRUPageFrameTest.java similarity index 96% rename from group12/247565311/week5/LRUPageFrameTest.java rename to group12/247565311/structure/week5/LRUPageFrameTest.java index 8593a83739..cb795054d5 100644 --- a/group12/247565311/week5/LRUPageFrameTest.java +++ b/group12/247565311/structure/week5/LRUPageFrameTest.java @@ -1,4 +1,4 @@ -package week5; +package structure. week5; import static org.junit.Assert.*; diff --git a/group12/247565311/structure/week6/StackUtil.java b/group12/247565311/structure/week6/StackUtil.java new file mode 100644 index 0000000000..9895f02f30 --- /dev/null +++ b/group12/247565311/structure/week6/StackUtil.java @@ -0,0 +1,133 @@ +package structure.week6; +import java.util.Stack; +public class StackUtil { + + public static void bad_reverse(Stack<Integer> s) { + if(s == null || s.isEmpty()){ + return; + } + Stack<Integer> tmpStack = new Stack(); + while(!s.isEmpty()){ + tmpStack.push(s.pop()); + } + s = tmpStack; + } + + /** + * 閸嬪洩顔曢弽鍫滆厬閻ㄥ嫬鍘撶槐鐘虫ЦInteger, 娴犲孩鐖ゆい璺哄煂閺嶅牆绨抽弰锟� 5,4,3,2,1 鐠嬪啰鏁ょ拠銉︽煙濞夋洖鎮楅敍锟介崗鍐濞嗏�绨崣妯硅礋: 1,2,3,4,5 + * 濞夈劍鍓伴敍姘涧閼虫垝濞囬悽鈯縯ack閻ㄥ嫬鐔�張顒佹惙娴f粣绱濋崡纭僽sh,pop,peek,isEmpty閿涳拷閸欘垯浜掓担璺ㄦ暏閸欙箑顦绘稉锟介嚋閺嶅牊娼垫潏鍛И + */ + public static void reverse(Stack<Integer> s){ + if(s == null || s.isEmpty()) return; + int size = 0; + Stack<Integer> s1 = new Stack<Integer>(); + while(!s.isEmpty()){ + s1.push(s.pop()); + size += 1; + } + while(!s1.isEmpty()) + s.push(s1.pop()); + for(int i=0;i<size;i++){ + Integer integer = s.pop(); + while(s.size()>i) + s1.push(s.pop()); + s.push(integer); + while(s1.size()>0) + s.push(s1.pop()); + } + } + // 閫氳繃閫掑綊鍙互涓嶄娇鐢ㄥ爢鏍堝畬鎴愯繖涓�姛鑳� + public static void reverse2(Stack<Integer> s) { + if(s == null || s.isEmpty()){ + return; + } + Integer top = s.pop(); + reverse(s); + addToBottom(s,top); + } + public static void addToBottom(Stack<Integer> s, Integer value){ + if(s.isEmpty()){ + s.push(value); + } else{ + Integer top = s.pop(); + addToBottom(s,value); + s.push(top); + } + } + /** + * 閸掔娀娅庨弽鍫滆厬閻ㄥ嫭鐓囨稉顏勫帗缁憋拷濞夈劍鍓伴敍姘涧閼虫垝濞囬悽鈯縯ack閻ㄥ嫬鐔�張顒佹惙娴f粣绱濋崡纭僽sh,pop,peek,isEmpty閿涳拷閸欘垯浜掓担璺ㄦ暏閸欙箑顦绘稉锟介嚋閺嶅牊娼垫潏鍛И + * + * @param o + */ + public static void remove(Stack s,Object o) { + if(s == null || s.isEmpty()){ + return; + } + Stack tmpStack = new Stack(); + while(!s.isEmpty()){ + Object value = s.pop(); + if(!value.equals(o)){ + tmpStack.push(value); + } + } + while(!tmpStack.isEmpty()){ + s.push(tmpStack.pop()); + } + } + + /** + * 娴犲孩鐖ゆい璺哄絿瀵版en娑擃亜鍘撶槐锟�閸樼喐娼甸惃鍕垽娑擃厼鍘撶槐鐘辩箽閹镐椒绗夐崣锟� * 濞夈劍鍓伴敍姘涧閼虫垝濞囬悽鈯縯ack閻ㄥ嫬鐔�張顒佹惙娴f粣绱濋崡纭僽sh,pop,peek,isEmpty閿涳拷閸欘垯浜掓担璺ㄦ暏閸欙箑顦绘稉锟介嚋閺嶅牊娼垫潏鍛И + * @param len + * @return + */ + public static Object[] getTop(Stack s,int len) { + if(s == null || s.isEmpty() || s.size()<len || len <=0 ){ + return null; + } + Stack tmpStack = new Stack(); + int i = 0; + Object[] result = new Object[len]; + while(!s.isEmpty()){ + Object value = s.pop(); + tmpStack.push(value); + result[i++] = value; + if(i == len){ + break; + } + } + return result; + } + /** + * 鐎涙顑佹稉鐬�閸欘垵鍏橀崠鍛儓鏉╂瑤绨虹�妤冾儊閿涳拷 ( ) [ ] { }, a,b,c... x,yz + * 娴h法鏁ら崼鍡樼垽濡拷鐓$�妤冾儊娑撶灚娑擃厾娈戦幏顒�娇閺勵垯绗夐弰顖涘灇鐎电懓鍤悳鎵畱閵嗭拷 + * 娓氬顩 = "([e{d}f])" , 閸掓瑨顕氱�妤冾儊娑撹弓鑵戦惃鍕閸欓攱妲搁幋鎰嚠閸戣櫣骞囬敍锟界拠銉︽煙濞夋洝绻戦崶鐎焤ue + * 婵″倹鐏�s = "([b{x]y})", 閸掓瑨顕氱�妤冾儊娑撹弓鑵戦惃鍕閸欒渹绗夐弰顖涘灇鐎电懓鍤悳鎵畱閿涳拷鐠囥儲鏌熷▔鏇$箲閸ョ�alse; + * @param s + * @return + */ + public static boolean isValidPairs(String s){ + Stack<Character> stack = new Stack(); + for(int i=0;i<s.length();i++){ + char c = s.charAt(i); + if(c == '(' || c =='[' || c == '{'){ + stack.push(c); + } else if( c == ')'){ + char topChar = stack.pop(); + if(topChar != '('){ + return false; + } + } else if( c == ']'){ + char topChar = stack.pop(); + if(topChar != '['){ + return false; + } + } else if( c == '}'){ + char topChar = stack.pop(); + if(topChar != '{'){ + return false; + } + } + } + return stack.size() == 0; + } +} diff --git a/group12/247565311/structure/week6/StackUtilTest.java b/group12/247565311/structure/week6/StackUtilTest.java new file mode 100644 index 0000000000..f1a8aec8ac --- /dev/null +++ b/group12/247565311/structure/week6/StackUtilTest.java @@ -0,0 +1,78 @@ +package structure.week6; + +import static org.junit.Assert.fail; + +import java.util.Stack; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +public class StackUtilTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testAddToBottom() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + + StackUtil.addToBottom(s, 0); + + Assert.assertEquals("[0, 1, 2, 3]", s.toString()); + + } + @Test + public void testReverse() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + Assert.assertEquals("[1, 2, 3, 4, 5]", s.toString()); + StackUtil.reverse(s); + Assert.assertEquals("[5, 4, 3, 2, 1]", s.toString()); + } + + @Test + public void testRemove() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + StackUtil.remove(s, 2); + Assert.assertEquals("[1, 3]", s.toString()); + } + + @Test + public void testGetTop() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + { + Object[] values = StackUtil.getTop(s, 3); + Assert.assertEquals(5, values[0]); + Assert.assertEquals(4, values[1]); + Assert.assertEquals(3, values[2]); + } + } + + @Test + public void testIsValidPairs() { + Assert.assertTrue(StackUtil.isValidPairs("([e{d}f])")); + Assert.assertFalse(StackUtil.isValidPairs("([b{x]y})")); + } + +} \ No newline at end of file diff --git a/group12/247565311/week6/InfixExpr.java b/group12/247565311/structure/week7/InfixExpr.java similarity index 78% rename from group12/247565311/week6/InfixExpr.java rename to group12/247565311/structure/week7/InfixExpr.java index d50bc09c32..4fc4d13fbe 100644 --- a/group12/247565311/week6/InfixExpr.java +++ b/group12/247565311/structure/week7/InfixExpr.java @@ -1,27 +1,26 @@ -package week6; - +package structure.week7; +// 姹傝В琛ㄨ揪寮忓瓧绗︿覆锛岄鍏堝皢琛ㄨ揪寮忓垱寤烘垚涓�5琛ㄨ揪寮忔爲锛岄渶瑕佹牴鎹繍绠楃鐨勪紭鍏堢骇鏉ュ垱寤� public class InfixExpr { String expr = null; - Node node = new Node(); Element getElem = null; public InfixExpr(String expr) { this.expr = expr; getElem = new Element(expr); } - public float evaluate() { + public float evaluate() throws Exception{ Node node = new Node('\0',getElem.getNextNum()); Node root = createNode(node); - return getValue(root); + return (float) getValue(root); } class Element{ private int index; - private String str + private String str; public Element(String _str){ index = 0; str = _str; } public double getNextNum(){ - double resl = 0,resr; + double resl = 0,resr=0; int fbits = 0; char ch = str.charAt(index); boolean hasp = false; @@ -31,7 +30,7 @@ public double getNextNum(){ else{ if(hasp){ fbits -= 1; - resr += (double)(ch-'0') * Math.pow(10,fbits) + resr += (double)(ch-'0') * Math.pow(10,fbits); }else{ resl *= 10; resl += (ch-'0'); @@ -76,28 +75,25 @@ private Node createNode(Node root){ }else{ } - Node node = new Node(getElem.getNextOper,0); + Node node = new Node(getElem.getNextOper(),0); node.left = root; - node.right = + node.right = null; + // todo + return node; } - private double getValue(Node root){ - if(root == null) throw new Exception("inlegal operator found"); + private double getValue(Node root) throws Exception{ + if(root == null) throw new Exception("表达式非法"); switch(root.op){ case '+': return getValue(root.left)+getValue(root.right); - break; - case '-': + case '-': return getValue(root.left)-getValue(root.right); - break; - case '*': + case '*': return getValue(root.left)*getValue(root.right); - break; - case '/': + case '/': return getValue(root.left)/getValue(root.right); - break; - default: + default: return root.val; - break; } } } diff --git a/group12/247565311/week6/InfixExprTest.java b/group12/247565311/structure/week7/InfixExprTest.java similarity index 50% rename from group12/247565311/week6/InfixExprTest.java rename to group12/247565311/structure/week7/InfixExprTest.java index cbf7e5ef39..21680594de 100644 --- a/group12/247565311/week6/InfixExprTest.java +++ b/group12/247565311/structure/week7/InfixExprTest.java @@ -1,3 +1,4 @@ +package structure.week7; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -16,27 +17,47 @@ public void testEvaluate() { //InfixExpr expr = new InfixExpr("300*20+12*5-20/4"); { InfixExpr expr = new InfixExpr("2+3*4+5"); - Assert.assertEquals(19.0, expr.evaluate(), 0.001f); + try { + Assert.assertEquals(19.0, expr.evaluate(), 0.001f); + } catch (Exception e) { + e.printStackTrace(); + } } { InfixExpr expr = new InfixExpr("3*20+12*5-40/2"); - Assert.assertEquals(100.0, expr.evaluate(), 0.001f); + try { + Assert.assertEquals(100.0, expr.evaluate(), 0.001f); + } catch (Exception e) { + e.printStackTrace(); + } } { InfixExpr expr = new InfixExpr("3*20/2"); - Assert.assertEquals(30, expr.evaluate(), 0.001f); + try { + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } catch (Exception e) { + e.printStackTrace(); + } } { InfixExpr expr = new InfixExpr("20/2*3"); - Assert.assertEquals(30, expr.evaluate(), 0.001f); + try { + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } catch (Exception e) { + e.printStackTrace(); + } } { InfixExpr expr = new InfixExpr("10-30+50"); - Assert.assertEquals(30, expr.evaluate(), 0.001f); + try { + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } catch (Exception e) { + e.printStackTrace(); + } } } } \ No newline at end of file diff --git a/group12/247565311/week2/struts.xml b/group12/247565311/week2/struts.xml deleted file mode 100644 index 234232d0b6..0000000000 --- a/group12/247565311/week2/struts.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<struts> - <action name="login" class="week2.LoginAction"> - <result name="success">/jsp/homepage.jsp</result> - <result name="fail">/jsp/showLogin.jsp</result> - </action> - <action name="logout" class="week2.LogoutAction"> - <result name = "success">/jsp/welcome.jsp</result> - <result name = "error">/jsp/error.jsp</result> - </action> -</struts> diff --git a/group12/247565311/week2/LoginAction.java b/group12/247565311/week2_miniStruts/LoginAction.java similarity index 96% rename from group12/247565311/week2/LoginAction.java rename to group12/247565311/week2_miniStruts/LoginAction.java index b0ae6ebf5b..f696180eeb 100644 --- a/group12/247565311/week2/LoginAction.java +++ b/group12/247565311/week2_miniStruts/LoginAction.java @@ -1,4 +1,4 @@ -package week2; +package week2_miniStruts; public class LoginAction { private String name ; diff --git a/group12/247565311/week2/Struts.java b/group12/247565311/week2_miniStruts/Struts.java similarity index 99% rename from group12/247565311/week2/Struts.java rename to group12/247565311/week2_miniStruts/Struts.java index 9c8135be38..5ccadb610f 100644 --- a/group12/247565311/week2/Struts.java +++ b/group12/247565311/week2_miniStruts/Struts.java @@ -1,4 +1,4 @@ -package week2; +package week2_miniStruts; import java.io.File; import java.lang.reflect.Field; import java.lang.reflect.Method; diff --git a/group12/247565311/week2/StrutsTest.java b/group12/247565311/week2_miniStruts/StrutsTest.java similarity index 97% rename from group12/247565311/week2/StrutsTest.java rename to group12/247565311/week2_miniStruts/StrutsTest.java index 1be688671e..f0fa5dd5b7 100644 --- a/group12/247565311/week2/StrutsTest.java +++ b/group12/247565311/week2_miniStruts/StrutsTest.java @@ -1,4 +1,4 @@ -package week2; +package week2_miniStruts; import java.util.HashMap; import java.util.Map; diff --git a/group12/247565311/week2/View.java b/group12/247565311/week2_miniStruts/View.java similarity index 94% rename from group12/247565311/week2/View.java rename to group12/247565311/week2_miniStruts/View.java index 4f88ad3b84..3d69a03600 100644 --- a/group12/247565311/week2/View.java +++ b/group12/247565311/week2_miniStruts/View.java @@ -1,4 +1,4 @@ -package week2; +package week2_miniStruts; import java.util.Map; public class View { private String jsp; diff --git a/group12/247565311/week3/FileDownloader.java b/group12/247565311/week3/FileDownloader.java deleted file mode 100644 index 1a426c3682..0000000000 --- a/group12/247565311/week3/FileDownloader.java +++ /dev/null @@ -1,77 +0,0 @@ -package week3; -import java.util.concurrent.CyclicBarrier; -import java.io.IOException; -import java.io.RandomAccessFile; - -import week3.api.Connection; -import week3.api.ConnectionException; -import week3.api.ConnectionManager; -import week3.api.DownloadListener; -import week3.impl.ConnectionManagerImpl; - -public class FileDownloader { - private int MaxThreadNum = 4; - private String url = null,path=null; - DownloadListener listener = null; - private ConnectionManager cm = new ConnectionManagerImpl(); - - public FileDownloader(String weburl,String localpath) { - this.url = weburl; - this.path = localpath; - } - - public void execute() throws InterruptedException{ - // 在这里实现你的代码, 注意: 需要用多线程实现下载 - // 这个类依赖于其他几个接口, 你需要写这几个接口的实现代码 - // (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; - CyclicBarrier barr= new CyclicBarrier(MaxThreadNum,new Runnable(){ - public void run(){ - listener.notifyFinished(); - } - }); - try { - conn = cm.open(this.url); - int length = conn.getContentLength(); - // 在这里创建出一个同样大小的空文件, 路径是path - RandomAccessFile tarfile = new RandomAccessFile(path,"rw"); - tarfile.setLength(length); - tarfile.close(); - Thread[] threads = new Thread[4]; - threads[0] = new DownloadThread(barr,cm.open(this.url),0,length/4,path); - threads[1] = new DownloadThread(barr,cm.open(this.url),length/4,length/2,path); - threads[2] = new DownloadThread(barr,cm.open(this.url),length/2,3*length/4,path); - threads[3] = new DownloadThread(barr,cm.open(this.url),3*length/4,length,path); - for(int i=0;i<4;i++) - threads[i].start(); - } catch (ConnectionException | IOException 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; - } - public double getDownPercent(){ - return 0.0; - } -} diff --git a/group12/247565311/week3/api/Connection.java b/group12/247565311/week3/api/Connection.java deleted file mode 100644 index 8c34a8d07a..0000000000 --- a/group12/247565311/week3/api/Connection.java +++ /dev/null @@ -1,24 +0,0 @@ -package week3.api; - -import java.io.IOException; -import java.net.HttpURLConnection; - -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/group12/247565311/week3/DownloadThread.java b/group12/247565311/week3_fileDownloader/DownloadThread.java similarity index 85% rename from group12/247565311/week3/DownloadThread.java rename to group12/247565311/week3_fileDownloader/DownloadThread.java index 2670bef00b..11d228b652 100644 --- a/group12/247565311/week3/DownloadThread.java +++ b/group12/247565311/week3_fileDownloader/DownloadThread.java @@ -1,17 +1,11 @@ -package week3; +package week3_fileDownloader; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; -import week3.api.Connection; +import week3_fileDownloader.api.Connection; public class DownloadThread extends Thread{ Connection conn; diff --git a/group12/247565311/week3_fileDownloader/FileDownloader.java b/group12/247565311/week3_fileDownloader/FileDownloader.java new file mode 100644 index 0000000000..2c23ac39c0 --- /dev/null +++ b/group12/247565311/week3_fileDownloader/FileDownloader.java @@ -0,0 +1,78 @@ +package week3_fileDownloader; + +import java.util.concurrent.CyclicBarrier; +import java.io.IOException; +import java.io.RandomAccessFile; + +import week3_fileDownloader.api.Connection; +import week3_fileDownloader.api.ConnectionException; +import week3_fileDownloader.api.ConnectionManager; +import week3_fileDownloader.api.DownloadListener; +import week3_fileDownloader.impl.ConnectionManagerImpl; + +public class FileDownloader { + private int MaxThreadNum = 4; + private String url = null,path=null; + DownloadListener listener = null; + private ConnectionManager cm = new ConnectionManagerImpl(); + + public FileDownloader(String weburl,String localpath) { + this.url = weburl; + this.path = localpath; + } + + public void execute() throws InterruptedException{ + // 鍦ㄨ繖閲屽疄鐜颁綘鐨勪唬鐮侊紝 娉ㄦ剰锛�闇�鐢ㄥ绾跨▼瀹炵幇涓嬭浇 + // 杩欎釜绫讳緷璧栦簬鍏朵粬鍑犱釜鎺ュ彛, 浣犻渶瑕佸啓杩欏嚑涓帴鍙g殑瀹炵幇浠g爜 + // (1) ConnectionManager , 鍙互鎵撳紑涓�釜杩炴帴锛岄�杩嘋onnection鍙互璇诲彇鍏朵腑鐨勪竴娈碉紙鐢╯tartPos, endPos鏉ユ寚瀹氾級 + // (2) DownloadListener, 鐢变簬鏄绾跨▼涓嬭浇锛�璋冪敤杩欎釜绫荤殑瀹㈡埛绔笉鐭ラ亾浠�箞鏃跺�缁撴潫锛屾墍浠ヤ綘闇�瀹炵幇褰撴墍鏈� + // 绾跨▼閮芥墽琛屽畬浠ュ悗锛�璋冪敤listener鐨刵otifiedFinished鏂规硶锛�杩欐牱瀹㈡埛绔氨鑳芥敹鍒伴�鐭ャ� + // 鍏蜂綋鐨勫疄鐜版�璺細 + // 1. 闇�璋冪敤ConnectionManager鐨刼pen鏂规硶鎵撳紑杩炴帴锛�鐒跺悗閫氳繃Connection.getContentLength鏂规硶鑾峰緱鏂囦欢鐨勯暱搴� + // 2. 鑷冲皯鍚姩3涓嚎绋嬩笅杞斤紝 娉ㄦ剰姣忎釜绾跨▼闇�鍏堣皟鐢–onnectionManager鐨刼pen鏂规硶 + // 鐒跺悗璋冪敤read鏂规硶锛�read鏂规硶涓湁璇诲彇鏂囦欢鐨勫紑濮嬩綅缃拰缁撴潫浣嶇疆鐨勫弬鏁帮紝 杩斿洖鍊兼槸byte[]鏁扮粍 + // 3. 鎶奲yte鏁扮粍鍐欏叆鍒版枃浠朵腑 + // 4. 鎵�湁鐨勭嚎绋嬮兘涓嬭浇瀹屾垚浠ュ悗锛�闇�璋冪敤listener鐨刵otifiedFinished鏂规硶 + + // 涓嬮潰鐨勪唬鐮佹槸绀轰緥浠g爜锛�涔熷氨鏄鍙湁涓�釜绾跨▼锛�浣犻渶瑕佹敼閫犳垚澶氱嚎绋嬬殑銆� + Connection conn = null; + CyclicBarrier barr= new CyclicBarrier(MaxThreadNum,new Runnable(){ + public void run(){ + listener.notifyFinished(); + } + }); + try { + conn = cm.open(this.url); + int length = conn.getContentLength(); + // 鍦ㄨ繖閲屽垱寤哄嚭涓�釜鍚屾牱澶у皬鐨勭┖鏂囦欢锛�璺緞鏄痯ath + RandomAccessFile tarfile = new RandomAccessFile(path,"rw"); + tarfile.setLength(length); + tarfile.close(); + Thread[] threads = new Thread[4]; + threads[0] = new DownloadThread(barr,cm.open(this.url),0,length/4,path); + threads[1] = new DownloadThread(barr,cm.open(this.url),length/4,length/2,path); + threads[2] = new DownloadThread(barr,cm.open(this.url),length/2,3*length/4,path); + threads[3] = new DownloadThread(barr,cm.open(this.url),3*length/4,length,path); + for(int i=0;i<4;i++) + threads[i].start(); + } catch (ConnectionException | IOException 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; + } + public double getDownPercent(){ + return 0.0; + } +} diff --git a/group12/247565311/week3/FileDownloaderTest.java b/group12/247565311/week3_fileDownloader/FileDownloaderTest.java similarity index 74% rename from group12/247565311/week3/FileDownloaderTest.java rename to group12/247565311/week3_fileDownloader/FileDownloaderTest.java index 3c729218d3..3488fd5245 100644 --- a/group12/247565311/week3/FileDownloaderTest.java +++ b/group12/247565311/week3_fileDownloader/FileDownloaderTest.java @@ -1,12 +1,12 @@ -package week3; +package week3_fileDownloader; import org.junit.After; import org.junit.Before; import org.junit.Test; -import week3.api.ConnectionManager; -import week3.api.DownloadListener; -import week3.impl.ConnectionManagerImpl; +import week3_fileDownloader.api.ConnectionManager; +import week3_fileDownloader.api.DownloadListener; +import week3_fileDownloader.impl.ConnectionManagerImpl; public class FileDownloaderTest { boolean downloadFinished = false; @@ -38,13 +38,13 @@ public void notifyFinished() { } while (!downloadFinished) { try { - Thread.sleep(100);//休眠0.1秒 + Thread.sleep(100);//浼戠湢0.1绉� time += 1; } catch (InterruptedException e) { e.printStackTrace(); } } - System.out.println("下载完成!耗时:"+time/10.0+" 秒。"); + System.out.println("涓嬭浇瀹屾垚锛佽�鏃讹細"+time/10.0+" 绉掋�"); } } diff --git a/group12/247565311/week3_fileDownloader/api/Connection.java b/group12/247565311/week3_fileDownloader/api/Connection.java new file mode 100644 index 0000000000..5100870e1f --- /dev/null +++ b/group12/247565311/week3_fileDownloader/api/Connection.java @@ -0,0 +1,23 @@ +package week3_fileDownloader.api; + +import java.io.IOException; +import java.net.HttpURLConnection; + +public interface Connection{ + /** + * 缁欏畾寮�鍜岀粨鏉熶綅缃紝 璇诲彇鏁版嵁锛�杩斿洖鍊兼槸瀛楄妭鏁扮粍 + * @param startPos 寮�浣嶇疆锛�浠�寮� + * @param endPos 缁撴潫浣嶇疆 + * @return + */ + public byte[] read(int startPos,int endPos) throws IOException; + /** + * 寰楀埌鏁版嵁鍐呭鐨勯暱搴� * @return + */ + public int getContentLength(); + + /** + * 鍏抽棴杩炴帴 + */ + public void close(); +} diff --git a/group12/247565311/week3/api/ConnectionException.java b/group12/247565311/week3_fileDownloader/api/ConnectionException.java similarity index 73% rename from group12/247565311/week3/api/ConnectionException.java rename to group12/247565311/week3_fileDownloader/api/ConnectionException.java index 74ad30f40b..4a9cfd8aa6 100644 --- a/group12/247565311/week3/api/ConnectionException.java +++ b/group12/247565311/week3_fileDownloader/api/ConnectionException.java @@ -1,4 +1,4 @@ -package week3.api; +package week3_fileDownloader.api; public class ConnectionException extends Exception { private String exceptionstr = ""; diff --git a/group12/247565311/week3/api/ConnectionManager.java b/group12/247565311/week3_fileDownloader/api/ConnectionManager.java similarity index 61% rename from group12/247565311/week3/api/ConnectionManager.java rename to group12/247565311/week3_fileDownloader/api/ConnectionManager.java index 9b20c0177b..f917cde2e9 100644 --- a/group12/247565311/week3/api/ConnectionManager.java +++ b/group12/247565311/week3_fileDownloader/api/ConnectionManager.java @@ -1,8 +1,8 @@ -package week3.api; +package week3_fileDownloader.api; public interface ConnectionManager { /** - * 给定一个url , 打开一个连接 + * 缁欏畾涓�釜url , 鎵撳紑涓�釜杩炴帴 * @param url * @return */ diff --git a/group12/247565311/week3/api/DownloadListener.java b/group12/247565311/week3_fileDownloader/api/DownloadListener.java similarity index 67% rename from group12/247565311/week3/api/DownloadListener.java rename to group12/247565311/week3_fileDownloader/api/DownloadListener.java index da4eb7abc3..27fc35452f 100644 --- a/group12/247565311/week3/api/DownloadListener.java +++ b/group12/247565311/week3_fileDownloader/api/DownloadListener.java @@ -1,4 +1,4 @@ -package week3.api; +package week3_fileDownloader.api; public interface DownloadListener { public void notifyFinished(); diff --git a/group12/247565311/week3/impl/ConnectionImpl.java b/group12/247565311/week3_fileDownloader/impl/ConnectionImpl.java similarity index 95% rename from group12/247565311/week3/impl/ConnectionImpl.java rename to group12/247565311/week3_fileDownloader/impl/ConnectionImpl.java index 7173caf56d..78f393e07e 100644 --- a/group12/247565311/week3/impl/ConnectionImpl.java +++ b/group12/247565311/week3_fileDownloader/impl/ConnectionImpl.java @@ -1,4 +1,4 @@ -package week3.impl; +package week3_fileDownloader.impl; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -9,7 +9,7 @@ import java.net.URLConnection; import java.util.Arrays; -import week3.api.Connection; +import week3_fileDownloader.api.Connection; public class ConnectionImpl implements Connection{ URL url = null; diff --git a/group12/247565311/week3/impl/ConnectionManagerImpl.java b/group12/247565311/week3_fileDownloader/impl/ConnectionManagerImpl.java similarity index 64% rename from group12/247565311/week3/impl/ConnectionManagerImpl.java rename to group12/247565311/week3_fileDownloader/impl/ConnectionManagerImpl.java index b4a7cf381f..7aab7eb651 100644 --- a/group12/247565311/week3/impl/ConnectionManagerImpl.java +++ b/group12/247565311/week3_fileDownloader/impl/ConnectionManagerImpl.java @@ -1,12 +1,12 @@ -package week3.impl; +package week3_fileDownloader.impl; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; -import week3.api.Connection; -import week3.api.ConnectionException; -import week3.api.ConnectionManager; +import week3_fileDownloader.api.Connection; +import week3_fileDownloader.api.ConnectionException; +import week3_fileDownloader.api.ConnectionManager; public class ConnectionManagerImpl implements ConnectionManager { URL urllink = null; diff --git a/group12/247565311/week5/ClassFileLoaderTest.java b/group12/247565311/week5/ClassFileLoaderTest.java deleted file mode 100644 index 565203556a..0000000000 --- a/group12/247565311/week5/ClassFileLoaderTest.java +++ /dev/null @@ -1,72 +0,0 @@ -package week5; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class ClassFileLoaderTest { - static String path1 = "F:\\code_language\\demo\\Homework\\bin\\week5\\"; - 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 = "EmployeeV1"; - byte[] byteCodes = new byte[0]; - try { - byteCodes = loader.readBinaryCode(className); - } catch (Exception e) { - e.printStackTrace(); - } - // ע⣺ֽܺJVM汾йϵ Կõൽж - Assert.assertEquals(267, byteCodes.length); - } - - @Test - public void testMagicNumber(){ - ClassFileLoader loader = new ClassFileLoader(); - loader.addClassPath(path1); - String className = "EmployeeV1"; - byte[] byteCodes = new byte[0]; - try { - byteCodes = loader.readBinaryCode(className); - } catch (Exception e) { - e.printStackTrace(); - } - 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/group12/247565311/week567_miniJVM/attr/AttributeInfo.java b/group12/247565311/week567_miniJVM/attr/AttributeInfo.java new file mode 100644 index 0000000000..e97ebe0065 --- /dev/null +++ b/group12/247565311/week567_miniJVM/attr/AttributeInfo.java @@ -0,0 +1,24 @@ +package week567_miniJVM.attr; + + + + +public abstract class AttributeInfo { + public static final String CODE = "Code"; + public static final String CONST_VALUE = "ConstantValue"; + public static final String EXCEPTIONS = "Exceptions"; + public static final String LINE_NUM_TABLE = "LineNumberTable"; + public static final String LOCAL_VAR_TABLE = "LocalVariableTable"; + public static final String STACK_MAP_TABLE = "StackMapTable"; + int attrNameIndex; + int attrLen ; + public AttributeInfo(int attrNameIndex, int attrLen) { + + this.attrNameIndex = attrNameIndex; + this.attrLen = attrLen; + } + + +} + + diff --git a/group12/247565311/week567_miniJVM/attr/CodeAttr.java b/group12/247565311/week567_miniJVM/attr/CodeAttr.java new file mode 100644 index 0000000000..b32d6aada9 --- /dev/null +++ b/group12/247565311/week567_miniJVM/attr/CodeAttr.java @@ -0,0 +1,63 @@ + + + +package week567_miniJVM.attr; + +import week567_miniJVM.clz.ClassFile; +import week567_miniJVM.constant.ConstantPool; +import week567_miniJVM.loader.ByteCodeIterator; + + +public class CodeAttr extends AttributeInfo { + private int maxStack ; + private int maxLocals ; + private int codeLen ; + private String code; + public String getCode() { + return code; + } + + //private ByteCodeCommand[] cmds ; + //public ByteCodeCommand[] getCmds() { + // return cmds; + //} + private LineNumberTable lineNumTable; + private LocalVariableTable localVarTable; + private StackMapTable stackMapTable; + + public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen,String code /*ByteCodeCommand[] cmds*/) { + super(attrNameIndex, attrLen); + this.maxStack = maxStack; + this.maxLocals = maxLocals; + this.codeLen = codeLen; + this.code = code; + //this.cmds = cmds; + } + + public void setLineNumberTable(LineNumberTable t) { + this.lineNumTable = t; + } + + public void setLocalVariableTable(LocalVariableTable t) { + this.localVarTable = t; + } + + public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ + + + return null; + } + private void setStackMapTable(StackMapTable t) { + this.stackMapTable = t; + + } + + + + + +} + + + + diff --git a/group12/247565311/week567_miniJVM/attr/LineNumberTable.java b/group12/247565311/week567_miniJVM/attr/LineNumberTable.java new file mode 100644 index 0000000000..1160f1b274 --- /dev/null +++ b/group12/247565311/week567_miniJVM/attr/LineNumberTable.java @@ -0,0 +1,51 @@ + +package week567_miniJVM.attr; + +import java.util.ArrayList; +import java.util.List; + +import week567_miniJVM.loader.ByteCodeIterator; + +public class LineNumberTable extends AttributeInfo { + List<LineNumberItem> items = new ArrayList<LineNumberItem>(); + + private static class LineNumberItem{ + int startPC; + int lineNum; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLineNum() { + return lineNum; + } + public void setLineNum(int lineNum) { + this.lineNum = lineNum; + } + } + public void addLineNumberItem(LineNumberItem item){ + this.items.add(item); + } + public LineNumberTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + + } + + public static LineNumberTable parse(ByteCodeIterator iter){ + + return null; + } + + + +} + + + + + + + + diff --git a/group12/247565311/week567_miniJVM/attr/LocalVariableItem.java b/group12/247565311/week567_miniJVM/attr/LocalVariableItem.java new file mode 100644 index 0000000000..5ce8ad8810 --- /dev/null +++ b/group12/247565311/week567_miniJVM/attr/LocalVariableItem.java @@ -0,0 +1,47 @@ + +package week567_miniJVM.attr; + +public class LocalVariableItem { + private int startPC; + private int length; + private int nameIndex; + private int descIndex; + private int index; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getNameIndex() { + return nameIndex; + } + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + public int getDescIndex() { + return descIndex; + } + public void setDescIndex(int descIndex) { + this.descIndex = descIndex; + } + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } +} + + + + + + + diff --git a/group12/247565311/week567_miniJVM/attr/LocalVariableTable.java b/group12/247565311/week567_miniJVM/attr/LocalVariableTable.java new file mode 100644 index 0000000000..c8dbf11b70 --- /dev/null +++ b/group12/247565311/week567_miniJVM/attr/LocalVariableTable.java @@ -0,0 +1,37 @@ + + +package week567_miniJVM.attr; + + +import java.util.ArrayList; +import java.util.List; + +import week567_miniJVM.constant.ConstantPool; + +import week567_miniJVM.loader.ByteCodeIterator; + +public class LocalVariableTable extends AttributeInfo{ + + List<LocalVariableItem> items = new ArrayList<LocalVariableItem>(); + + public LocalVariableTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static LocalVariableTable parse(ByteCodeIterator iter){ + + return null; + } + private void addLocalVariableItem(LocalVariableItem item) { + this.items.add(item); + } + + +} + + + + + + + diff --git a/group12/247565311/week567_miniJVM/attr/StackMapTable.java b/group12/247565311/week567_miniJVM/attr/StackMapTable.java new file mode 100644 index 0000000000..c6b72f2655 --- /dev/null +++ b/group12/247565311/week567_miniJVM/attr/StackMapTable.java @@ -0,0 +1,44 @@ + +package week567_miniJVM.attr; + + +import week567_miniJVM.loader.ByteCodeIterator; + +public class StackMapTable extends AttributeInfo{ + + private String originalCode; + + public StackMapTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static StackMapTable parse(ByteCodeIterator iter){ + int index = iter.nextU2ToInt(); + int len = iter.nextU4ToInt(); + StackMapTable t = new StackMapTable(index,len); + + //鍚庨潰鐨凷tackMapTable澶繃澶嶆潅锛�涓嶅啀澶勭悊锛�鍙妸鍘熷鐨勪唬鐮佽杩涙潵淇濆瓨 + String code = iter.nextUxToHexString(len); + t.setOriginalCode(code); + + return t; + } + + private void setOriginalCode(String code) { + this.originalCode = code; + + } +} + + + + + + + + + + + + + diff --git a/group12/247565311/week6/clz/AccessFlag.java b/group12/247565311/week567_miniJVM/clz/AccessFlag.java similarity index 93% rename from group12/247565311/week6/clz/AccessFlag.java rename to group12/247565311/week567_miniJVM/clz/AccessFlag.java index e0296ad596..cb28fbe259 100644 --- a/group12/247565311/week6/clz/AccessFlag.java +++ b/group12/247565311/week567_miniJVM/clz/AccessFlag.java @@ -1,4 +1,4 @@ -package week6.clz; +package week567_miniJVM.clz; public class AccessFlag { private int flagValue; diff --git a/group12/247565311/week6/clz/ClassFile.java b/group12/247565311/week567_miniJVM/clz/ClassFile.java similarity index 82% rename from group12/247565311/week6/clz/ClassFile.java rename to group12/247565311/week567_miniJVM/clz/ClassFile.java index 3ee6f00701..91226364b8 100644 --- a/group12/247565311/week6/clz/ClassFile.java +++ b/group12/247565311/week567_miniJVM/clz/ClassFile.java @@ -1,7 +1,10 @@ -package week6.clz; +package week567_miniJVM.clz; -import week6.constant.ClassInfo; -import week6.constant.ConstantPool; +import week567_miniJVM.constant.ClassInfo; +import week567_miniJVM.constant.ConstantPool; +import week567_miniJVM.field.Field; +import week567_miniJVM.method.Method; +import structure.week1.ArrayList; public class ClassFile { @@ -72,4 +75,10 @@ private String getSuperClassName(){ ClassInfo superClass = (ClassInfo)this.getConstantPool().getConstantInfo(this.clzIndex.getSuperClassIndex()); return superClass.getClassName(); } + public ArrayList<Method> getMethods() { + return null; + } + public ArrayList<Field> getFields() { + return null; + } } diff --git a/group12/247565311/week6/clz/ClassIndex.java b/group12/247565311/week567_miniJVM/clz/ClassIndex.java similarity index 93% rename from group12/247565311/week6/clz/ClassIndex.java rename to group12/247565311/week567_miniJVM/clz/ClassIndex.java index 5bf00fcc13..77118cafa6 100644 --- a/group12/247565311/week6/clz/ClassIndex.java +++ b/group12/247565311/week567_miniJVM/clz/ClassIndex.java @@ -1,4 +1,4 @@ -package week6.clz; +package week567_miniJVM.clz; public class ClassIndex { private int thisClassIndex; diff --git a/group12/247565311/week6/constant/ClassInfo.java b/group12/247565311/week567_miniJVM/constant/ClassInfo.java similarity index 93% rename from group12/247565311/week6/constant/ClassInfo.java rename to group12/247565311/week567_miniJVM/constant/ClassInfo.java index 9320ae828c..77aa730b16 100644 --- a/group12/247565311/week6/constant/ClassInfo.java +++ b/group12/247565311/week567_miniJVM/constant/ClassInfo.java @@ -1,4 +1,4 @@ -package week6.constant; +package week567_miniJVM.constant; public class ClassInfo extends ConstantInfo { private int type = ConstantInfo.CLASS_INFO; diff --git a/group12/247565311/week6/constant/ConstantInfo.java b/group12/247565311/week567_miniJVM/constant/ConstantInfo.java similarity index 95% rename from group12/247565311/week6/constant/ConstantInfo.java rename to group12/247565311/week567_miniJVM/constant/ConstantInfo.java index 4eaebf241d..7277bd18c4 100644 --- a/group12/247565311/week6/constant/ConstantInfo.java +++ b/group12/247565311/week567_miniJVM/constant/ConstantInfo.java @@ -1,4 +1,4 @@ -package week6.constant; +package week567_miniJVM.constant; public abstract class ConstantInfo { public static final int UTF8_INFO = 1; diff --git a/group12/247565311/week6/constant/ConstantPool.java b/group12/247565311/week567_miniJVM/constant/ConstantPool.java similarity index 94% rename from group12/247565311/week6/constant/ConstantPool.java rename to group12/247565311/week567_miniJVM/constant/ConstantPool.java index 83c71e30a1..fb35f6c253 100644 --- a/group12/247565311/week6/constant/ConstantPool.java +++ b/group12/247565311/week567_miniJVM/constant/ConstantPool.java @@ -1,4 +1,4 @@ -package week6.constant; +package week567_miniJVM.constant; import java.util.ArrayList; import java.util.List; diff --git a/group12/247565311/week6/constant/FieldRefInfo.java b/group12/247565311/week567_miniJVM/constant/FieldRefInfo.java similarity index 97% rename from group12/247565311/week6/constant/FieldRefInfo.java rename to group12/247565311/week567_miniJVM/constant/FieldRefInfo.java index 0c96b0e537..20e7d91e67 100644 --- a/group12/247565311/week6/constant/FieldRefInfo.java +++ b/group12/247565311/week567_miniJVM/constant/FieldRefInfo.java @@ -1,4 +1,4 @@ -package week6.constant; +package week567_miniJVM.constant; public class FieldRefInfo extends ConstantInfo{ private int type = ConstantInfo.FIELD_INFO; diff --git a/group12/247565311/week6/constant/MethodRefInfo.java b/group12/247565311/week567_miniJVM/constant/MethodRefInfo.java similarity index 97% rename from group12/247565311/week6/constant/MethodRefInfo.java rename to group12/247565311/week567_miniJVM/constant/MethodRefInfo.java index 75a4efdc98..82b29c7446 100644 --- a/group12/247565311/week6/constant/MethodRefInfo.java +++ b/group12/247565311/week567_miniJVM/constant/MethodRefInfo.java @@ -1,4 +1,4 @@ -package week6.constant; +package week567_miniJVM.constant; public class MethodRefInfo extends ConstantInfo { diff --git a/group12/247565311/week6/constant/NameAndTypeInfo.java b/group12/247565311/week567_miniJVM/constant/NameAndTypeInfo.java similarity index 96% rename from group12/247565311/week6/constant/NameAndTypeInfo.java rename to group12/247565311/week567_miniJVM/constant/NameAndTypeInfo.java index 404571f46a..3a87554806 100644 --- a/group12/247565311/week6/constant/NameAndTypeInfo.java +++ b/group12/247565311/week567_miniJVM/constant/NameAndTypeInfo.java @@ -1,4 +1,4 @@ -package week6.constant; +package week567_miniJVM.constant; public class NameAndTypeInfo extends ConstantInfo{ public int type = ConstantInfo.NAME_AND_TYPE_INFO; diff --git a/group12/247565311/week6/constant/NullConstantInfo.java b/group12/247565311/week567_miniJVM/constant/NullConstantInfo.java similarity index 81% rename from group12/247565311/week6/constant/NullConstantInfo.java rename to group12/247565311/week567_miniJVM/constant/NullConstantInfo.java index d7453d52e4..1b9ed25aba 100644 --- a/group12/247565311/week6/constant/NullConstantInfo.java +++ b/group12/247565311/week567_miniJVM/constant/NullConstantInfo.java @@ -1,4 +1,4 @@ -package week6.constant; +package week567_miniJVM.constant; public class NullConstantInfo extends ConstantInfo { diff --git a/group12/247565311/week6/constant/StringInfo.java b/group12/247565311/week567_miniJVM/constant/StringInfo.java similarity index 92% rename from group12/247565311/week6/constant/StringInfo.java rename to group12/247565311/week567_miniJVM/constant/StringInfo.java index 90fbf14752..7a8e8da135 100644 --- a/group12/247565311/week6/constant/StringInfo.java +++ b/group12/247565311/week567_miniJVM/constant/StringInfo.java @@ -1,4 +1,4 @@ -package week6.constant; +package week567_miniJVM.constant; public class StringInfo extends ConstantInfo{ private int type = ConstantInfo.STRING_INFO; diff --git a/group12/247565311/week6/constant/UTF8Info.java b/group12/247565311/week567_miniJVM/constant/UTF8Info.java similarity index 94% rename from group12/247565311/week6/constant/UTF8Info.java rename to group12/247565311/week567_miniJVM/constant/UTF8Info.java index 23ce5c011d..ac2341bda9 100644 --- a/group12/247565311/week6/constant/UTF8Info.java +++ b/group12/247565311/week567_miniJVM/constant/UTF8Info.java @@ -1,4 +1,4 @@ -package week6.constant; +package week567_miniJVM.constant; public class UTF8Info extends ConstantInfo{ private int type = ConstantInfo.UTF8_INFO; diff --git a/group12/247565311/week567_miniJVM/field/Field.java b/group12/247565311/week567_miniJVM/field/Field.java new file mode 100644 index 0000000000..47eac5a308 --- /dev/null +++ b/group12/247565311/week567_miniJVM/field/Field.java @@ -0,0 +1,33 @@ +package week567_miniJVM.field; + +import week567_miniJVM.constant.ConstantPool; +import week567_miniJVM.constant.UTF8Info; +import week567_miniJVM.loader.ByteCodeIterator; + + +public class Field { + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + + + private ConstantPool pool; + + public Field( int accessFlag, int nameIndex, int descriptorIndex,ConstantPool pool) { + + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + this.pool = pool; + } + + + + + public static Field parse(ConstantPool pool,ByteCodeIterator iter){ + + return null; + } + +} \ No newline at end of file diff --git a/group12/247565311/week567_miniJVM/loader/ByteCodeIterator.java b/group12/247565311/week567_miniJVM/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..d38345b3fe --- /dev/null +++ b/group12/247565311/week567_miniJVM/loader/ByteCodeIterator.java @@ -0,0 +1,20 @@ +package week567_miniJVM.loader; + +public class ByteCodeIterator { + + public int nextU2ToInt() { + // TODO Զɵķ + return 0; + } + + public int nextU4ToInt() { + // TODO Զɵķ + return 0; + } + + public String nextUxToHexString(int len) { + // TODO Զɵķ + return null; + } + +} diff --git a/group12/247565311/week5/ClassFileLoader.java b/group12/247565311/week567_miniJVM/loader/ClassFileLoader.java similarity index 86% rename from group12/247565311/week5/ClassFileLoader.java rename to group12/247565311/week567_miniJVM/loader/ClassFileLoader.java index fc5e920f19..89c66a8197 100644 --- a/group12/247565311/week5/ClassFileLoader.java +++ b/group12/247565311/week567_miniJVM/loader/ClassFileLoader.java @@ -1,4 +1,4 @@ -package week5; +package week567_miniJVM.loader; import java.io.File; import java.io.FileInputStream; @@ -6,6 +6,9 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; + +import week567_miniJVM.clz.ClassFile; + public class ClassFileLoader { private List<String> clzPaths = new ArrayList<String>(); @@ -17,7 +20,9 @@ public byte[] readBinaryCode(String className) throws Exception { } return null; } - + public ClassFile loadClass(String className){ + return null; + } private byte[] loadClassFile(String clzFileName) throws Exception { File file = new File(clzFileName); long filelength = file.length(); @@ -40,15 +45,6 @@ public void addClassPath(String path) { clzPaths.add(path); } - public String getClassPath_V1(){ - String res = ""; - int size = clzPaths.size(); - for(int i=0;i<size-1;i++){ - res += clzPaths.get(i); - } - res += clzPaths.get(size-1); - return res; - } public String getClassPath(){ String res = ""; diff --git a/group12/247565311/week567_miniJVM/loader/ClassFileParser.java b/group12/247565311/week567_miniJVM/loader/ClassFileParser.java new file mode 100644 index 0000000000..5a23889b50 --- /dev/null +++ b/group12/247565311/week567_miniJVM/loader/ClassFileParser.java @@ -0,0 +1,44 @@ +package week567_miniJVM.loader; + +import java.io.UnsupportedEncodingException; + +import week567_miniJVM.clz.AccessFlag; +import week567_miniJVM.clz.ClassFile; +import week567_miniJVM.clz.ClassIndex; +import week567_miniJVM.constant.ClassInfo; +import week567_miniJVM.constant.ConstantPool; +import week567_miniJVM.constant.FieldRefInfo; +import week567_miniJVM.constant.MethodRefInfo; +import week567_miniJVM.constant.NameAndTypeInfo; +import week567_miniJVM.constant.NullConstantInfo; +import week567_miniJVM.constant.StringInfo; +import week567_miniJVM.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/group12/247565311/week567_miniJVM/method/Method.java b/group12/247565311/week567_miniJVM/method/Method.java new file mode 100644 index 0000000000..aadd29e9a6 --- /dev/null +++ b/group12/247565311/week567_miniJVM/method/Method.java @@ -0,0 +1,58 @@ +package week567_miniJVM.method; + +import week567_miniJVM.clz.ClassFile; +import week567_miniJVM.attr.AttributeInfo; +import week567_miniJVM.attr.CodeAttr; +import week567_miniJVM.constant.ConstantPool; +import week567_miniJVM.constant.UTF8Info; +import week567_miniJVM.loader.ByteCodeIterator; + + + +public class Method { + + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private CodeAttr codeAttr; + + private ClassFile clzFile; + + + public ClassFile getClzFile() { + return clzFile; + } + + public int getNameIndex() { + return nameIndex; + } + public int getDescriptorIndex() { + return descriptorIndex; + } + + public CodeAttr getCodeAttr() { + return codeAttr; + } + + public void setCodeAttr(CodeAttr code) { + this.codeAttr = code; + } + + public Method(ClassFile clzFile,int accessFlag, int nameIndex, int descriptorIndex) { + this.clzFile = clzFile; + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + } + + + + + + public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ + return null; + + } +} + diff --git a/group12/247565311/week6/test/ClassFileloaderTest.java b/group12/247565311/week567_miniJVM/test/ClassFileLoaderTest.java similarity index 52% rename from group12/247565311/week6/test/ClassFileloaderTest.java rename to group12/247565311/week567_miniJVM/test/ClassFileLoaderTest.java index 492c48475e..ed81eaa399 100644 --- a/group12/247565311/week6/test/ClassFileloaderTest.java +++ b/group12/247565311/week567_miniJVM/test/ClassFileLoaderTest.java @@ -1,36 +1,33 @@ -package week6.test; +package week567_miniJVM.test; + +import structure.week1.ArrayList; +import structure.week1.List; +import week567_miniJVM.clz.ClassFile; +import week567_miniJVM.clz.ClassIndex; +import week567_miniJVM.constant.ClassInfo; +import week567_miniJVM.constant.ConstantPool; +import week567_miniJVM.constant.MethodRefInfo; +import week567_miniJVM.constant.NameAndTypeInfo; +import week567_miniJVM.constant.UTF8Info; +import week567_miniJVM.field.Field; +import week567_miniJVM.loader.ClassFileLoader; +import week567_miniJVM.method.Method; import org.junit.After; -import org.junit.Assert; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import week6.clz.ClassFile; -import week6.clz.ClassIndex; -import week6.constant.ClassInfo; -import week6.constant.ConstantPool; -import week6.constant.MethodRefInfo; -import week6.constant.NameAndTypeInfo; -import week6.constant.UTF8Info; -import week6.loader.ClassFileLoader; - - - - - -public class ClassFileloaderTest { - - +public class ClassFileLoaderTest { private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; - - static String path1 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\mini-jvm\\bin"; + static String path1 = "F:\\code_language\\demo\\Homework\\bin\\week567_miniJVM\\test"; static String path2 = "C:\temp"; static ClassFile clzFile = null; static { ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); - String className = "week6.test.EmployeeV1"; + String className = "com.coderising.jvm.test.EmployeeV1"; clzFile = loader.loadClass(className); clzFile.print(); @@ -40,146 +37,115 @@ public class ClassFileloaderTest { @Before public void setUp() throws Exception { } - @After public void tearDown() throws Exception { } - @Test - public void testClassPath(){ - + 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() { - + public void testClassFileLength() { ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); - - String className = "week6.test.EmployeeV1"; - - byte[] byteCodes = loader.readBinaryCode(className); - - // 娉ㄦ剰锛氳繖涓瓧鑺傛暟鍙兘鍜屼綘鐨凧VM鐗堟湰鏈夊叧绯伙紝 浣犲彲浠ョ湅鐪嬬紪璇戝ソ鐨勭被鍒板簳鏈夊澶� - Assert.assertEquals(1056, byteCodes.length); - + String className = "EmployeeV1"; + byte[] byteCodes = new byte[0]; + try { + byteCodes = loader.readBinaryCode(className); + } catch (Exception e) { + e.printStackTrace(); + } + // 这里断言.class文件的字节数 + Assert.assertEquals(267, byteCodes.length); } - - @Test public void testMagicNumber(){ ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); - String className = "week6.test.EmployeeV1"; - byte[] byteCodes = loader.readBinaryCode(className); + String className = "EmployeeV1"; + byte[] byteCodes = new byte[0]; + try { + byteCodes = loader.readBinaryCode(className); + } catch (Exception e) { + e.printStackTrace(); + } 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(); - } - + 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(); + } /** - * ---------------------------------------------------------------------- - */ - - + * miniJVM第二次作业测试用例 + */ @Test - public void testVersion(){ - + 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("<init>", 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()); @@ -187,16 +153,74 @@ public void testConstantPool(){ } @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()); } - - - -} + /** + * miniJVM第三次作业测试用例 + */ + @Test + public void testReadFields(){ + ArrayList<Field> fields = clzFile.getFields(); + Assert.assertEquals(2, fields.size()); + { + Field f = fields.get(0); + Assert.assertEquals("name:Ljava/lang/String;", f.toString()); + } + { + Field f = fields.get(1); + Assert.assertEquals("age:I", f.toString()); + } + } + @Test + public void testMethods(){ + ArrayList<Method> methods = clzFile.getMethods(); + ConstantPool pool = clzFile.getConstantPool(); + { + Method m = methods.get(0); + assertMethodEquals(pool,m, + "<init>", + "(Ljava/lang/String;I)V", + "2ab7000c2a2bb5000f2a1cb50011b1"); + } + { + Method m = methods.get(1); + assertMethodEquals(pool,m, + "setName", + "(Ljava/lang/String;)V", + "2a2bb5000fb1"); + } + { + Method m = methods.get(2); + assertMethodEquals(pool,m, + "setAge", + "(I)V", + "2a1bb50011b1"); + } + { + Method m = methods.get(3); + assertMethodEquals(pool,m, + "sayHello", + "()V", + "b2001c1222b60024b1"); + } + { + Method m = methods.get(4); + assertMethodEquals(pool,m, + "main", + "([Ljava/lang/String;)V", + "bb000159122b101db7002d4c2bb6002fb1"); + } + } + private void assertMethodEquals(ConstantPool pool,Method m , String expectedName, String expectedDesc,String expectedCode){ + String methodName = pool.getUTF8String(m.getNameIndex()); + String methodDesc = pool.getUTF8String(m.getDescriptorIndex()); + String code = m.getCodeAttr().getCode(); + Assert.assertEquals(expectedName, methodName); + Assert.assertEquals(expectedDesc, methodDesc); + Assert.assertEquals(expectedCode, code); + } +} \ No newline at end of file diff --git a/group12/247565311/week5/EmployeeV1.java b/group12/247565311/week567_miniJVM/test/EmployeeV1.java similarity index 50% rename from group12/247565311/week5/EmployeeV1.java rename to group12/247565311/week567_miniJVM/test/EmployeeV1.java index 22949d2a0b..b9855461ae 100644 --- a/group12/247565311/week5/EmployeeV1.java +++ b/group12/247565311/week567_miniJVM/test/EmployeeV1.java @@ -1,4 +1,4 @@ -package week5; +package week567_miniJVM.test; public class EmployeeV1 { diff --git a/group12/247565311/week6/util/Util.java b/group12/247565311/week567_miniJVM/util/Util.java similarity index 94% rename from group12/247565311/week6/util/Util.java rename to group12/247565311/week567_miniJVM/util/Util.java index 7192b2473c..c10eaee6f2 100644 --- a/group12/247565311/week6/util/Util.java +++ b/group12/247565311/week567_miniJVM/util/Util.java @@ -1,4 +1,4 @@ -package week6.util; +package week567_miniJVM.util; public class Util { public static int byteToInt(byte[] codes){ diff --git a/group12/247565311/week6/loader/ByteCodeIterator.java b/group12/247565311/week6/loader/ByteCodeIterator.java deleted file mode 100644 index 3c5efed8e1..0000000000 --- a/group12/247565311/week6/loader/ByteCodeIterator.java +++ /dev/null @@ -1,5 +0,0 @@ -package week6.loader; - -public class ByteCodeIterator { - -} diff --git a/group12/247565311/week6/loader/ClassFileLoader.java b/group12/247565311/week6/loader/ClassFileLoader.java deleted file mode 100644 index 2963ed821c..0000000000 --- a/group12/247565311/week6/loader/ClassFileLoader.java +++ /dev/null @@ -1,136 +0,0 @@ -package week6.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 week6.clz.ClassFile; - -public class ClassFileLoader { - - private List<String> clzPaths = new ArrayList<String>(); - - 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/group12/247565311/week6/loader/ClassFileParser.java b/group12/247565311/week6/loader/ClassFileParser.java deleted file mode 100644 index 4062e68226..0000000000 --- a/group12/247565311/week6/loader/ClassFileParser.java +++ /dev/null @@ -1,44 +0,0 @@ -package week6.loader; - -import java.io.UnsupportedEncodingException; - -import week6.clz.AccessFlag; -import week6.clz.ClassFile; -import week6.clz.ClassIndex; -import week6.constant.ClassInfo; -import week6.constant.ConstantPool; -import week6.constant.FieldRefInfo; -import week6.constant.MethodRefInfo; -import week6.constant.NameAndTypeInfo; -import week6.constant.NullConstantInfo; -import week6.constant.StringInfo; -import week6.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/group12/247565311/week6/test/EmployeeV1.java b/group12/247565311/week6/test/EmployeeV1.java deleted file mode 100644 index ad2b054733..0000000000 --- a/group12/247565311/week6/test/EmployeeV1.java +++ /dev/null @@ -1,28 +0,0 @@ -package week6.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 e6fe32423e311f1737ee853c9af59c71eb71319a Mon Sep 17 00:00:00 2001 From: onlyliuxin <14703250@qq.com> Date: Wed, 12 Apr 2017 10:48:43 +0800 Subject: [PATCH 232/287] refactor --- .../src/com/coding/basic/stack/StackUtil.java | 35 +++++++++++++++++-- .../com/coding/basic/stack/StackUtilTest.java | 12 ++++++- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/liuxin/data-structure/src/com/coding/basic/stack/StackUtil.java b/liuxin/data-structure/src/com/coding/basic/stack/StackUtil.java index d4c496a2f9..7fb450d0a0 100644 --- a/liuxin/data-structure/src/com/coding/basic/stack/StackUtil.java +++ b/liuxin/data-structure/src/com/coding/basic/stack/StackUtil.java @@ -15,6 +15,29 @@ public static void bad_reverse(Stack<Integer> s) { } + + public static void reverse_247565311(Stack<Integer> s){ + if(s == null || s.isEmpty()) { + return; + } + + int size = s.size(); + Stack<Integer> tmpStack = new Stack<Integer>(); + + for(int i=0;i<size;i++){ + Integer top = s.pop(); + while(s.size()>i){ + tmpStack.push(s.pop()); + } + s.push(top); + while(tmpStack.size()>0){ + s.push(tmpStack.pop()); + } + } + } + + + /** * 假设栈中的元素是Integer, 从栈顶到栈底是 : 5,4,3,2,1 调用该方法后, 元素次序变为: 1,2,3,4,5 * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 @@ -23,9 +46,15 @@ public static void reverse(Stack<Integer> s) { if(s == null || s.isEmpty()){ return; } - Integer top = s.pop(); - reverse(s); - addToBottom(s,top); + + Stack<Integer> tmp = new Stack<Integer>(); + while(!s.isEmpty()){ + tmp.push(s.pop()); + } + while(!tmp.isEmpty()){ + Integer top = tmp.pop(); + addToBottom(s,top); + } } diff --git a/liuxin/data-structure/src/com/coding/basic/stack/StackUtilTest.java b/liuxin/data-structure/src/com/coding/basic/stack/StackUtilTest.java index 766c7eeb29..d0df46a052 100644 --- a/liuxin/data-structure/src/com/coding/basic/stack/StackUtilTest.java +++ b/liuxin/data-structure/src/com/coding/basic/stack/StackUtilTest.java @@ -42,7 +42,17 @@ public void testReverse() { StackUtil.reverse(s); Assert.assertEquals("[5, 4, 3, 2, 1]", s.toString()); } - + @Test + public void testReverse_247565311() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + + Assert.assertEquals("[1, 2, 3]", s.toString()); + StackUtil.reverse_247565311(s); + Assert.assertEquals("[3, 2, 1]", s.toString()); + } @Test public void testRemove() { Stack<Integer> s = new Stack(); From 452b338ecaab79be8185b7df3a1f3137bdb12d70 Mon Sep 17 00:00:00 2001 From: zheng <765324639@qq.com> Date: Wed, 12 Apr 2017 12:40:05 +0800 Subject: [PATCH 233/287] =?UTF-8?q?jvm=E7=AC=AC=E4=B8=89=E6=AC=A1=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A(=E5=B1=9E=E6=80=A7=E5=92=8C=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E9=83=A8=E5=88=86=E8=A7=A3=E6=9E=90)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/minijvm/attr/AttributeInfo.java | 19 +++ .../src/main/java/minijvm/attr/CodeAttr.java | 55 +++++++ .../java/minijvm/attr/LineNumberTable.java | 42 ++++++ .../java/minijvm/attr/LocalVariableItem.java | 39 +++++ .../java/minijvm/attr/LocalVariableTable.java | 26 ++++ .../main/java/minijvm/attr/StackMapTable.java | 30 ++++ .../src/main/java/minijvm/clz/ClassFile.java | 21 ++- .../src/main/java/minijvm/field/Field.java | 39 +++++ .../java/minijvm/loader/ByteCodeIterator.java | 18 +++ .../java/minijvm/loader/ClassFileParser.java | 140 +++++++++++++++++- .../src/main/java/minijvm/method/Method.java | 54 +++++++ .../minijvm/loader/ClassFileloaderTest.java | 75 ++++++++++ 12 files changed, 555 insertions(+), 3 deletions(-) create mode 100644 group01/765324639/src/main/java/minijvm/attr/AttributeInfo.java create mode 100644 group01/765324639/src/main/java/minijvm/attr/CodeAttr.java create mode 100644 group01/765324639/src/main/java/minijvm/attr/LineNumberTable.java create mode 100644 group01/765324639/src/main/java/minijvm/attr/LocalVariableItem.java create mode 100644 group01/765324639/src/main/java/minijvm/attr/LocalVariableTable.java create mode 100644 group01/765324639/src/main/java/minijvm/attr/StackMapTable.java create mode 100644 group01/765324639/src/main/java/minijvm/field/Field.java create mode 100644 group01/765324639/src/main/java/minijvm/method/Method.java diff --git a/group01/765324639/src/main/java/minijvm/attr/AttributeInfo.java b/group01/765324639/src/main/java/minijvm/attr/AttributeInfo.java new file mode 100644 index 0000000000..fc261d7eff --- /dev/null +++ b/group01/765324639/src/main/java/minijvm/attr/AttributeInfo.java @@ -0,0 +1,19 @@ +package minijvm.attr; + +public abstract class AttributeInfo { + public static final String CODE = "Code"; + public static final String CONST_VALUE = "ConstantValue"; + public static final String EXCEPTIONS = "Exceptions"; + public static final String LINE_NUM_TABLE = "LineNumberTable"; + public static final String LOCAL_VAR_TABLE = "LocalVariableTable"; + public static final String STACK_MAP_TABLE = "StackMapTable"; + int attrNameIndex; + int attrLen ; + public AttributeInfo(int attrNameIndex, int attrLen) { + + this.attrNameIndex = attrNameIndex; + this.attrLen = attrLen; + } + + +} diff --git a/group01/765324639/src/main/java/minijvm/attr/CodeAttr.java b/group01/765324639/src/main/java/minijvm/attr/CodeAttr.java new file mode 100644 index 0000000000..0044adced8 --- /dev/null +++ b/group01/765324639/src/main/java/minijvm/attr/CodeAttr.java @@ -0,0 +1,55 @@ +package minijvm.attr; + +import minijvm.clz.ClassFile; +import minijvm.loader.ByteCodeIterator; + + +public class CodeAttr extends AttributeInfo { + private int maxStack ; + private int maxLocals ; + private int codeLen ; + private String code; + public String getCode() { + return code; + } + + //private ByteCodeCommand[] cmds ; + //public ByteCodeCommand[] getCmds() { + // return cmds; + //} + private LineNumberTable lineNumTable; + private LocalVariableTable localVarTable; + private StackMapTable stackMapTable; + + public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen,String code /*ByteCodeCommand[] cmds*/) { + super(attrNameIndex, attrLen); + this.maxStack = maxStack; + this.maxLocals = maxLocals; + this.codeLen = codeLen; + this.code = code; + //this.cmds = cmds; + } + + public void setLineNumberTable(LineNumberTable t) { + this.lineNumTable = t; + } + + public void setLocalVariableTable(LocalVariableTable t) { + this.localVarTable = t; + } + + public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ + + + return null; + } + private void setStackMapTable(StackMapTable t) { + this.stackMapTable = t; + + } + + + + + +} diff --git a/group01/765324639/src/main/java/minijvm/attr/LineNumberTable.java b/group01/765324639/src/main/java/minijvm/attr/LineNumberTable.java new file mode 100644 index 0000000000..71a44fd83e --- /dev/null +++ b/group01/765324639/src/main/java/minijvm/attr/LineNumberTable.java @@ -0,0 +1,42 @@ +package minijvm.attr; + +import java.util.ArrayList; +import java.util.List; + +import minijvm.loader.ByteCodeIterator; + +public class LineNumberTable extends AttributeInfo { + List<LineNumberItem> items = new ArrayList<LineNumberItem>(); + + private static class LineNumberItem{ + int startPC; + int lineNum; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLineNum() { + return lineNum; + } + public void setLineNum(int lineNum) { + this.lineNum = lineNum; + } + } + public void addLineNumberItem(LineNumberItem item){ + this.items.add(item); + } + public LineNumberTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + + } + + public static LineNumberTable parse(ByteCodeIterator iter){ + + return null; + } + + + +} diff --git a/group01/765324639/src/main/java/minijvm/attr/LocalVariableItem.java b/group01/765324639/src/main/java/minijvm/attr/LocalVariableItem.java new file mode 100644 index 0000000000..7953b04d23 --- /dev/null +++ b/group01/765324639/src/main/java/minijvm/attr/LocalVariableItem.java @@ -0,0 +1,39 @@ +package minijvm.attr; + +public class LocalVariableItem { + private int startPC; + private int length; + private int nameIndex; + private int descIndex; + private int index; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getNameIndex() { + return nameIndex; + } + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + public int getDescIndex() { + return descIndex; + } + public void setDescIndex(int descIndex) { + this.descIndex = descIndex; + } + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } +} diff --git a/group01/765324639/src/main/java/minijvm/attr/LocalVariableTable.java b/group01/765324639/src/main/java/minijvm/attr/LocalVariableTable.java new file mode 100644 index 0000000000..90248d54f4 --- /dev/null +++ b/group01/765324639/src/main/java/minijvm/attr/LocalVariableTable.java @@ -0,0 +1,26 @@ +package minijvm.attr; + + +import java.util.ArrayList; +import java.util.List; + +import minijvm.loader.ByteCodeIterator; + +public class LocalVariableTable extends AttributeInfo{ + + List<LocalVariableItem> items = new ArrayList<LocalVariableItem>(); + + public LocalVariableTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static LocalVariableTable parse(ByteCodeIterator iter){ + + return null; + } + private void addLocalVariableItem(LocalVariableItem item) { + this.items.add(item); + } + + +} diff --git a/group01/765324639/src/main/java/minijvm/attr/StackMapTable.java b/group01/765324639/src/main/java/minijvm/attr/StackMapTable.java new file mode 100644 index 0000000000..7ed27a16a5 --- /dev/null +++ b/group01/765324639/src/main/java/minijvm/attr/StackMapTable.java @@ -0,0 +1,30 @@ +package minijvm.attr; + + +import minijvm.loader.ByteCodeIterator; + +public class StackMapTable extends AttributeInfo{ + + private String originalCode; + + public StackMapTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static StackMapTable parse(ByteCodeIterator iter){ + int index = iter.nextU2ToInt(); + int len = iter.nextU4ToInt(); + StackMapTable t = new StackMapTable(index,len); + + //后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 + String code = iter.nextUxToHexString(len); + t.setOriginalCode(code); + + return t; + } + + private void setOriginalCode(String code) { + this.originalCode = code; + + } +} diff --git a/group01/765324639/src/main/java/minijvm/clz/ClassFile.java b/group01/765324639/src/main/java/minijvm/clz/ClassFile.java index 36eddeb46d..d1cdbe0e05 100644 --- a/group01/765324639/src/main/java/minijvm/clz/ClassFile.java +++ b/group01/765324639/src/main/java/minijvm/clz/ClassFile.java @@ -1,7 +1,12 @@ package minijvm.clz; +import java.util.ArrayList; +import java.util.List; + import minijvm.constant.ClassInfo; import minijvm.constant.ConstantPool; +import minijvm.field.Field; +import minijvm.method.Method; public class ClassFile { @@ -11,7 +16,8 @@ public class ClassFile { private AccessFlag accessFlag; private ClassIndex clzIndex; private ConstantPool pool; - + private List<Field> fields = new ArrayList<Field>(); + private List<Method> methods = new ArrayList<Method>(); public ClassIndex getClzIndex() { return clzIndex; @@ -48,7 +54,18 @@ public void setClassIndex(ClassIndex clzIndex) { this.clzIndex = clzIndex; } - + public void addField(Field f){ + this.fields.add(f); + } + public List<Field> getFields(){ + return this.fields; + } + public void addMethod(Method m){ + this.methods.add(m); + } + public List<Method> getMethods() { + return methods; + } public void print(){ diff --git a/group01/765324639/src/main/java/minijvm/field/Field.java b/group01/765324639/src/main/java/minijvm/field/Field.java new file mode 100644 index 0000000000..85fded5380 --- /dev/null +++ b/group01/765324639/src/main/java/minijvm/field/Field.java @@ -0,0 +1,39 @@ +package minijvm.field; + +import minijvm.constant.ConstantPool; +import minijvm.constant.UTF8Info; +import minijvm.loader.ByteCodeIterator; + + +public class Field { + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + + + private ConstantPool pool; + + public Field( int accessFlag, int nameIndex, int descriptorIndex,ConstantPool pool) { + + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + this.pool = pool; + } + + + + + public static Field parse(ConstantPool pool,ByteCodeIterator iter){ + + return null; + } + + @Override + public String toString() { + String fieldName = ((UTF8Info)pool.getConstantInfo(nameIndex)).getValue(); + String fieldDescription = ((UTF8Info)pool.getConstantInfo(descriptorIndex)).getValue(); + return fieldName + ":" + fieldDescription; + } +} diff --git a/group01/765324639/src/main/java/minijvm/loader/ByteCodeIterator.java b/group01/765324639/src/main/java/minijvm/loader/ByteCodeIterator.java index 24a4db6f27..bcfbbace77 100644 --- a/group01/765324639/src/main/java/minijvm/loader/ByteCodeIterator.java +++ b/group01/765324639/src/main/java/minijvm/loader/ByteCodeIterator.java @@ -21,10 +21,22 @@ public int nextU1ToInt() { 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 nextUxToHexString(int length) { + byte[] src = new byte[length]; + for (int i = 0; i < length; i++) { + src[i] = codes[pos++]; + } + return Util.byteToHexString(src); + } public String nextLengthToString(int length) { String dest = null; @@ -36,6 +48,12 @@ public String nextLengthToString(int length) { return dest; } + public void back(int length) { + for (int i = 0; i < length; i++) { + pos--; + } + } + private byte[] getBytes(int length) { byte[] b = new byte[length]; for (int i = 0; i < length; i++) { diff --git a/group01/765324639/src/main/java/minijvm/loader/ClassFileParser.java b/group01/765324639/src/main/java/minijvm/loader/ClassFileParser.java index dc800a211f..cb42be22d6 100644 --- a/group01/765324639/src/main/java/minijvm/loader/ClassFileParser.java +++ b/group01/765324639/src/main/java/minijvm/loader/ClassFileParser.java @@ -1,5 +1,12 @@ package minijvm.loader; +import java.util.ArrayList; +import java.util.List; + +import minijvm.attr.AttributeInfo; +import minijvm.attr.CodeAttr; +import minijvm.attr.LineNumberTable; +import minijvm.attr.LocalVariableTable; import minijvm.clz.AccessFlag; import minijvm.clz.ClassFile; import minijvm.clz.ClassIndex; @@ -12,6 +19,8 @@ import minijvm.constant.NullConstantInfo; import minijvm.constant.StringInfo; import minijvm.constant.UTF8Info; +import minijvm.field.Field; +import minijvm.method.Method; public class ClassFileParser { @@ -33,10 +42,19 @@ public ClassFile parse(byte[] codes) { classFile.setAccessFlag(parseAccessFlag(iter)); classFile.setClassIndex(parseClassIndex(iter)); + // 目前没有处理接口 + parseInterfaces(iter); + + List<Field> fieldList = parseFields(iter, pool); + addFields(classFile, fieldList); + + List<Method> methodList = parseMethods(iter, classFile); + addMethods(classFile, methodList); + return classFile; } - private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { int flag = iter.nextU2ToInt(); AccessFlag accessFlag = new AccessFlag(flag); return accessFlag; @@ -115,5 +133,125 @@ private ConstantPool parseConstantPool(ByteCodeIterator iter) { return pool; } + private void parseInterfaces(ByteCodeIterator iter) { + int interfaceNum = iter.nextU2ToInt(); + if (interfaceNum != 0) { + throw new RuntimeException("有接口没有读取"); + } + } + + private List<Field> parseFields(ByteCodeIterator iter, ConstantPool pool) { + int filedNum = iter.nextU2ToInt(); + System.out.println("Field num: " + filedNum); + + List<Field> fieldList = new ArrayList<>(); + for (int i = 0; i < filedNum; i++) { + int accessFlag = iter.nextU2ToInt(); + int nameIndex = iter.nextU2ToInt(); + int descriptionIndex = iter.nextU2ToInt(); + int attributesCount = iter.nextU2ToInt(); + if (attributesCount != 0) { + throw new RuntimeException("字段的属性表没有处理"); + } + + fieldList.add(new Field(accessFlag, nameIndex, descriptionIndex, pool)); + } + + return fieldList; + } + + private void addFields(ClassFile classFile, List<Field> fieldList) { + for (Field field : fieldList) { + classFile.addField(field); + } + } + + private List<Method> parseMethods(ByteCodeIterator iter, ClassFile classFile) { + int methodNum = iter.nextU2ToInt(); + System.out.println("Methods num: " + methodNum); + + List<Method> methodList = new ArrayList<>(); + for (int i = 0; i < methodNum; i++) { + int accessFlag = iter.nextU2ToInt(); + int nameIndex = iter.nextU2ToInt(); + int descriptionIndex = iter.nextU2ToInt(); + + Method method = new Method(classFile, accessFlag, nameIndex, descriptionIndex); + + int attributesCount = iter.nextU2ToInt(); + for (int j = 0; j < attributesCount; j++) { + parseAttribute(iter, method, classFile); + } + + methodList.add(method); + } + return methodList; + } + + private void parseAttribute(ByteCodeIterator iter, Method method, ClassFile classFile) { + int nameIndex = iter.nextU2ToInt(); + int length = iter.nextU4ToInt(); + + if (AttributeInfo.CODE.equals(getUTF8ValueOfConstantPool(nameIndex, classFile))) { + CodeAttr codeAttr = parseCodeAttribute(iter, classFile); + method.setCodeAttr(codeAttr); + } else { + //TODO 目前没有处理除CODE外的其余属性 + iter.nextUxToHexString(length); + } + + } + + private CodeAttr parseCodeAttribute(ByteCodeIterator iter, ClassFile classFile) { + iter.back(6); // 因为之前验证类型时前进了6个字节,在此回退 + + int nameIndex = iter.nextU2ToInt(); + int length = iter.nextU4ToInt(); + int maxStack = iter.nextU2ToInt(); + int maxLocals = iter.nextU2ToInt(); + int codeLength = iter.nextU4ToInt(); + String code = iter.nextUxToHexString(codeLength); + + CodeAttr codeAttr = new CodeAttr(nameIndex, length, maxStack, maxLocals, codeLength, code); + + // TODO Code属性中的exception + int exceptionLength = iter.nextU2ToInt(); + if (exceptionLength != 0) { + throw new RuntimeException("Code属性中有异常字段没有处理"); + } + + // Code属性中的属性 + int attributesCount = iter.nextU2ToInt(); + for (int i = 0; i < attributesCount; i++) { + int attrNameIndex = iter.nextU2ToInt(); + int attrLength = iter.nextU4ToInt(); + + if (AttributeInfo.LINE_NUM_TABLE.equals(getUTF8ValueOfConstantPool(attrNameIndex, classFile))) { + LineNumberTable lineNumberTable = new LineNumberTable(attrNameIndex, attrLength); + codeAttr.setLineNumberTable(lineNumberTable); + iter.nextUxToHexString(attrLength); + } else if (AttributeInfo.LOCAL_VAR_TABLE.equals(getUTF8ValueOfConstantPool(attrNameIndex, classFile))) { + LocalVariableTable localVariableTable = new LocalVariableTable(attrNameIndex, attrLength); + codeAttr.setLocalVariableTable(localVariableTable); + iter.nextUxToHexString(attrLength); + } else { + String msg = "此属性:" + getUTF8ValueOfConstantPool(attrNameIndex, classFile) + "还没有处理"; + throw new RuntimeException(msg); + } + } + + return codeAttr; + } + + private void addMethods(ClassFile classFile, List<Method> methodList) { + for (Method method : methodList) { + classFile.addMethod(method); + } + } + + private String getUTF8ValueOfConstantPool(int index, ClassFile classFile) { + ConstantPool constantPool = classFile.getConstantPool(); + return constantPool.getUTF8String(index); + } } diff --git a/group01/765324639/src/main/java/minijvm/method/Method.java b/group01/765324639/src/main/java/minijvm/method/Method.java new file mode 100644 index 0000000000..3d0b9a5678 --- /dev/null +++ b/group01/765324639/src/main/java/minijvm/method/Method.java @@ -0,0 +1,54 @@ +package minijvm.method; + +import minijvm.attr.CodeAttr; +import minijvm.clz.ClassFile; +import minijvm.loader.ByteCodeIterator; + + + +public class Method { + + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private CodeAttr codeAttr; + + private ClassFile clzFile; + + + public ClassFile getClzFile() { + return clzFile; + } + + public int getNameIndex() { + return nameIndex; + } + public int getDescriptorIndex() { + return descriptorIndex; + } + + public CodeAttr getCodeAttr() { + return codeAttr; + } + + public void setCodeAttr(CodeAttr code) { + this.codeAttr = code; + } + + public Method(ClassFile clzFile,int accessFlag, int nameIndex, int descriptorIndex) { + this.clzFile = clzFile; + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + } + + + + + + public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ + return null; + + } +} diff --git a/group01/765324639/src/test/java/minijvm/loader/ClassFileloaderTest.java b/group01/765324639/src/test/java/minijvm/loader/ClassFileloaderTest.java index bc93fc112a..80586f51e2 100644 --- a/group01/765324639/src/test/java/minijvm/loader/ClassFileloaderTest.java +++ b/group01/765324639/src/test/java/minijvm/loader/ClassFileloaderTest.java @@ -1,6 +1,7 @@ package minijvm.loader; import java.io.File; +import java.util.List; import org.junit.After; import org.junit.Assert; @@ -14,6 +15,8 @@ import minijvm.constant.MethodRefInfo; import minijvm.constant.NameAndTypeInfo; import minijvm.constant.UTF8Info; +import minijvm.field.Field; +import minijvm.method.Method; @@ -195,5 +198,77 @@ public void testClassIndex(){ Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); } + + /** + * 下面是第三次JVM课应实现的测试用例 + */ + @Test + public void testReadFields(){ + + List<Field> fields = clzFile.getFields(); + Assert.assertEquals(2, fields.size()); + { + Field f = fields.get(0); + Assert.assertEquals("name:Ljava/lang/String;", f.toString()); + } + { + Field f = fields.get(1); + Assert.assertEquals("age:I", f.toString()); + } + } + @Test + public void testMethods(){ + + List<Method> methods = clzFile.getMethods(); + ConstantPool pool = clzFile.getConstantPool(); + + { + Method m = methods.get(0); + assertMethodEquals(pool,m, + "<init>", + "(Ljava/lang/String;I)V", + "2ab7000c2a2bb5000f2a1cb50011b1"); + + } + { + Method m = methods.get(1); + assertMethodEquals(pool,m, + "setName", + "(Ljava/lang/String;)V", + "2a2bb5000fb1"); + + } + { + Method m = methods.get(2); + assertMethodEquals(pool,m, + "setAge", + "(I)V", + "2a1bb50011b1"); + } + { + Method m = methods.get(3); + assertMethodEquals(pool,m, + "sayHello", + "()V", + "b2001c1222b60024b1"); + + } + { + Method m = methods.get(4); + assertMethodEquals(pool,m, + "main", + "([Ljava/lang/String;)V", + "bb000159122b101db7002d4c2bb6002fb1"); + } + } + + private void assertMethodEquals(ConstantPool pool,Method m , String expectedName, String expectedDesc,String expectedCode){ + String methodName = pool.getUTF8String(m.getNameIndex()); + String methodDesc = pool.getUTF8String(m.getDescriptorIndex()); + String code = m.getCodeAttr().getCode(); + Assert.assertEquals(expectedName, methodName); + Assert.assertEquals(expectedDesc, methodDesc); + Assert.assertEquals(expectedCode, code); + } } From d8fe97e589c148970258dc3a032ad62c24ad1541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BE=9A=E5=90=AF=E7=9B=BC?= <gongqipan@qipeipu.com> Date: Wed, 12 Apr 2017 15:23:35 +0800 Subject: [PATCH 234/287] jvm second --- .../java/com/pan/basic/BinaryTreeNode.java | 32 ++ .../src/main/java/com/pan/basic/Iterator.java | 7 + .../src/main/java/com/pan/basic/List.java | 9 + .../src/main/java/com/pan/basic/Queue.java | 19 ++ .../java/com/pan/linklist/LRUPageFrame.java | 133 +++++++++ .../main/java/com/pan/stack/StackUtil.java | 141 +++++++++ .../java/com/pan/week01/base/Iterator.java | 12 - .../main/java/com/pan/week02/ArrayUtil.java | 282 ------------------ group11/252308879/mini-jvm/pom.xml | 7 +- .../src/main/java/com/pan/alg/StackUtil.java | 141 +++++++++ .../src/main/java/com/pan/jvm/EmployeeV1.java | 1 - .../main/java/com/pan/jvm/clz/ClassFile.java | 30 +- .../com/pan/jvm/loader/ByteCodeIterator.java | 95 +++--- .../com/pan/jvm/loader/ClassFileParser.java | 121 +++++++- .../test/java/com/pan/alg/StackUtilTest.java | 78 +++++ ...aderTest.java => ClassFileLoaderTest.java} | 210 +++++++------ 16 files changed, 843 insertions(+), 475 deletions(-) create mode 100644 group11/252308879/data-structure/src/main/java/com/pan/basic/BinaryTreeNode.java create mode 100644 group11/252308879/data-structure/src/main/java/com/pan/basic/Iterator.java create mode 100644 group11/252308879/data-structure/src/main/java/com/pan/basic/List.java create mode 100644 group11/252308879/data-structure/src/main/java/com/pan/basic/Queue.java create mode 100644 group11/252308879/data-structure/src/main/java/com/pan/linklist/LRUPageFrame.java create mode 100644 group11/252308879/data-structure/src/main/java/com/pan/stack/StackUtil.java delete mode 100644 group11/252308879/data-structure/src/main/java/com/pan/week01/base/Iterator.java delete mode 100644 group11/252308879/data-structure/src/main/java/com/pan/week02/ArrayUtil.java create mode 100644 group11/252308879/mini-jvm/src/main/java/com/pan/alg/StackUtil.java create mode 100644 group11/252308879/mini-jvm/src/test/java/com/pan/alg/StackUtilTest.java rename group11/252308879/mini-jvm/src/test/java/com/pan/jvm/{ClassFileloaderTest.java => ClassFileLoaderTest.java} (50%) diff --git a/group11/252308879/data-structure/src/main/java/com/pan/basic/BinaryTreeNode.java b/group11/252308879/data-structure/src/main/java/com/pan/basic/BinaryTreeNode.java new file mode 100644 index 0000000000..aab398a9b6 --- /dev/null +++ b/group11/252308879/data-structure/src/main/java/com/pan/basic/BinaryTreeNode.java @@ -0,0 +1,32 @@ +package com.pan.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; + } + + public BinaryTreeNode insert(Object o){ + return null; + } + +} diff --git a/group11/252308879/data-structure/src/main/java/com/pan/basic/Iterator.java b/group11/252308879/data-structure/src/main/java/com/pan/basic/Iterator.java new file mode 100644 index 0000000000..70735fa34e --- /dev/null +++ b/group11/252308879/data-structure/src/main/java/com/pan/basic/Iterator.java @@ -0,0 +1,7 @@ +package com.pan.basic; + +public interface Iterator { + public boolean hasNext(); + public Object next(); + +} diff --git a/group11/252308879/data-structure/src/main/java/com/pan/basic/List.java b/group11/252308879/data-structure/src/main/java/com/pan/basic/List.java new file mode 100644 index 0000000000..8ac9cf8e2e --- /dev/null +++ b/group11/252308879/data-structure/src/main/java/com/pan/basic/List.java @@ -0,0 +1,9 @@ +package com.pan.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/252308879/data-structure/src/main/java/com/pan/basic/Queue.java b/group11/252308879/data-structure/src/main/java/com/pan/basic/Queue.java new file mode 100644 index 0000000000..874d8a5690 --- /dev/null +++ b/group11/252308879/data-structure/src/main/java/com/pan/basic/Queue.java @@ -0,0 +1,19 @@ +package com.pan.basic; + +public class Queue { + + public void enQueue(Object o){ + } + + public Object deQueue(){ + return null; + } + + public boolean isEmpty(){ + return false; + } + + public int size(){ + return -1; + } +} diff --git a/group11/252308879/data-structure/src/main/java/com/pan/linklist/LRUPageFrame.java b/group11/252308879/data-structure/src/main/java/com/pan/linklist/LRUPageFrame.java new file mode 100644 index 0000000000..5208e5bc76 --- /dev/null +++ b/group11/252308879/data-structure/src/main/java/com/pan/linklist/LRUPageFrame.java @@ -0,0 +1,133 @@ +package com.pan.linklist; + + +/* + * 用双向链表实现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/252308879/data-structure/src/main/java/com/pan/stack/StackUtil.java b/group11/252308879/data-structure/src/main/java/com/pan/stack/StackUtil.java new file mode 100644 index 0000000000..b4056e830a --- /dev/null +++ b/group11/252308879/data-structure/src/main/java/com/pan/stack/StackUtil.java @@ -0,0 +1,141 @@ +package com.pan.stack; + + +import java.util.Stack; + +/** + * Created by QiPan on 2017/4/12. + */ +public class StackUtil { + + public static void bad_reverse(Stack<Integer> s) { + if(s == null || s.isEmpty()){ + return; + } + Stack<Integer> tmpStack = new Stack(); + while(!s.isEmpty()){ + tmpStack.push(s.pop()); + } + + s = tmpStack; + + } + + /** + * 假设栈中的元素是Integer, 从栈顶到栈底是 : 5,4,3,2,1 调用该方法后, 元素次序变为: 1,2,3,4,5 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + */ + public static void reverse(Stack<Integer> s) { + if(s == null || s.isEmpty()){ + return; + } + Integer top = s.pop(); + reverse(s); + addToBottom(s,top); + + + } + public static void addToBottom(Stack<Integer> s, Integer value){ + if(s.isEmpty()){ + s.push(value); + } else{ + Integer top = s.pop(); + addToBottom(s,value); + s.push(top); + } + + } + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s,Object o) { + if(s == null || s.isEmpty()){ + return; + } + Stack tmpStack = new Stack(); + + while(!s.isEmpty()){ + Object value = s.pop(); + if(!value.equals(o)){ + tmpStack.push(value); + } + } + + while(!tmpStack.isEmpty()){ + s.push(tmpStack.pop()); + } + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * @param len + * @return + */ + public static Object[] getTop(Stack s,int len) { + + if(s == null || s.isEmpty() || s.size()<len || len <=0 ){ + return null; + } + + Stack tmpStack = new Stack(); + int i = 0; + Object[] result = new Object[len]; + while(!s.isEmpty()){ + Object value = s.pop(); + tmpStack.push(value); + result[i++] = value; + if(i == len){ + break; + } + } + + 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<Character> stack = new Stack(); + for(int i=0;i<s.length();i++){ + char c = s.charAt(i); + + if(c == '(' || c =='[' || c == '{'){ + + stack.push(c); + + } else if( c == ')'){ + + char topChar = stack.pop(); + if(topChar != '('){ + return false; + } + + } else if( c == ']'){ + + char topChar = stack.pop(); + if(topChar != '['){ + return false; + } + + } else if( c == '}'){ + + char topChar = stack.pop(); + if(topChar != '{'){ + return false; + } + + } + } + return stack.size() == 0; + } + +} diff --git a/group11/252308879/data-structure/src/main/java/com/pan/week01/base/Iterator.java b/group11/252308879/data-structure/src/main/java/com/pan/week01/base/Iterator.java deleted file mode 100644 index 2f4317524e..0000000000 --- a/group11/252308879/data-structure/src/main/java/com/pan/week01/base/Iterator.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.pan.week01.base; - -/** - * Created by QiPan on 2017/2/23. - */ -public interface Iterator { - boolean hasNext(); - - Object next(); - - void remove(); -} diff --git a/group11/252308879/data-structure/src/main/java/com/pan/week02/ArrayUtil.java b/group11/252308879/data-structure/src/main/java/com/pan/week02/ArrayUtil.java deleted file mode 100644 index e835e31269..0000000000 --- a/group11/252308879/data-structure/src/main/java/com/pan/week02/ArrayUtil.java +++ /dev/null @@ -1,282 +0,0 @@ -package com.pan.week02; - -import java.util.Arrays; - -/** - * Created by QiPan on 2017/2/27. - */ -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) { - - // 如果是null, 或者长度小于等于1, 直接返回 - if (origin == null || origin.length <= 1) { - return; - } - for (int i = 0; i < origin.length / 2; i++) { - int tmp = origin[i]; - origin[i] = origin[origin.length - 1 - i]; - origin[origin.length - 1 - i] = tmp; - } - } - - /** - * 现在有如下的一个数组: 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 oldArray; - } - int[] newArray = null; - int count = 0; //统计被移出的数组的个数 - for (int i = 0; i < oldArray.length; i++) { - int num = oldArray[i]; - if (num == 0) { - count++; - System.arraycopy(oldArray, i + 1, oldArray, i, oldArray.length - i - 1); - i--; - } - } - if (count == 0) { - newArray = oldArray; - } else { - newArray = new int[oldArray.length - count]; - System.arraycopy(oldArray, 0, newArray, 0, oldArray.length - count); - } - return newArray; - } - - /** - * 不用JavaAPI来做 - * - * @param oldArray - * @return - */ - public static int[] removeZero_2(int[] oldArray) { - - if (oldArray == null) { - return oldArray; - } - int count = 0; - for (int num : oldArray) { - if (num == 0) { - count++; - } - } - int[] newArray = new int[oldArray.length - count]; - for (int i = 0, j = 0; i < oldArray.length; i++, j++) { - int num = oldArray[i]; - if (num == 0) { - j--; - } else { - newArray[j] = num; - } - } - 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) { - //先初始化一个array3,但不是最后返回的数组 - int[] array3 = new int[array1.length + array2.length]; - int i = 0, j = 0; - int array3Size = 0; // 统计实际上合并数组后的大小 - while (i < array1.length && j < array2.length) { - if (array1[i] < array2[j]) {// 如果array1中元素小,则插入到array3中 - array3[array3Size++] = array1[i]; - ++i; - } else if (array1[i] > array2[j]) {//如果array2中元素小,则插入到array3中 - array3[array3Size++] = array2[j]; - ++j; - } else {//否则随便插入一个,但是计数要同时加1 - array3[array3Size++] = array1[i]; - ++i; - ++j; - } - } - - if (i == array1.length) { //如果array1中全部循环完毕了,那么需要去处理array2中剩余的元素 - for (int n = j; n < array2.length; n++) { - array3[array3Size++] = array2[n]; - } - } else if (j == array2.length) {// 如果array2中全部循环完毕,那么需要去处理array1中剩余的元素 - for (int n = i; n < array1.length; n++) { - array3[array3Size++] = array1[n]; - } - } - int[] returnResultArray = new int[array3Size]; - System.arraycopy(array3, 0, returnResultArray, 0, - array3Size); - return returnResultArray; - } - - /** - * 把一个已经存满数据的数组 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 (oldArray == null) { - oldArray = new int[size]; - } - oldArray = Arrays.copyOf(oldArray, oldArray.length + size); - return oldArray; - } - - /** - * 斐波那契数列为: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]; - } - int[] arrays = new int[max / 2]; - int firstNum = 1; //第一个数字 - int secondNum = 1; // 第二个数字 - int arraySize = 0; - arrays[arraySize++] = 1; // 初始化第一位 - while (secondNum < max) { - arrays[arraySize++] = secondNum; - int tmpNum = secondNum; // 保存第二个数,得会需要付给第一个数 - secondNum = firstNum + secondNum; // 为前两个数之和 - firstNum = tmpNum; // 第一个数,后移 - } - return Arrays.copyOf(arrays, arraySize); - } - - /** - * 返回小于给定最大值max的所有素数数组 - * 例如max = 23, 返回的数组为[2,3,5,7,11,13,17,19] - * - * @param max - * @return - */ - public static int[] getPrimes(int max) { - int[] returnResultArray = new int[max + 1]; - int arraySize = 0; - for (int i = 2; i < max; i++) { - if (isPrime(i)) { - returnResultArray[arraySize++] = i; - } - - } - if (arraySize == returnResultArray.length) { - return returnResultArray; - } - return Arrays.copyOf(returnResultArray, arraySize); - } - - private static boolean isPrime(final int number) { - if (number < 2) { - return false; - } - // 因为不可能将一个数除与所有小于它的数字,只要检查到N的平方根就好了。 - // 但直接开根号还有个精度的问题。这个可能会产生误差。 索性将判断条件写成 i*i<=number - for (int i = 2; i * i <= number; i++) { - if (number % i == 0) {//查看所有小于number平方根的数,能够被整除 - return false; - } - } - // 如果一个都没有,那么就是素数 - return true; - } - - /** - * 所谓“完数”, 是指这个数恰好等于它的因子之和,例如6=1+2+3 - * 给定一个最大值max, 返回一个数组, 数组中是小于max 的所有完数 - * - * @param max - * @return - */ - public static int[] getPerfectNumbers(int max) { - int[] array = new int[max]; - int arraySize = 0; - for (int n = 0; n < max; n++) { - int fac,// 被除的因子 - sum,// 用来统计因子之和 - num;// 除数的因子,中间变量 - for (sum = 1, num = n, fac = 2; fac < num; fac++) { - - if (n % fac == 0) {// 如果余数为0,那么说明有因子 - sum += fac; // 统计因子和 - num = n / fac; // num=等于除数的最大因子 - if (num == fac) // 如果最大和最小相等跳出循环 - break; - sum += num; // 再统计因子 - } - } - - if (sum == n) { //因子和与整数相等,那么就是一个完美数 - if (n != 1) { - System.out.println(n + "是一个完全数,其因子为:"); - } - for (fac = 1; fac < n; fac++) { - if (n % fac == 0) {// 列出所有的因子 - System.out.print(fac + " "); - } - } - System.out.println(); - array[arraySize++] = n; // 放到数组中 - } - } - return Arrays.copyOf(array, arraySize); - } - - /** - * 用seperator 把数组 array给连接起来 - * 例如array= [3,8,9], seperator = "-" - * 则返回值为"3-8-9" - * - * @param array - * @param seperator - * @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]); - continue; - } - str.append(array[i]).append(seperator); - } - return str.toString(); - } - -} diff --git a/group11/252308879/mini-jvm/pom.xml b/group11/252308879/mini-jvm/pom.xml index 9487a16199..a1421f550e 100644 --- a/group11/252308879/mini-jvm/pom.xml +++ b/group11/252308879/mini-jvm/pom.xml @@ -21,11 +21,16 @@ </properties> <dependencies> + <dependency> + <groupId>com.pan</groupId> + <artifactId>data-structure</artifactId> + <version>1.0.0-SNAPSHOT</version> + </dependency> + <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> - <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/alg/StackUtil.java b/group11/252308879/mini-jvm/src/main/java/com/pan/alg/StackUtil.java new file mode 100644 index 0000000000..1c7e0a5d0e --- /dev/null +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/alg/StackUtil.java @@ -0,0 +1,141 @@ +package com.pan.alg; + + +import java.util.Stack; + +/** + * Created by QiPan on 2017/4/12. + */ +public class StackUtil { + + public static void bad_reverse(Stack<Integer> s) { + if(s == null || s.isEmpty()){ + return; + } + Stack<Integer> tmpStack = new Stack(); + while(!s.isEmpty()){ + tmpStack.push(s.pop()); + } + + s = tmpStack; + + } + + /** + * 假设栈中的元素是Integer, 从栈顶到栈底是 : 5,4,3,2,1 调用该方法后, 元素次序变为: 1,2,3,4,5 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + */ + public static void reverse(Stack<Integer> s) { + if(s == null || s.isEmpty()){ + return; + } + Integer top = s.pop(); + reverse(s); + addToBottom(s,top); + + + } + public static void addToBottom(Stack<Integer> s, Integer value){ + if(s.isEmpty()){ + s.push(value); + } else{ + Integer top = s.pop(); + addToBottom(s,value); + s.push(top); + } + + } + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s,Object o) { + if(s == null || s.isEmpty()){ + return; + } + Stack tmpStack = new Stack(); + + while(!s.isEmpty()){ + Object value = s.pop(); + if(!value.equals(o)){ + tmpStack.push(value); + } + } + + while(!tmpStack.isEmpty()){ + s.push(tmpStack.pop()); + } + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * @param len + * @return + */ + public static Object[] getTop(Stack s,int len) { + + if(s == null || s.isEmpty() || s.size()<len || len <=0 ){ + return null; + } + + Stack tmpStack = new Stack(); + int i = 0; + Object[] result = new Object[len]; + while(!s.isEmpty()){ + Object value = s.pop(); + tmpStack.push(value); + result[i++] = value; + if(i == len){ + break; + } + } + + 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<Character> stack = new Stack(); + for(int i=0;i<s.length();i++){ + char c = s.charAt(i); + + if(c == '(' || c =='[' || c == '{'){ + + stack.push(c); + + } else if( c == ')'){ + + char topChar = stack.pop(); + if(topChar != '('){ + return false; + } + + } else if( c == ']'){ + + char topChar = stack.pop(); + if(topChar != '['){ + return false; + } + + } else if( c == '}'){ + + char topChar = stack.pop(); + if(topChar != '{'){ + return false; + } + + } + } + return stack.size() == 0; + } + +} diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/EmployeeV1.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/EmployeeV1.java index 92b5b403ca..71f9ff54a4 100644 --- a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/EmployeeV1.java +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/EmployeeV1.java @@ -2,7 +2,6 @@ public class EmployeeV1 { - private String name; private int age; diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/ClassFile.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/ClassFile.java index 2b3a185ac6..e632888d89 100644 --- a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/ClassFile.java +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/clz/ClassFile.java @@ -9,16 +9,16 @@ import com.pan.jvm.method.Method; public class ClassFile { - + private int minorVersion; private int majorVersion; - + private AccessFlag accessFlag; private ClassIndex clzIndex; private ConstantPool pool; private List<Field> fields = new ArrayList<Field>(); private List<Method> methods = new ArrayList<Method>(); - + public ClassIndex getClzIndex() { return clzIndex; } @@ -28,10 +28,10 @@ public AccessFlag getAccessFlag() { public void setAccessFlag(AccessFlag accessFlag) { this.accessFlag = accessFlag; } - - - - public ConstantPool getConstantPool() { + + + + public ConstantPool getConstantPool() { return pool; } public int getMinorVersion() { @@ -48,12 +48,12 @@ public void setMajorVersion(int majorVersion) { } public void setConstPool(ConstantPool pool) { this.pool = pool; - + } public void setClassIndex(ClassIndex clzIndex) { - this.clzIndex = clzIndex; + this.clzIndex = clzIndex; } - + public void addField(Field f){ this.fields.add(f); } @@ -66,20 +66,16 @@ public void addMethod(Method m){ public List<Method> getMethods() { return methods; } - - + + 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); diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ByteCodeIterator.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ByteCodeIterator.java index c0f9a6eaa5..24f00ccc5d 100644 --- a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ByteCodeIterator.java +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ByteCodeIterator.java @@ -4,54 +4,49 @@ import com.pan.jvm.util.Util; -public class ByteCodeIterator { - byte[] codes; - int pos = 0; - - ByteCodeIterator(byte[] codes) { - this.codes = codes; - } - - - - 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; - } - - 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 nextUxToHexString(int len) { - byte[] tmp = new byte[len]; - - for (int i = 0; i < len; i++) { - tmp[i] = codes[pos++]; - } - return Util.byteToHexString(tmp).toLowerCase(); - - } - - public void back(int n) { - this.pos -= n; - } +public class ByteCodeIterator { + byte[] codes; + int pos = 0; + + ByteCodeIterator(byte[] codes) { + this.codes = codes; + } + + 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; + } + + 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 nextUxToHexString(int len) { + byte[] tmp = new byte[len]; + + for (int i = 0; i < len; i++) { + tmp[i] = codes[pos++]; + } + return Util.byteToHexString(tmp).toLowerCase(); + } + + public void back(int n) { + this.pos -= n; + } } diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileParser.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileParser.java index d2ba152e05..7ab096b4f5 100644 --- a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileParser.java +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileParser.java @@ -3,30 +3,139 @@ import com.pan.jvm.clz.AccessFlag; import com.pan.jvm.clz.ClassFile; import com.pan.jvm.clz.ClassIndex; -import com.pan.jvm.constant.ConstantPool; +import com.pan.jvm.constant.*; + +import java.io.UnsupportedEncodingException; public class ClassFileParser { public ClassFile parse(byte[] codes) { + ByteCodeIterator iterator = new ByteCodeIterator(codes); + String magicNumber = iterator.nextU4ToHexString(); + if (!"cafebabe".equals(magicNumber)) {// 验证是否为Java的.class文件 + return null; + } + ClassFile classFile = new ClassFile(); + classFile.setMinorVersion(iterator.nextU2ToInt()); + classFile.setMajorVersion(iterator.nextU2ToInt()); + + ConstantPool constantPool = parseConstantPool(iterator); + classFile.setConstPool(constantPool); + + AccessFlag flag = parseAccessFlag(iterator); + classFile.setAccessFlag(flag); - return null; + // this clz 和 supper clz + ClassIndex clzIndex = parseClassIndex(iterator); + classFile.setClassIndex(clzIndex); + + parseInterfaces(iterator); + return classFile; } private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + AccessFlag accessFlag = new AccessFlag(iter.nextU2ToInt()); + return accessFlag; + } - return null; + private ClassIndex parseClassIndex(ByteCodeIterator iter) { + + int thisClassIndex = iter.nextU2ToInt(); + int supperClassIndex = iter.nextU2ToInt(); + + ClassIndex classIndex = new ClassIndex(); + classIndex.setThisClassIndex(thisClassIndex); + classIndex.setSuperClassIndex(supperClassIndex); + return classIndex; } - private ClassIndex parseClassInfex(ByteCodeIterator iter) { + private void parseInterfaces(ByteCodeIterator iter) { + int interfaceCount = iter.nextU2ToInt(); - return null; + System.out.println("interfaceCount:" + interfaceCount); + // TODO : 如果实现了interface, 这里需要解析 } + /** + * 解析常量池 + * + * @param iter + * @return + */ private ConstantPool parseConstantPool(ByteCodeIterator iter) { - return null; + int constPoolCount = iter.nextU2ToInt(); + + System.out.println("Constant Pool Count :" + constPoolCount); + ConstantPool pool = new ConstantPool(); + // 因为常量池中的信息是从 1 开始的,但是数组或者List 下标是从0开始,所以设置第一个为空的常量 + pool.addConstantInfo(new NullConstantInfo()); + + for (int i = 1; i <= constPoolCount - 1; i++) { + + // 获取标识符信息 + int tag = iter.nextU1toInt(); + + switch (tag) { + + case 7: //CONSTANT_Class + int utf8Index = iter.nextU2ToInt(); + ClassInfo classInfo = new ClassInfo(pool); + classInfo.setUtf8Index(utf8Index); + + pool.addConstantInfo(classInfo); + break; + case 9: // CONSTANT_Fieldref + FieldRefInfo fieldRefInfo = new FieldRefInfo(pool); + fieldRefInfo.setClassInfoIndex(iter.nextU2ToInt()); + fieldRefInfo.setNameAndTypeIndex(iter.nextU2ToInt()); + + pool.addConstantInfo(fieldRefInfo); + break; + case 10: // CONSTANT_Methodref + MethodRefInfo methodRefInfo = new MethodRefInfo(pool); + methodRefInfo.setClassInfoIndex(iter.nextU2ToInt()); + methodRefInfo.setNameAndTypeIndex(iter.nextU2ToInt()); + + pool.addConstantInfo(methodRefInfo); + break; + case 8: + StringInfo info = new StringInfo(pool); + info.setIndex(iter.nextU2ToInt()); + pool.addConstantInfo(info); + break; + case 12: // CONSTANT_NameAndType + NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(pool); + nameAndTypeInfo.setIndex1(iter.nextU2ToInt()); + nameAndTypeInfo.setIndex2(iter.nextU2ToInt()); + + pool.addConstantInfo(nameAndTypeInfo); + break; + case 1: // CONSTANT_Utf8 + int length = iter.nextU2ToInt(); + byte[] data = iter.getBytes(length); + String value = null; + try { + value = new String(data, "utf-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + UTF8Info utf8Str = new UTF8Info(pool); + utf8Str.setLength(length); + utf8Str.setValue(value); + + pool.addConstantInfo(utf8Str); + break; + default: + throw new RuntimeException("the constant pool tag " + tag + " has not been implemented yet."); + + } + } + System.out.println("Finished reading Constant pool "); + return pool; } diff --git a/group11/252308879/mini-jvm/src/test/java/com/pan/alg/StackUtilTest.java b/group11/252308879/mini-jvm/src/test/java/com/pan/alg/StackUtilTest.java new file mode 100644 index 0000000000..f94a01b2d7 --- /dev/null +++ b/group11/252308879/mini-jvm/src/test/java/com/pan/alg/StackUtilTest.java @@ -0,0 +1,78 @@ +package com.pan.alg; + +import static org.junit.Assert.fail; + +import java.util.Stack; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +public class StackUtilTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testAddToBottom() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + + StackUtil.addToBottom(s, 0); + + Assert.assertEquals("[0, 1, 2, 3]", s.toString()); + + } + @Test + public void testReverse() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + Assert.assertEquals("[1, 2, 3, 4, 5]", s.toString()); + StackUtil.reverse(s); + Assert.assertEquals("[5, 4, 3, 2, 1]", s.toString()); + } + + @Test + public void testRemove() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + StackUtil.remove(s, 2); + Assert.assertEquals("[1, 3]", s.toString()); + } + + @Test + public void testGetTop() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + { + Object[] values = StackUtil.getTop(s, 3); + Assert.assertEquals(5, values[0]); + Assert.assertEquals(4, values[1]); + Assert.assertEquals(3, values[2]); + } + } + + @Test + public void testIsValidPairs() { + Assert.assertTrue(StackUtil.isValidPairs("([e{d}f])")); + Assert.assertFalse(StackUtil.isValidPairs("([b{x]y})")); + } + +} diff --git a/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/ClassFileloaderTest.java b/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/ClassFileLoaderTest.java similarity index 50% rename from group11/252308879/mini-jvm/src/test/java/com/pan/jvm/ClassFileloaderTest.java rename to group11/252308879/mini-jvm/src/test/java/com/pan/jvm/ClassFileLoaderTest.java index 4bcb38e917..2aed2e5e44 100644 --- a/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/ClassFileloaderTest.java +++ b/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/ClassFileLoaderTest.java @@ -19,28 +19,28 @@ -public class ClassFileloaderTest { +public class ClassFileLoaderTest { - private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + private static final String FULL_QUALIFIED_CLASS_NAME = "com/pan/jvm/EmployeeV1"; static String path1 = EmployeeV1.class.getClassLoader().getResource("").getPath() .replace("test-classes", "classes"); - static String path2 = "C:\temp"; - -// static ClassFile clzFile = null; -// static { -// ClassFileLoader loader = new ClassFileLoader(); -// loader.addClassPath(path1); -// String className = "com.pan.jvm.EmployeeV1"; -// -// clzFile = loader.loadClass(className); -// clzFile.print(); -// } - + static String path2 = "C:/temp"; + static ClassFile clzFile = null; + static { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "com.pan.jvm.EmployeeV1"; + + clzFile = loader.loadClass(className); + clzFile.print(); + } + + @Before - public void setUp() throws Exception { + public void setUp() throws Exception { } @After @@ -85,104 +85,102 @@ public void testMagicNumber(){ byte[] codes = new byte[]{byteCodes[0],byteCodes[1],byteCodes[2],byteCodes[3]}; - String acctualValue = Util.byteToHexString(codes); + String actualValue = Util.byteToHexString(codes); - Assert.assertEquals("cafebabe", acctualValue); + Assert.assertEquals("cafebabe", actualValue); } /** * ---------------------------------------------------------------------- */ -// -// -// @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("<init>", 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()); -// } + + + @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("<init>", 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()); + } // // /** // * 下面是第三次JVM课应实现的测试用例 From e3c83ee067a95c320bbcecea2eddb8eed393fb03 Mon Sep 17 00:00:00 2001 From: 592146505 <592146505@qq.com> Date: Wed, 12 Apr 2017 17:13:48 +0800 Subject: [PATCH 235/287] =?UTF-8?q?=E5=B8=B8=E9=87=8F=E6=B1=A0=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=E5=AE=8C=E6=88=90=EF=BC=8CstackUtil=E5=8C=B9=E9=85=8D?= =?UTF-8?q?=E6=8B=AC=E5=8F=B7=E6=9C=AA=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/org/wsc/coding/basic/stack/Stack.java | 80 +++++++++-- .../org/wsc/coding/basic/stack/StackUtil.java | 90 +++++++++++++ .../wsc/coding/basic/stack/StackUtilTest.java | 77 +++++++++++ .../wsc/coderising/jvm/clz/AccessFlag.java | 42 ++++++ .../org/wsc/coderising/jvm/clz/ClassFile.java | 81 +++++++++++ .../wsc/coderising/jvm/clz/ClassIndex.java | 32 +++++ .../coderising/jvm/constant/ClassInfo.java | 37 +++++ .../coderising/jvm/constant/ConstantInfo.java | 46 +++++++ .../coderising/jvm/constant/ConstantPool.java | 38 ++++++ .../coderising/jvm/constant/FieldRefInfo.java | 67 +++++++++ .../jvm/constant/MethodRefInfo.java | 65 +++++++++ .../jvm/constant/NameAndTypeInfo.java | 57 ++++++++ .../jvm/constant/NullConstantInfo.java | 22 +++ .../coderising/jvm/constant/StringInfo.java | 35 +++++ .../wsc/coderising/jvm/constant/UTF8Info.java | 45 +++++++ .../jvm/loader/ByteCodeIterator.java | 59 ++++++++ .../jvm/loader/ClassFileLoader.java | 22 ++- .../jvm/loader/ClassFileParser.java | 107 +++++++++++++++ .../jvm/test/ClassFileloaderTest.java | 127 +++++++++++++++++- .../src/org/wsc/coderising/jvm/util/Util.java | 22 +++ 20 files changed, 1127 insertions(+), 24 deletions(-) create mode 100644 group20/592146505/data-structure/src/org/wsc/coding/basic/stack/StackUtil.java create mode 100644 group20/592146505/data-structure/src/org/wsc/coding/basic/stack/StackUtilTest.java create mode 100644 group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/clz/AccessFlag.java create mode 100644 group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/clz/ClassFile.java create mode 100644 group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/clz/ClassIndex.java create mode 100644 group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/ClassInfo.java create mode 100644 group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/ConstantInfo.java create mode 100644 group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/ConstantPool.java create mode 100644 group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/FieldRefInfo.java create mode 100644 group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/MethodRefInfo.java create mode 100644 group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/NameAndTypeInfo.java create mode 100644 group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/NullConstantInfo.java create mode 100644 group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/StringInfo.java create mode 100644 group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/UTF8Info.java create mode 100644 group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/loader/ByteCodeIterator.java create mode 100644 group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/loader/ClassFileParser.java create mode 100644 group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/util/Util.java diff --git a/group20/592146505/data-structure/src/org/wsc/coding/basic/stack/Stack.java b/group20/592146505/data-structure/src/org/wsc/coding/basic/stack/Stack.java index 09f83c98b6..b72a46008a 100644 --- a/group20/592146505/data-structure/src/org/wsc/coding/basic/stack/Stack.java +++ b/group20/592146505/data-structure/src/org/wsc/coding/basic/stack/Stack.java @@ -2,23 +2,75 @@ import org.wsc.coding.basic.list.ArrayList; -public class Stack { - private ArrayList elementData = new ArrayList(); - - public void push(Object o){ +/** + * 栈 + * + * @author Administrator + * @date 2017年4月7日下午3:06:06 + * @version v1.0 + * + * @param <E> + */ +public class Stack<E> { + private ArrayList<E> elementData = new ArrayList<E>(); + + /** + * 将元素压入栈顶 + * + * @param e + */ + public void push(E e) { + elementData.add(e); } - - public Object pop(){ - return null; + + /** + * 弹出栈顶元素 + * + * @return + */ + public E pop() { + return elementData.remove(elementData.size() - 1); } - - public Object peek(){ - return null; + + /** + * 观察栈顶元素 + * + * @return + */ + public E peek() { + return elementData.get(elementData.size() - 1); } - public boolean isEmpty(){ - return false; + + /** + * 是否为空 + * + * @return + */ + public boolean isEmpty() { + return elementData.isEmpty(); + } + + /** + * 栈深度 + * + * @return + */ + public int size() { + return elementData.size(); } - public int size(){ - return -1; + + @Override + public String toString() { + StringBuffer str = new StringBuffer(); + str.append("["); + for (int i = 0; i < elementData.size(); i++) { + str.append(elementData.get(i)); + if(i < elementData.size()-1) + str.append(", "); + } + str.append("]"); + return str.toString(); } + + } diff --git a/group20/592146505/data-structure/src/org/wsc/coding/basic/stack/StackUtil.java b/group20/592146505/data-structure/src/org/wsc/coding/basic/stack/StackUtil.java new file mode 100644 index 0000000000..1ced8606bd --- /dev/null +++ b/group20/592146505/data-structure/src/org/wsc/coding/basic/stack/StackUtil.java @@ -0,0 +1,90 @@ +package org.wsc.coding.basic.stack; + +/** + * @author Administrator + * @date 2017年4月10日下午4:55:34 + * @version v1.0 + * + */ +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()){ + Object top = s.pop(); + reverse(s); + toTop(s,top); + } + + } + private static void toTop(Stack s,Object t){ + if(s.isEmpty()){ + s.push(t); + return; + } + Object top = s.pop(); + toTop(s,t); + s.push(top); + } + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s, Object o) { + //递归 + if (!s.isEmpty()) { + Object ob = s.pop(); + remove(s,o); + if(ob !=o) + s.push(ob); + } + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param len + * @return + */ + public static Object[] getTop(Stack s, int len) { + Object[] tops = new Object[len]; + getTop(s,len,tops); + return tops; + } + + private static void getTop(Stack s, int len,Object[] tops) { + //递归 + if (!s.isEmpty()&&len>0) { + Object ob = s.pop(); + getTop(s,--len,tops); + tops[tops.length-1-len] = ob; + s.push(ob); + } + } + + /** + * 字符串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[] chars = s.toCharArray(); + Stack<Character> stack = new Stack<Character>(); + for (int i = 0; i > chars.length; i++) { + stack.push(chars[i]); + } + + return false; + } + +} diff --git a/group20/592146505/data-structure/src/org/wsc/coding/basic/stack/StackUtilTest.java b/group20/592146505/data-structure/src/org/wsc/coding/basic/stack/StackUtilTest.java new file mode 100644 index 0000000000..d4e508ad2f --- /dev/null +++ b/group20/592146505/data-structure/src/org/wsc/coding/basic/stack/StackUtilTest.java @@ -0,0 +1,77 @@ +package org.wsc.coding.basic.stack; + +import static org.junit.Assert.*; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class StackUtilTest { + + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + +// @Test +// public void testAddToBottom() { +// Stack<Integer> s = new Stack(); +// s.push(1); +// s.push(2); +// s.push(3); +// +// StackUtil.addToBottom(s, 0); +// +// Assert.assertEquals("[0, 1, 2, 3]", s.toString()); +// +// } + @Test + public void testReverse() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + Assert.assertEquals("[1, 2, 3, 4, 5]", s.toString()); + StackUtil.reverse(s); + Assert.assertEquals("[5, 4, 3, 2, 1]", s.toString()); + } + + @Test + public void testRemove() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + StackUtil.remove(s, 2); + Assert.assertEquals("[1, 3]", s.toString()); + } + + @Test + public void testGetTop() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + { + Object[] values = StackUtil.getTop(s, 3); + Assert.assertEquals(5, values[0]); + Assert.assertEquals(4, values[1]); + Assert.assertEquals(3, values[2]); + } + } + + @Test + public void testIsValidPairs() { + Assert.assertTrue(StackUtil.isValidPairs("([e{d}f])")); + Assert.assertFalse(StackUtil.isValidPairs("([b{x]y})")); + } +} diff --git a/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/clz/AccessFlag.java b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..27b7e219f6 --- /dev/null +++ b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/clz/AccessFlag.java @@ -0,0 +1,42 @@ +package org.wsc.coderising.jvm.clz; + +/** + * + * 访问标志 + * @author Administrator + * @date 2017年4月9日下午2:24:21 + * @version v1.0 + * + */ +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 + * @return + */ + public boolean isPublicClass() { + return (this.flagValue & 0x0001) != 0; + } + + /** + * 是final + * @return + */ + public boolean isFinalClass() { + return (this.flagValue & 0x0010) != 0; + } +} diff --git a/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/clz/ClassFile.java b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..8684930f96 --- /dev/null +++ b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/clz/ClassFile.java @@ -0,0 +1,81 @@ +package org.wsc.coderising.jvm.clz; + +import org.wsc.coderising.jvm.constant.ClassInfo; +import org.wsc.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/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/clz/ClassIndex.java b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..153cacd76d --- /dev/null +++ b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/clz/ClassIndex.java @@ -0,0 +1,32 @@ +package org.wsc.coderising.jvm.clz; + +/** + * + * 类及父类索引 + * @author Administrator + * @date 2017年4月9日下午2:39:45 + * @version v1.0 + * + */ +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/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/ClassInfo.java b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..1976fa4d14 --- /dev/null +++ b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/ClassInfo.java @@ -0,0 +1,37 @@ +package org.wsc.coderising.jvm.constant; + +/** + * + * 类描述符 + * @author Administrator + * @date 2017年4月9日下午2:45:38 + * @version v1.0 + * + */ +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/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/ConstantInfo.java b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..236e058d7d --- /dev/null +++ b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/ConstantInfo.java @@ -0,0 +1,46 @@ +package org.wsc.coderising.jvm.constant; + +/** + * + * 描述符 + * @author Administrator + * @date 2017年4月9日下午2:46:19 + * @version v1.0 + * + */ +public abstract class ConstantInfo { + /** UTF-8编码的字符串 */ + 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/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/ConstantPool.java b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..69ef091503 --- /dev/null +++ b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/ConstantPool.java @@ -0,0 +1,38 @@ +package org.wsc.coderising.jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * 常量池 + * @author Administrator + * @date 2017年4月9日下午2:53:16 + * @version v1.0 + * + */ +public class ConstantPool { + private List<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + 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/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/FieldRefInfo.java b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..b4066363e5 --- /dev/null +++ b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/FieldRefInfo.java @@ -0,0 +1,67 @@ +package org.wsc.coderising.jvm.constant; + +/** + * + * 字段描述符 + * @author Administrator + * @date 2017年4月9日下午2:53:27 + * @version v1.0 + * + */ +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/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/MethodRefInfo.java b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..f7e298cac1 --- /dev/null +++ b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/MethodRefInfo.java @@ -0,0 +1,65 @@ +package org.wsc.coderising.jvm.constant; + +/** + * + * 类中方法描述符 + * @author Administrator + * @date 2017年4月9日下午2:53:39 + * @version v1.0 + * + */ +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/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/NameAndTypeInfo.java b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..24cde05109 --- /dev/null +++ b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,57 @@ +package org.wsc.coderising.jvm.constant; + +/** + * + * 字段或方法部分描述符 + * @author Administrator + * @date 2017年4月9日下午2:53:59 + * @version v1.0 + * + */ +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/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/NullConstantInfo.java b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..0772bc0eb6 --- /dev/null +++ b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/NullConstantInfo.java @@ -0,0 +1,22 @@ +package org.wsc.coderising.jvm.constant; + +/** + * + * 空描述符 + * @author Administrator + * @date 2017年4月9日下午2:54:21 + * @version v1.0 + * + */ +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo() { + + } + + @Override + public int getType() { + return -1; + } + +} diff --git a/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/StringInfo.java b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..69f36a300f --- /dev/null +++ b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/StringInfo.java @@ -0,0 +1,35 @@ +package org.wsc.coderising.jvm.constant; + +/** + * + * 字符串描述符 + * @author Administrator + * @date 2017年4月9日下午2:54:31 + * @version v1.0 + * + */ +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/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/UTF8Info.java b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..b2ae869de8 --- /dev/null +++ b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/constant/UTF8Info.java @@ -0,0 +1,45 @@ +package org.wsc.coderising.jvm.constant; + +/** + * + * utf-8编码的字符串 + * @author Administrator + * @date 2017年4月9日下午2:54:41 + * @version v1.0 + * + */ +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/592146505/mini-jvm/src/org/wsc/coderising/jvm/loader/ByteCodeIterator.java b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..431ea1b891 --- /dev/null +++ b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,59 @@ +package org.wsc.coderising.jvm.loader; + +import java.util.ConcurrentModificationException; + +import org.wsc.coderising.jvm.util.Util; + +/** + * + * 字节迭代器 + * @author Administrator + * @date 2017年4月12日下午1:16:39 + * @version v1.0 + * + */ +public class ByteCodeIterator{ + + private byte[] codes; + + private int cursor=0; + + ByteCodeIterator(byte[] byteCodes) { + super(); + this.codes = byteCodes; + } + + public boolean hasNext() { + return cursor != codes.length; + } + + public byte next() { + if(cursor > codes.length) + throw new ConcurrentModificationException(); + return codes[cursor++]; + } + + public byte[] getBytes(int count) { + byte[] bytes = new byte[count]; + for (int i = 0; i < count; i++) { + bytes[i] = next(); + } + return bytes; + } + + public int nextU1ToInt(){ + return Util.byteToInt(getBytes(1)); + } + + public int nextU2ToInt(){ + return Util.byteToInt(getBytes(2)); + } + + public int nextU4ToInt(){ + return Util.byteToInt(getBytes(4)); + } + + public String nextU4ToHexString(){ + return Util.byteToHexString(getBytes(4)); + } +} 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 index 6732cf28c7..ed5bfb4149 100644 --- 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 @@ -8,6 +8,8 @@ import java.util.ArrayList; import java.util.List; +import org.wsc.coderising.jvm.clz.ClassFile; + public class ClassFileLoader { private List<String> clzPaths = new ArrayList<String>(); @@ -16,19 +18,25 @@ public class ClassFileLoader { DataInputStream dis; private ByteArrayOutputStream baos; - public byte[] readBinaryCode(String className) throws ClassNotFoundException, IOException { + public byte[] readBinaryCode(String className) throws ClassNotFoundException { 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)); + try { + buffer = getFileToByte(new File(clzPath)); + if(buffer != null && buffer.length > 0) + break; + } catch (IOException e) { + throw new ClassNotFoundException(); + } close(); } - if (buffer == null) { + + if (buffer == null || buffer.length == 0) throw new ClassNotFoundException(); - } return buffer; } @@ -58,6 +66,12 @@ private byte[] getFileToByte(File file) throws IOException { } return baos.toByteArray(); } + + public ClassFile loadClass(String className) throws ClassNotFoundException { + byte[] codes = this.readBinaryCode(className); + ClassFileParser parser = new ClassFileParser(); + return parser.parse(codes); + } private void close() { try { diff --git a/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/loader/ClassFileParser.java b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..13a99b1a63 --- /dev/null +++ b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/loader/ClassFileParser.java @@ -0,0 +1,107 @@ +package org.wsc.coderising.jvm.loader; + +import java.io.UnsupportedEncodingException; + +import org.wsc.coderising.jvm.clz.AccessFlag; +import org.wsc.coderising.jvm.clz.ClassFile; +import org.wsc.coderising.jvm.clz.ClassIndex; +import org.wsc.coderising.jvm.constant.ClassInfo; +import org.wsc.coderising.jvm.constant.ConstantPool; +import org.wsc.coderising.jvm.constant.FieldRefInfo; +import org.wsc.coderising.jvm.constant.MethodRefInfo; +import org.wsc.coderising.jvm.constant.NameAndTypeInfo; +import org.wsc.coderising.jvm.constant.NullConstantInfo; +import org.wsc.coderising.jvm.constant.StringInfo; +import org.wsc.coderising.jvm.constant.UTF8Info; + +public class ClassFileParser { + + public ClassFile parse(byte[] codes) { + ClassFile classFile = new ClassFile(); + ByteCodeIterator iter = new ByteCodeIterator(codes); + String magicNumber = iter.nextU4ToHexString(); + if (!"cafebabe".equals(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) { + return new AccessFlag(iter.nextU2ToInt()); + } + + private ClassIndex parseClassIndex(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(); + System.out.println("constant pool count:" + constantPoolCount); + // 常量池 + ConstantPool pool = new ConstantPool(); + pool.addConstantInfo(new NullConstantInfo());// 常量池索引从1开始 + for (int i = 1; i < constantPoolCount; i++) { + int tag = iter.nextU1ToInt(); + switch (tag) { + case 1://UTF-8 String + int length = iter.nextU2ToInt(); + String utf8Str = null; + try { + utf8Str = new String(iter.getBytes(length),"UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + UTF8Info utf8Info = new UTF8Info(pool); + utf8Info.setValue(utf8Str); + utf8Info.setLength(length); + pool.addConstantInfo(utf8Info); + break; + case 7://类或接口的符号引用 + ClassInfo classInfo = new ClassInfo(pool); + classInfo.setUtf8Index(iter.nextU2ToInt()); + pool.addConstantInfo(classInfo); + break; + case 8://字符串类型字面量 + StringInfo stringInfo = new StringInfo(pool); + stringInfo.setIndex(iter.nextU2ToInt()); + pool.addConstantInfo(stringInfo); + break; + case 9://字段的符号引用 + FieldRefInfo fieldRefInfo = new FieldRefInfo(pool); + fieldRefInfo.setClassInfoIndex(iter.nextU2ToInt()); + fieldRefInfo.setNameAndTypeIndex(iter.nextU2ToInt()); + pool.addConstantInfo(fieldRefInfo); + break; + case 10://类中方法的符号引用 + MethodRefInfo methodRefInfo = new MethodRefInfo(pool); + methodRefInfo.setClassInfoIndex(iter.nextU2ToInt()); + methodRefInfo.setNameAndTypeIndex(iter.nextU2ToInt()); + pool.addConstantInfo(methodRefInfo); + break; + case 12://字段或方法的部门符号引用 + NameAndTypeInfo nameAndType = new NameAndTypeInfo(pool); + nameAndType.setIndex1(iter.nextU2ToInt()); + nameAndType.setIndex2(iter.nextU2ToInt()); + pool.addConstantInfo(nameAndType); + break; + default: + throw new RuntimeException("the constant pool tag:" + tag + " is not implements"); + } + } + return pool; + } + +} 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 index e3dabb26ab..a326f7f467 100644 --- 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 @@ -6,12 +6,36 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.wsc.coderising.jvm.clz.ClassFile; +import org.wsc.coderising.jvm.clz.ClassIndex; +import org.wsc.coderising.jvm.constant.ClassInfo; +import org.wsc.coderising.jvm.constant.ConstantPool; +import org.wsc.coderising.jvm.constant.MethodRefInfo; +import org.wsc.coderising.jvm.constant.NameAndTypeInfo; +import org.wsc.coderising.jvm.constant.UTF8Info; import org.wsc.coderising.jvm.loader.ClassFileLoader; public class ClassFileloaderTest { - - static String path1 = "./bin"; - static String path2 = "C:/temp"; +private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + + static String path1 = "e:/desktop"; + static String path2 = "./bin"; + + 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 (ClassNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + clzFile.print(); + } + @Before public void setUp() throws Exception { @@ -40,12 +64,12 @@ public void testClassFileLength() throws ClassNotFoundException, IOException { ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); - String className = "org.wsc.coderising.jvm.test.EmployeeV1"; + String className = "com.coderising.jvm.test.EmployeeV1"; byte[] byteCodes = loader.readBinaryCode(className); // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 - Assert.assertEquals(1064, byteCodes.length); + Assert.assertEquals(1056, byteCodes.length); } @@ -53,7 +77,7 @@ public void testClassFileLength() throws ClassNotFoundException, IOException { public void testMagicNumber() throws ClassNotFoundException, IOException { ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); - String className = "org.wsc.coderising.jvm.test.EmployeeV1"; + String className = "com.coderising.jvm.test.EmployeeV1"; byte[] byteCodes = loader.readBinaryCode(className); byte[] codes = new byte[] { byteCodes[0], byteCodes[1], byteCodes[2], byteCodes[3] }; @@ -76,4 +100,95 @@ 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("<init>", 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/592146505/mini-jvm/src/org/wsc/coderising/jvm/util/Util.java b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/util/Util.java new file mode 100644 index 0000000000..f39e6be4b5 --- /dev/null +++ b/group20/592146505/mini-jvm/src/org/wsc/coderising/jvm/util/Util.java @@ -0,0 +1,22 @@ +package org.wsc.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 227607c30666b12a6965bf055699dbc54e3ed2da Mon Sep 17 00:00:00 2001 From: Haochen <haochen_233333@163.com> Date: Wed, 12 Apr 2017 18:33:46 +0800 Subject: [PATCH 236/287] few changes --- .../895457260/code/src/main/java/algorithm/ArrayUtil.java | 2 +- .../code/src/test/java/algorithm/StackUtilTest.java | 5 +++++ .../code/src/test/java/datastructure/LinkedListTest.java | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/group01/895457260/code/src/main/java/algorithm/ArrayUtil.java b/group01/895457260/code/src/main/java/algorithm/ArrayUtil.java index bb5a25a93a..4ac933f4f3 100644 --- a/group01/895457260/code/src/main/java/algorithm/ArrayUtil.java +++ b/group01/895457260/code/src/main/java/algorithm/ArrayUtil.java @@ -96,7 +96,7 @@ public int[] merge(int[] array1, int[] array2) { return newArray; } /** - * 把一个已经存满数据的数组 oldArray的容量进行扩展, 扩展后的新数据大小为oldArray.length + size + * 把一个已经存满数据的数组 oldArray的容量进行扩展, 扩展后的新数据大小为oldArray.size + size * 注意,老数组的元素在新数组中需要保持 * 例如 oldArray = [2,3,6] , size = 3,则返回的新数组为 * [2,3,6,0,0,0] diff --git a/group01/895457260/code/src/test/java/algorithm/StackUtilTest.java b/group01/895457260/code/src/test/java/algorithm/StackUtilTest.java index 8ec48fa134..b66065dd4e 100644 --- a/group01/895457260/code/src/test/java/algorithm/StackUtilTest.java +++ b/group01/895457260/code/src/test/java/algorithm/StackUtilTest.java @@ -75,10 +75,15 @@ public void testRemove() throws Exception { public void testGetTop() throws Exception { //TODO: Test goes here... Stack stack = build(1, 3, 5); + Object[] array = toArray(stack); Assert.assertArrayEquals(new Object[] {}, StackUtil.getTop(stack, 0)); + Assert.assertArrayEquals(new Object[] {1, 3, 5}, array); Assert.assertArrayEquals(new Object[] {3, 5}, StackUtil.getTop(stack, 2)); + Assert.assertArrayEquals(new Object[] {1, 3, 5}, array); Assert.assertArrayEquals(new Object[] {1, 3, 5}, StackUtil.getTop(stack, 3)); + Assert.assertArrayEquals(new Object[] {1, 3, 5}, array); Assert.assertArrayEquals(new Object[] {1, 3, 5}, StackUtil.getTop(stack, 4)); + Assert.assertArrayEquals(new Object[] {1, 3, 5}, array); } /** diff --git a/group01/895457260/code/src/test/java/datastructure/LinkedListTest.java b/group01/895457260/code/src/test/java/datastructure/LinkedListTest.java index dee34c8b3f..d6437ec636 100644 --- a/group01/895457260/code/src/test/java/datastructure/LinkedListTest.java +++ b/group01/895457260/code/src/test/java/datastructure/LinkedListTest.java @@ -114,7 +114,7 @@ public void testRemoveFirstHalf() throws Exception { /** * - * Method: remove(int i, int length) + * Method: remove(int i, int size) * */ @Test From ae72f41e5585de2020133020f006df0d434880be Mon Sep 17 00:00:00 2001 From: Haochen <haochen_233333@163.com> Date: Wed, 12 Apr 2017 19:13:44 +0800 Subject: [PATCH 237/287] start fields and methods loading --- .../src/main/java/jvm/ClassFileLoader.java | 2 +- .../src/main/java/jvm/attr/AttributeInfo.java | 19 +++++ .../code/src/main/java/jvm/attr/CodeAttr.java | 54 +++++++++++++ .../main/java/jvm/attr/LineNumberTable.java | 42 ++++++++++ .../main/java/jvm/attr/LocalVariableItem.java | 39 ++++++++++ .../java/jvm/attr/LocalVariableTable.java | 26 +++++++ .../src/main/java/jvm/attr/StackMapTable.java | 28 +++++++ .../main/java/jvm/classfile/AccessFlag.java | 23 +++++- .../main/java/jvm/classfile/ClassFile.java | 42 ++++++++++ .../main/java/jvm/classfile/ClassParser.java | 9 +-- .../main/java/jvm/classfile/ConstantPool.java | 10 ++- .../code/src/main/java/jvm/field/Field.java | 24 ++++++ .../code/src/main/java/jvm/method/Method.java | 48 ++++++++++++ .../main/java/jvm/util/ByteCodeIterator.java | 57 ++++++++++++++ .../test/java/jvm/ClassFileLoaderTest.java | 78 +++++++++++++++++++ 15 files changed, 493 insertions(+), 8 deletions(-) create mode 100644 group01/895457260/code/src/main/java/jvm/attr/AttributeInfo.java create mode 100644 group01/895457260/code/src/main/java/jvm/attr/CodeAttr.java create mode 100644 group01/895457260/code/src/main/java/jvm/attr/LineNumberTable.java create mode 100644 group01/895457260/code/src/main/java/jvm/attr/LocalVariableItem.java create mode 100644 group01/895457260/code/src/main/java/jvm/attr/LocalVariableTable.java create mode 100644 group01/895457260/code/src/main/java/jvm/attr/StackMapTable.java create mode 100644 group01/895457260/code/src/main/java/jvm/field/Field.java create mode 100644 group01/895457260/code/src/main/java/jvm/method/Method.java create mode 100644 group01/895457260/code/src/main/java/jvm/util/ByteCodeIterator.java diff --git a/group01/895457260/code/src/main/java/jvm/ClassFileLoader.java b/group01/895457260/code/src/main/java/jvm/ClassFileLoader.java index 28a4ff0b30..ade626ad83 100644 --- a/group01/895457260/code/src/main/java/jvm/ClassFileLoader.java +++ b/group01/895457260/code/src/main/java/jvm/ClassFileLoader.java @@ -77,7 +77,7 @@ boolean checkMagicNumber(byte[] bytes) { return magicNumber.equals(str.toLowerCase()); } - ClassFile load(String className) throws ReadClassException { + public ClassFile load(String className) throws ReadClassException { byte[] bytes = readBinaryCode(className); if (checkMagicNumber(bytes)) { return ClassParser.parse(bytes); diff --git a/group01/895457260/code/src/main/java/jvm/attr/AttributeInfo.java b/group01/895457260/code/src/main/java/jvm/attr/AttributeInfo.java new file mode 100644 index 0000000000..838d0b0852 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/attr/AttributeInfo.java @@ -0,0 +1,19 @@ +package jvm.attr; + +public abstract class AttributeInfo { + public static final String CODE = "Code"; + public static final String CONST_VALUE = "ConstantValue"; + public static final String EXCEPTIONS = "Exceptions"; + public static final String LINE_NUM_TABLE = "LineNumberTable"; + public static final String LOCAL_VAR_TABLE = "LocalVariableTable"; + public static final String STACK_MAP_TABLE = "StackMapTable"; + int attrNameIndex; + int attrLen ; + public AttributeInfo(int attrNameIndex, int attrLen) { + + this.attrNameIndex = attrNameIndex; + this.attrLen = attrLen; + } + + +} diff --git a/group01/895457260/code/src/main/java/jvm/attr/CodeAttr.java b/group01/895457260/code/src/main/java/jvm/attr/CodeAttr.java new file mode 100644 index 0000000000..e9384082a4 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/attr/CodeAttr.java @@ -0,0 +1,54 @@ +package jvm.attr; + +import jvm.classfile.ClassFile; +import jvm.util.ByteCodeIterator; + +public class CodeAttr extends AttributeInfo { + private int maxStack ; + private int maxLocals ; + private int codeLen ; + private String code; + public String getCode() { + return code; + } + + //private ByteCodeCommand[] cmds ; + //public ByteCodeCommand[] getCmds() { + // return cmds; + //} + private LineNumberTable lineNumTable; + private LocalVariableTable localVarTable; + private StackMapTable stackMapTable; + + public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen,String code /*ByteCodeCommand[] cmds*/) { + super(attrNameIndex, attrLen); + this.maxStack = maxStack; + this.maxLocals = maxLocals; + this.codeLen = codeLen; + this.code = code; + //this.cmds = cmds; + } + + public void setLineNumberTable(LineNumberTable t) { + this.lineNumTable = t; + } + + public void setLocalVariableTable(LocalVariableTable t) { + this.localVarTable = t; + } + + public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ + + + return null; + } + private void setStackMapTable(StackMapTable t) { + this.stackMapTable = t; + + } + + + + + +} diff --git a/group01/895457260/code/src/main/java/jvm/attr/LineNumberTable.java b/group01/895457260/code/src/main/java/jvm/attr/LineNumberTable.java new file mode 100644 index 0000000000..e31d86525e --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/attr/LineNumberTable.java @@ -0,0 +1,42 @@ +package jvm.attr; + +import jvm.util.ByteCodeIterator; + +import java.util.ArrayList; +import java.util.List; + +public class LineNumberTable extends AttributeInfo { + List<LineNumberItem> items = new ArrayList<LineNumberItem>(); + + private static class LineNumberItem{ + int startPC; + int lineNum; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLineNum() { + return lineNum; + } + public void setLineNum(int lineNum) { + this.lineNum = lineNum; + } + } + public void addLineNumberItem(LineNumberItem item){ + this.items.add(item); + } + public LineNumberTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + + } + + public static LineNumberTable parse(ByteCodeIterator iter){ + + return null; + } + + + +} diff --git a/group01/895457260/code/src/main/java/jvm/attr/LocalVariableItem.java b/group01/895457260/code/src/main/java/jvm/attr/LocalVariableItem.java new file mode 100644 index 0000000000..cc408c9f3e --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/attr/LocalVariableItem.java @@ -0,0 +1,39 @@ +package jvm.attr; + +public class LocalVariableItem { + private int startPC; + private int length; + private int nameIndex; + private int descIndex; + private int index; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getNameIndex() { + return nameIndex; + } + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + public int getDescIndex() { + return descIndex; + } + public void setDescIndex(int descIndex) { + this.descIndex = descIndex; + } + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/attr/LocalVariableTable.java b/group01/895457260/code/src/main/java/jvm/attr/LocalVariableTable.java new file mode 100644 index 0000000000..fef46e9709 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/attr/LocalVariableTable.java @@ -0,0 +1,26 @@ +package jvm.attr; + + +import jvm.util.ByteCodeIterator; + +import java.util.ArrayList; +import java.util.List; + +public class LocalVariableTable extends AttributeInfo{ + + List<LocalVariableItem> items = new ArrayList<LocalVariableItem>(); + + public LocalVariableTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static LocalVariableTable parse(ByteCodeIterator iter){ + + return null; + } + private void addLocalVariableItem(LocalVariableItem item) { + this.items.add(item); + } + + +} diff --git a/group01/895457260/code/src/main/java/jvm/attr/StackMapTable.java b/group01/895457260/code/src/main/java/jvm/attr/StackMapTable.java new file mode 100644 index 0000000000..d0edb2cc97 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/attr/StackMapTable.java @@ -0,0 +1,28 @@ +package jvm.attr; + +import jvm.util.ByteCodeIterator; + +public class StackMapTable extends AttributeInfo{ + + private String originalCode; + + public StackMapTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static StackMapTable parse(ByteCodeIterator iter){ + int index = iter.nextU2ToInt(); + int len = iter.nextU4ToInt(); + StackMapTable t = new StackMapTable(index,len); + + //后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 + String code = iter.nextUxToHexString(len); + t.setOriginalCode(code); + + return t; + } + + private void setOriginalCode(String code) { + this.originalCode = code; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/AccessFlag.java b/group01/895457260/code/src/main/java/jvm/classfile/AccessFlag.java index f9b14f9d6f..18c327fb0d 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/AccessFlag.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/AccessFlag.java @@ -5,5 +5,26 @@ * TODO: */ public class AccessFlag { - int flags; + int flagValue; + + public AccessFlag() {} + + 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/group01/895457260/code/src/main/java/jvm/classfile/ClassFile.java b/group01/895457260/code/src/main/java/jvm/classfile/ClassFile.java index ccdb47bcf2..0f0d24aaa4 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/ClassFile.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/ClassFile.java @@ -1,6 +1,13 @@ package jvm.classfile; +import jvm.classfile.constant.item.impl.ClassInfo; +import jvm.field.Field; +import jvm.method.Method; + +import java.util.ArrayList; +import java.util.List; + /** * Created by Haochen on 2017/4/9. * TODO: @@ -11,6 +18,41 @@ public class ClassFile { ConstantPool constantPool; int minorVersion; int majorVersion; + private List<Field> fields = new ArrayList<>(); + private List<Method> methods = new ArrayList<>(); + + public void addField(Field f){ + this.fields.add(f); + } + public List<Field> getFields(){ + return this.fields; + } + public void addMethod(Method m){ + this.methods.add(m); + } + public List<Method> getMethods() { + return methods; + } + + 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.classIndex.getThisClassIndex(); + ClassInfo thisClass = (ClassInfo)this.getConstantPool().getConstantInfo(thisClassIndex); + return thisClass.getClassName(); + } + + private String getSuperClassName(){ + ClassInfo superClass = (ClassInfo)this.getConstantPool() + .getConstantInfo(this.classIndex.getSuperClassIndex()); + return superClass.getClassName(); + } public int getMinorVersion() { return minorVersion; 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 0a22134c6f..21b168df6e 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/ClassParser.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/ClassParser.java @@ -58,8 +58,7 @@ private static int parseMajorVersion(byte[] bytes, StartIndex index) { private static void linkConstantReferences(ClassFile classFile) { ConstantPool constantPool = classFile.constantPool; - Map<Integer, Constant> constantMap = constantPool.constantMap; - constantMap.forEach((i, c) -> { + constantPool.forEach((i, c) -> { if (c instanceof IReference) { ((IReference) c).linkReference(constantPool); } @@ -74,7 +73,7 @@ private static ConstantPool parseConstantPool(byte[] bytes, StartIndex index) { index.constantIndexMap.put(0, currentIndex); int count = ByteUtils.toInt(bytes, currentIndex, COUNT_LEN); - constantPool.constantMap.put(0, new CountConstant(count)); + constantPool.putConstantInfo(0, new CountConstant(count)); currentIndex += COUNT_LEN; Map<Integer, ConstantParser> parserMap = new HashMap<>(); @@ -89,7 +88,7 @@ private static ConstantPool parseConstantPool(byte[] bytes, StartIndex index) { ConstantParser parser = parserMap.get(i); int startIndex = index.constantIndexMap.get(i); Constant constant = parser.parse(bytes, startIndex); - constantPool.constantMap.put(i, constant); + constantPool.putConstantInfo(i, constant); } index.accessFlags = currentIndex; @@ -108,7 +107,7 @@ private static ClassIndex parseClassIndex(byte[] bytes, StartIndex index) { private static AccessFlag parseAccessFlag(byte[] bytes, StartIndex index) { AccessFlag accessFlag = new AccessFlag(); - accessFlag.flags = ByteUtils.toInt(bytes, index.accessFlags, 2); + accessFlag.flagValue = 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 index cc9ab01c24..2552411efa 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/ConstantPool.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/ConstantPool.java @@ -4,18 +4,26 @@ import java.util.HashMap; import java.util.Map; +import java.util.function.BiConsumer; /** * Created by Haochen on 2017/4/9. * TODO: */ public class ConstantPool { - Map<Integer, Constant> constantMap = new HashMap<>(); + private Map<Integer, Constant> constantMap = new HashMap<>(); + + public void forEach(BiConsumer<? super Integer, ? super Constant> action) { + constantMap.forEach(action); + } public int getSize() { return constantMap.size() - 1; } + Constant putConstantInfo(int index, Constant c) { + return constantMap.put(index, c); + } public Constant getConstantInfo(int index) { return constantMap.get(index); } diff --git a/group01/895457260/code/src/main/java/jvm/field/Field.java b/group01/895457260/code/src/main/java/jvm/field/Field.java new file mode 100644 index 0000000000..f5eaaf4f86 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/field/Field.java @@ -0,0 +1,24 @@ +package jvm.field; + +import jvm.classfile.ConstantPool; +import jvm.util.ByteCodeIterator; + +public class Field { + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private ConstantPool pool; + + public Field( int accessFlag, int nameIndex, int descriptorIndex,ConstantPool pool) { + + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + this.pool = pool; + } + + public static Field parse(ConstantPool pool, ByteCodeIterator iter){ + return null; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/method/Method.java b/group01/895457260/code/src/main/java/jvm/method/Method.java new file mode 100644 index 0000000000..8ba1c3d96c --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/method/Method.java @@ -0,0 +1,48 @@ +package jvm.method; + +import jvm.classfile.ClassFile; +import jvm.attr.CodeAttr; +import jvm.util.ByteCodeIterator; + + +public class Method { + + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private CodeAttr codeAttr; + + private ClassFile clzFile; + + + public ClassFile getClzFile() { + return clzFile; + } + + public int getNameIndex() { + return nameIndex; + } + public int getDescriptorIndex() { + return descriptorIndex; + } + + public CodeAttr getCodeAttr() { + return codeAttr; + } + + public void setCodeAttr(CodeAttr code) { + this.codeAttr = code; + } + + public Method(ClassFile clzFile,int accessFlag, int nameIndex, int descriptorIndex) { + this.clzFile = clzFile; + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + } + + public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ + return null; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/util/ByteCodeIterator.java b/group01/895457260/code/src/main/java/jvm/util/ByteCodeIterator.java new file mode 100644 index 0000000000..926de8df4a --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/util/ByteCodeIterator.java @@ -0,0 +1,57 @@ +package jvm.util; + +import java.util.Arrays; + +import jvm.util.ByteUtils; + +public class ByteCodeIterator { + private byte[] codes; + private int pos = 0; + + ByteCodeIterator(byte[] codes) { + this.codes = codes; + } + + 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; + } + + public int nextU1toInt() { + + return ByteUtils.toInt(new byte[] { codes[pos++] }, 0, 1); + } + + public int nextU2ToInt() { + return ByteUtils.toInt(new byte[] { codes[pos++], codes[pos++] }, 0 ,2); + } + + public int nextU4ToInt() { + return ByteUtils.toInt( + new byte[] { codes[pos++], codes[pos++], codes[pos++], codes[pos++] }, 0, 4); + } + + public String nextU4ToHexString() { + return ByteUtils.toHexString( + new byte[] { codes[pos++], codes[pos++], codes[pos++], codes[pos++] }, 0, 4); + } + + public String nextUxToHexString(int len) { + byte[] tmp = new byte[len]; + + for (int i = 0; i < len; i++) { + tmp[i] = codes[pos++]; + } + return ByteUtils.toHexString(tmp, 0, tmp.length).toLowerCase(); + + } + + public void back(int n) { + this.pos -= n; + } +} diff --git a/group01/895457260/code/src/test/java/jvm/ClassFileLoaderTest.java b/group01/895457260/code/src/test/java/jvm/ClassFileLoaderTest.java index 16fbfc58e5..4f24bf938c 100644 --- a/group01/895457260/code/src/test/java/jvm/ClassFileLoaderTest.java +++ b/group01/895457260/code/src/test/java/jvm/ClassFileLoaderTest.java @@ -8,11 +8,15 @@ import jvm.classfile.constant.item.impl.NameAndTypeInfo; import jvm.classfile.constant.item.impl.UTF8Info; import jvm.exception.ReadClassException; +import jvm.field.Field; +import jvm.method.Method; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import java.util.List; + public class ClassFileLoaderTest { private static final String FULL_QUALIFIED_CLASS_NAME = "jvm/EmployeeV1"; private static final String LOAD_CLASS_NAME = "jvm.EmployeeV1"; @@ -159,4 +163,78 @@ public void testClassIndex() { Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); } + +// /** +// * 下面是第三次JVM课应实现的测试用例 +// */ +// @Test +// public void testReadFields() { +// +// List<Field> fields = clzFile.getFields(); +// Assert.assertEquals(2, fields.size()); +// { +// Field f = fields.get(0); +// Assert.assertEquals("name:Ljava/lang/String;", f.toString()); +// } +// { +// Field f = fields.get(1); +// Assert.assertEquals("age:I", f.toString()); +// } +// } +// +// @Test +// public void testMethods() { +// +// List<Method> methods = clzFile.getMethods(); +// ConstantPool pool = clzFile.getConstantPool(); +// +// { +// Method m = methods.get(0); +// assertMethodEquals(pool,m, +// "<init>", +// "(Ljava/lang/String;I)V", +// "2ab7000c2a2bb5000f2a1cb50011b1"); +// +// } +// { +// Method m = methods.get(1); +// assertMethodEquals(pool,m, +// "setName", +// "(Ljava/lang/String;)V", +// "2a2bb5000fb1"); +// +// } +// { +// Method m = methods.get(2); +// assertMethodEquals(pool,m, +// "setAge", +// "(I)V", +// "2a1bb50011b1"); +// } +// { +// Method m = methods.get(3); +// assertMethodEquals(pool,m, +// "sayHello", +// "()V", +// "b2001c1222b60024b1"); +// +// } +// { +// Method m = methods.get(4); +// assertMethodEquals(pool,m, +// "main", +// "([Ljava/lang/String;)V", +// "bb000159122b101db7002d4c2bb6002fb1"); +// } +// } + + private void assertMethodEquals(ConstantPool pool, Method m, + String expectedName, String expectedDesc,String expectedCode) { + String methodName = ((UTF8Info) pool.getConstantInfo(m.getNameIndex())).getValue(); + String methodDesc = ((UTF8Info) pool.getConstantInfo(m.getDescriptorIndex())).getValue(); + String code = m.getCodeAttr().getCode(); + Assert.assertEquals(expectedName, methodName); + Assert.assertEquals(expectedDesc, methodDesc); + Assert.assertEquals(expectedCode, code); + } } From f69aea10e89cd1b0aaa2a04641cd20fc648dc97d Mon Sep 17 00:00:00 2001 From: Haochen <haochen_233333@163.com> Date: Wed, 12 Apr 2017 19:51:17 +0800 Subject: [PATCH 238/287] update the impl of constant pool loading with ByteCodeIterator --- .../src/main/java/jvm/attr/StackMapTable.java | 2 +- .../main/java/jvm/classfile/ClassParser.java | 104 ++++++------------ .../constant/parser/ConstantParser.java | 6 +- .../parser/ConstantParserFactory.java | 6 +- .../constant/parser/impl/ClassInfoParser.java | 12 +- .../parser/impl/DoubleInfoParser.java | 17 +-- .../parser/impl/FieldRefInfoParser.java | 14 +-- .../constant/parser/impl/FloatInfoParser.java | 13 +-- .../parser/impl/IntegerInfoParser.java | 13 +-- .../impl/InterfaceMethodRefInfoParser.java | 14 +-- .../parser/impl/InvokeDynamicInfoParser.java | 14 +-- .../constant/parser/impl/LongInfoParser.java | 17 +-- .../parser/impl/MethodHandleInfoParser.java | 14 +-- .../parser/impl/MethodRefInfoParser.java | 14 +-- .../parser/impl/MethodTypeInfoParser.java | 11 +- .../parser/impl/NameAndTypeInfoParser.java | 14 +-- .../parser/impl/StringInfoParser.java | 12 +- .../constant/parser/impl/UTF8InfoParser.java | 20 +--- .../main/java/jvm/util/ByteCodeIterator.java | 45 +++++--- 19 files changed, 119 insertions(+), 243 deletions(-) diff --git a/group01/895457260/code/src/main/java/jvm/attr/StackMapTable.java b/group01/895457260/code/src/main/java/jvm/attr/StackMapTable.java index d0edb2cc97..7bf883ff21 100644 --- a/group01/895457260/code/src/main/java/jvm/attr/StackMapTable.java +++ b/group01/895457260/code/src/main/java/jvm/attr/StackMapTable.java @@ -16,7 +16,7 @@ public static StackMapTable parse(ByteCodeIterator iter){ StackMapTable t = new StackMapTable(index,len); //后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 - String code = iter.nextUxToHexString(len); + String code = iter.nextHexString(len); t.setOriginalCode(code); return t; 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 21b168df6e..81ed11dd09 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/ClassParser.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/ClassParser.java @@ -5,6 +5,7 @@ import jvm.classfile.constant.item.impl.CountConstant; import jvm.classfile.constant.parser.ConstantParser; import jvm.classfile.constant.parser.ConstantParserFactory; +import jvm.util.ByteCodeIterator; import jvm.util.ByteUtils; import java.util.HashMap; @@ -15,99 +16,62 @@ * TODO: */ public class ClassParser { - private static class StartIndex { - int magicNumber = 0; - int minorVersion = 4; - int majorVersion = 6; - int constantPoolCount = 8; - Map<Integer, Integer> constantIndexMap = new HashMap<>(); - int accessFlags; - int thisClass; - int superClass; - int interfacesCount; - Map<Integer, Integer> interfaceIndexMap = new HashMap<>(); - int fieldsCount; - Map<Integer, Integer> fieldIndexMap = new HashMap<>(); - int methodsCount; - Map<Integer, Integer> methodIndexMap = new HashMap<>(); - int attributesCount; - Map<Integer, Integer> attributeIndexMap = new HashMap<>(); - } - - private static StartIndex index = new StartIndex(); - public static ClassFile parse(byte[] bytes) { ClassFile classFile = new ClassFile(); + ByteCodeIterator iterator = new ByteCodeIterator(bytes); + + iterator.skip(4); // skip magic number - 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); + classFile.minorVersion = parseMinorVersion(iterator); + classFile.majorVersion = parseMajorVersion(iterator); + classFile.constantPool = parseConstantPool(iterator); + classFile.accessFlag = parseAccessFlag(iterator); + classFile.classIndex = parseClassIndex(iterator); linkConstantReferences(classFile); return classFile; } - private static int parseMinorVersion(byte[] bytes, StartIndex index) { - return ByteUtils.toInt(bytes, index.minorVersion, 2); + private static int parseMinorVersion(ByteCodeIterator iterator) { + return iterator.nextU2ToInt(); } - private static int parseMajorVersion(byte[] bytes, StartIndex index) { - return ByteUtils.toInt(bytes, index.majorVersion, 2); + private static int parseMajorVersion(ByteCodeIterator iterator) { + return iterator.nextU2ToInt(); } - private static void linkConstantReferences(ClassFile classFile) { - ConstantPool constantPool = classFile.constantPool; - constantPool.forEach((i, c) -> { - if (c instanceof IReference) { - ((IReference) c).linkReference(constantPool); - } - }); - } - - private static ConstantPool parseConstantPool(byte[] bytes, StartIndex index) { - final int COUNT_LEN = 2; - + private static ConstantPool parseConstantPool(ByteCodeIterator iterator) { ConstantPool constantPool = new ConstantPool(); - int currentIndex = index.constantPoolCount; - index.constantIndexMap.put(0, currentIndex); - int count = ByteUtils.toInt(bytes, currentIndex, COUNT_LEN); + int count = iterator.nextU2ToInt(); constantPool.putConstantInfo(0, new CountConstant(count)); - currentIndex += COUNT_LEN; - Map<Integer, ConstantParser> parserMap = new HashMap<>(); - 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 = 1; i < count; ++i) { - ConstantParser parser = parserMap.get(i); - int startIndex = index.constantIndexMap.get(i); - Constant constant = parser.parse(bytes, startIndex); - constantPool.putConstantInfo(i, constant); + int tag = iterator.nextU1ToInt(); + ConstantParser parser = ConstantParserFactory.get(tag); + constantPool.putConstantInfo(i, parser.parse(iterator)); } - - 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) { + private static AccessFlag parseAccessFlag(ByteCodeIterator iterator) { + AccessFlag accessFlag = new AccessFlag(); + accessFlag.flagValue = iterator.nextU2ToInt(); + return accessFlag; + } + + private static ClassIndex parseClassIndex(ByteCodeIterator iterator) { ClassIndex classIndex = new ClassIndex(); - classIndex.thisClass = ByteUtils.toInt(bytes, index.thisClass, 2); - classIndex.superClass = ByteUtils.toInt(bytes, index.superClass, 2); + classIndex.thisClass = iterator.nextU2ToInt(); + classIndex.superClass = iterator.nextU2ToInt(); return classIndex; } - private static AccessFlag parseAccessFlag(byte[] bytes, StartIndex index) { - AccessFlag accessFlag = new AccessFlag(); - accessFlag.flagValue = ByteUtils.toInt(bytes, index.accessFlags, 2); - return accessFlag; + private static void linkConstantReferences(ClassFile classFile) { + ConstantPool constantPool = classFile.constantPool; + constantPool.forEach((i, c) -> { + if (c instanceof IReference) { + ((IReference) c).linkReference(constantPool); + } + }); } } 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 index cadf5104d3..9902724df0 100644 --- 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 @@ -1,14 +1,12 @@ package jvm.classfile.constant.parser; import jvm.classfile.constant.item.Constant; +import jvm.util.ByteCodeIterator; /** * Created by Haochen on 2017/4/9. * TODO: */ public interface ConstantParser { - int TAG_LEN = 1; - - Constant parse(byte[] bytes, int startIndex); - int length(); + Constant parse(ByteCodeIterator iterator); } 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 fec8930428..56583b2df7 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 @@ -23,7 +23,7 @@ public class ConstantParserFactory { 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) { + public static ConstantParser get(int type) { switch (type) { case CONSTANT_CLASS: return new ClassInfoParser(); @@ -46,9 +46,7 @@ public static ConstantParser get(int type, byte[] bytes, int startIndex) { 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); + return new UTF8InfoParser(); 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/ClassInfoParser.java b/group01/895457260/code/src/main/java/jvm/classfile/constant/parser/impl/ClassInfoParser.java index 2723ce61c4..78b9a3f03f 100644 --- 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 @@ -3,6 +3,7 @@ import jvm.classfile.constant.item.Constant; import jvm.classfile.constant.item.impl.ClassInfo; import jvm.classfile.constant.parser.ConstantParser; +import jvm.util.ByteCodeIterator; import jvm.util.ByteUtils; /** @@ -11,14 +12,7 @@ */ 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; + public Constant parse(ByteCodeIterator iterator) { + return new ClassInfo(iterator.nextU2ToInt()); } } 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 index 18a5bda426..72caf2f799 100644 --- 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 @@ -3,6 +3,7 @@ import jvm.classfile.constant.item.Constant; import jvm.classfile.constant.item.impl.DoubleInfo; import jvm.classfile.constant.parser.ConstantParser; +import jvm.util.ByteCodeIterator; /** * Created by Haochen on 2017/4/9. @@ -10,19 +11,9 @@ */ 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]; - } + public Constant parse(ByteCodeIterator iterator) { + byte[] high = iterator.getBytes(4); + byte[] low = iterator.getBytes(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 index 13c262d392..1a3feac724 100644 --- 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 @@ -3,6 +3,7 @@ import jvm.classfile.constant.item.Constant; import jvm.classfile.constant.item.impl.FieldRefInfo; import jvm.classfile.constant.parser.ConstantParser; +import jvm.util.ByteCodeIterator; import jvm.util.ByteUtils; /** @@ -11,16 +12,9 @@ */ 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); + public Constant parse(ByteCodeIterator iterator) { + int classIndex = iterator.nextU2ToInt(); + int nameAndTypeIndex = iterator.nextU2ToInt(); 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 index b099cc4cfe..bedd2fd963 100644 --- 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 @@ -3,6 +3,7 @@ import jvm.classfile.constant.item.Constant; import jvm.classfile.constant.item.impl.FloatInfo; import jvm.classfile.constant.parser.ConstantParser; +import jvm.util.ByteCodeIterator; /** * Created by Haochen on 2017/4/9. @@ -10,15 +11,7 @@ */ 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; + public Constant parse(ByteCodeIterator iterator) { + return new FloatInfo(iterator.getBytes(4)); } } 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 index 9de454a3f8..ac316580d7 100644 --- 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 @@ -3,6 +3,7 @@ import jvm.classfile.constant.item.Constant; import jvm.classfile.constant.item.impl.IntegerInfo; import jvm.classfile.constant.parser.ConstantParser; +import jvm.util.ByteCodeIterator; /** * Created by Haochen on 2017/4/9. @@ -10,15 +11,7 @@ */ 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; + public Constant parse(ByteCodeIterator iterator) { + return new IntegerInfo(iterator.getBytes(4)); } } 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 index cc379cc7e6..65a9ff4fdf 100644 --- 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 @@ -4,6 +4,7 @@ import jvm.classfile.constant.item.impl.FieldRefInfo; import jvm.classfile.constant.item.impl.InterfaceMethodRefInfo; import jvm.classfile.constant.parser.ConstantParser; +import jvm.util.ByteCodeIterator; import jvm.util.ByteUtils; /** @@ -12,16 +13,9 @@ */ 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); + public Constant parse(ByteCodeIterator iterator) { + int classIndex = iterator.nextU2ToInt(); + int nameAndTypeIndex = iterator.nextU2ToInt(); 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 index f77afe553b..1f8e5a3809 100644 --- 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 @@ -3,6 +3,7 @@ import jvm.classfile.constant.item.Constant; import jvm.classfile.constant.item.impl.InvokeDynamicInfo; import jvm.classfile.constant.parser.ConstantParser; +import jvm.util.ByteCodeIterator; import jvm.util.ByteUtils; /** @@ -11,16 +12,9 @@ */ 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); + public Constant parse(ByteCodeIterator iterator) { + int bootstrapMethodAttrIndex = iterator.nextU2ToInt(); + int nameAndTypeIndex = iterator.nextU2ToInt(); 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 index aa963a4dc0..f58c092665 100644 --- 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 @@ -4,6 +4,7 @@ import jvm.classfile.constant.item.impl.DoubleInfo; import jvm.classfile.constant.item.impl.LongInfo; import jvm.classfile.constant.parser.ConstantParser; +import jvm.util.ByteCodeIterator; /** * Created by Haochen on 2017/4/9. @@ -11,19 +12,9 @@ */ 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]; - } + public Constant parse(ByteCodeIterator iterator) { + byte[] high = iterator.getBytes(4); + byte[] low = iterator.getBytes(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 index 9e41aceec5..9bff9c4285 100644 --- 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 @@ -3,6 +3,7 @@ import jvm.classfile.constant.item.Constant; import jvm.classfile.constant.item.impl.MethodHandleInfo; import jvm.classfile.constant.parser.ConstantParser; +import jvm.util.ByteCodeIterator; import jvm.util.ByteUtils; /** @@ -11,16 +12,9 @@ */ 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); + public Constant parse(ByteCodeIterator iterator) { + int referenceKind = iterator.nextU1ToInt(); + int referenceIndex = iterator.nextU2ToInt(); 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 index ade7f94940..1dbe7f85c6 100644 --- 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 @@ -4,6 +4,7 @@ import jvm.classfile.constant.item.impl.FieldRefInfo; import jvm.classfile.constant.item.impl.MethodRefInfo; import jvm.classfile.constant.parser.ConstantParser; +import jvm.util.ByteCodeIterator; import jvm.util.ByteUtils; /** @@ -12,16 +13,9 @@ */ 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); + public Constant parse(ByteCodeIterator iterator) { + int classIndex = iterator.nextU2ToInt(); + int nameAndTypeIndex = iterator.nextU2ToInt(); 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 index d4af9c86e2..37a59f6422 100644 --- 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 @@ -3,6 +3,7 @@ import jvm.classfile.constant.item.Constant; import jvm.classfile.constant.item.impl.MethodTypeInfo; import jvm.classfile.constant.parser.ConstantParser; +import jvm.util.ByteCodeIterator; import jvm.util.ByteUtils; /** @@ -11,14 +12,8 @@ */ public class MethodTypeInfoParser implements ConstantParser { @Override - public Constant parse(byte[] bytes, int startIndex) { - startIndex += TAG_LEN; - int descriptorIndex = ByteUtils.toInt(bytes, startIndex, 2); + public Constant parse(ByteCodeIterator iterator) { + int descriptorIndex = iterator.nextU2ToInt(); 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 index 47ab719db8..3472f87f56 100644 --- 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 @@ -3,6 +3,7 @@ import jvm.classfile.constant.item.Constant; import jvm.classfile.constant.item.impl.NameAndTypeInfo; import jvm.classfile.constant.parser.ConstantParser; +import jvm.util.ByteCodeIterator; import jvm.util.ByteUtils; /** @@ -11,16 +12,9 @@ */ 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); + public Constant parse(ByteCodeIterator iterator) { + int nameIndex = iterator.nextU2ToInt(); + int descriptorIndex = iterator.nextU2ToInt(); 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 index 508beca537..b29ccdf4aa 100644 --- 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 @@ -3,6 +3,7 @@ import jvm.classfile.constant.item.Constant; import jvm.classfile.constant.item.impl.StringInfo; import jvm.classfile.constant.parser.ConstantParser; +import jvm.util.ByteCodeIterator; import jvm.util.ByteUtils; /** @@ -11,14 +12,7 @@ */ 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; + public Constant parse(ByteCodeIterator iterator) { + return new StringInfo(iterator.nextU2ToInt()); } } 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 108bc11642..58aa699c24 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 @@ -3,29 +3,17 @@ import jvm.classfile.constant.item.Constant; import jvm.classfile.constant.item.impl.UTF8Info; import jvm.classfile.constant.parser.ConstantParser; +import jvm.util.ByteCodeIterator; /** * 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); + public Constant parse(ByteCodeIterator iterator) { + int length = iterator.nextU2ToInt(); + byte[] array = iterator.getBytes(length); return new UTF8Info(length, array); } - - @Override - public int length() { - return 3 + length; - } } diff --git a/group01/895457260/code/src/main/java/jvm/util/ByteCodeIterator.java b/group01/895457260/code/src/main/java/jvm/util/ByteCodeIterator.java index 926de8df4a..4f9cfa7fef 100644 --- a/group01/895457260/code/src/main/java/jvm/util/ByteCodeIterator.java +++ b/group01/895457260/code/src/main/java/jvm/util/ByteCodeIterator.java @@ -2,13 +2,11 @@ import java.util.Arrays; -import jvm.util.ByteUtils; - public class ByteCodeIterator { private byte[] codes; private int pos = 0; - ByteCodeIterator(byte[] codes) { + public ByteCodeIterator(byte[] codes) { this.codes = codes; } @@ -22,36 +20,51 @@ public byte[] getBytes(int len) { return data; } - public int nextU1toInt() { + public int currentIndex() { + return pos; + } - return ByteUtils.toInt(new byte[] { codes[pos++] }, 0, 1); + public int nextU1ToInt() { + return nextInt(1); } public int nextU2ToInt() { - return ByteUtils.toInt(new byte[] { codes[pos++], codes[pos++] }, 0 ,2); + return nextInt(2); } public int nextU4ToInt() { - return ByteUtils.toInt( - new byte[] { codes[pos++], codes[pos++], codes[pos++], codes[pos++] }, 0, 4); + return nextInt(4); } public String nextU4ToHexString() { - return ByteUtils.toHexString( - new byte[] { codes[pos++], codes[pos++], codes[pos++], codes[pos++] }, 0, 4); + return nextHexString(4); } - public String nextUxToHexString(int len) { - byte[] tmp = new byte[len]; + public String nextHexString(int byteCount) { + String result = ByteUtils.toHexString(codes, pos, byteCount).toLowerCase(); + pos += byteCount; + return result; + } - for (int i = 0; i < len; i++) { - tmp[i] = codes[pos++]; - } - return ByteUtils.toHexString(tmp, 0, tmp.length).toLowerCase(); + public int nextInt(int byteCount) { + int result = ByteUtils.toInt(codes, pos, byteCount); + pos += byteCount; + return result; + } + public void skip(int n) { + this.pos += n; } public void back(int n) { this.pos -= n; } + + public void seekTo(int n) { + this.pos = n; + } + + public void reset() { + this.pos = 0; + } } From d3ba3218f47f648657df552ecd4488be6eb1adf2 Mon Sep 17 00:00:00 2001 From: Haochen <haochen_233333@163.com> Date: Wed, 12 Apr 2017 19:55:05 +0800 Subject: [PATCH 239/287] change the impl of constant pool to List --- .../src/main/java/jvm/classfile/ClassParser.java | 11 +++-------- .../src/main/java/jvm/classfile/ConstantPool.java | 14 +++++++------- 2 files changed, 10 insertions(+), 15 deletions(-) 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 81ed11dd09..e46705f4b8 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/ClassParser.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/ClassParser.java @@ -1,15 +1,10 @@ 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; import jvm.util.ByteCodeIterator; -import jvm.util.ByteUtils; - -import java.util.HashMap; -import java.util.Map; /** * Created by Haochen on 2017/4/9. @@ -43,12 +38,12 @@ private static ConstantPool parseConstantPool(ByteCodeIterator iterator) { ConstantPool constantPool = new ConstantPool(); int count = iterator.nextU2ToInt(); - constantPool.putConstantInfo(0, new CountConstant(count)); + constantPool.addConstantInfo(new CountConstant(count)); for (int i = 1; i < count; ++i) { int tag = iterator.nextU1ToInt(); ConstantParser parser = ConstantParserFactory.get(tag); - constantPool.putConstantInfo(i, parser.parse(iterator)); + constantPool.addConstantInfo(parser.parse(iterator)); } return constantPool; } @@ -68,7 +63,7 @@ private static ClassIndex parseClassIndex(ByteCodeIterator iterator) { private static void linkConstantReferences(ClassFile classFile) { ConstantPool constantPool = classFile.constantPool; - constantPool.forEach((i, c) -> { + constantPool.forEach(c -> { if (c instanceof IReference) { ((IReference) c).linkReference(constantPool); } 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 2552411efa..b077ad83a4 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/ConstantPool.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/ConstantPool.java @@ -2,18 +2,18 @@ import jvm.classfile.constant.item.Constant; -import java.util.HashMap; -import java.util.Map; -import java.util.function.BiConsumer; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; /** * Created by Haochen on 2017/4/9. * TODO: */ public class ConstantPool { - private Map<Integer, Constant> constantMap = new HashMap<>(); + private List<Constant> constantMap = new ArrayList<>(); - public void forEach(BiConsumer<? super Integer, ? super Constant> action) { + public void forEach(Consumer<? super Constant> action) { constantMap.forEach(action); } @@ -21,8 +21,8 @@ public int getSize() { return constantMap.size() - 1; } - Constant putConstantInfo(int index, Constant c) { - return constantMap.put(index, c); + boolean addConstantInfo(Constant c) { + return constantMap.add(c); } public Constant getConstantInfo(int index) { return constantMap.get(index); From b3a57a53ebcb629a3907d3a716e741aae6f9203e Mon Sep 17 00:00:00 2001 From: Patrick <Patrick@DESKTOP-JLNF6GI> Date: Wed, 12 Apr 2017 20:35:04 +0800 Subject: [PATCH 240/287] =?UTF-8?q?=E4=B8=AD=E5=BA=8F=E8=A1=A8=E8=BE=BE?= =?UTF-8?q?=E5=BC=8F=E5=92=8Cjvm=E8=A7=A3=E6=9E=90=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E5=92=8C=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../basic/stack/expr/InfixExpr.java | 83 ++++++++++++++++++ .../basic/stack/expr/InfixExprTest.java | 50 +++++++++++ .../minijvm/attr/AttributeInfo.java | 21 +++++ .../coding2017/minijvm/attr/CodeAttr.java | 85 +++++++++++++++++++ .../minijvm/attr/LineNumberTable.java | 53 ++++++++++++ .../minijvm/attr/LocalVariableItem.java | 39 +++++++++ .../minijvm/attr/LocalVariableTable.java | 41 +++++++++ .../minijvm/attr/StackMapTable.java | 29 +++++++ .../coding2017/minijvm/clz/ClassFile.java | 21 ++++- .../coding2017/minijvm/field/Field.java | 41 +++++++++ .../minijvm/loader/ByteCodeIterator.java | 3 + .../minijvm/loader/ClassFileParser.java | 29 +++++++ .../coding2017/minijvm/method/Method.java | 70 +++++++++++++++ .../minijvm/test/ClassFileloaderTest.java | 74 ++++++++++++++++ 14 files changed, 637 insertions(+), 2 deletions(-) create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/basic/stack/expr/InfixExpr.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/basic/stack/expr/InfixExprTest.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/AttributeInfo.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/CodeAttr.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/LineNumberTable.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/LocalVariableItem.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/LocalVariableTable.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/StackMapTable.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/field/Field.java create mode 100644 group24/121111914/src/com/github/ipk2015/coding2017/minijvm/method/Method.java diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/basic/stack/expr/InfixExpr.java b/group24/121111914/src/com/github/ipk2015/coding2017/basic/stack/expr/InfixExpr.java new file mode 100644 index 0000000000..1e597a2b24 --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/basic/stack/expr/InfixExpr.java @@ -0,0 +1,83 @@ +package com.github.ipk2015.coding2017.basic.stack.expr; + +import com.github.ipk2015.coding2017.basic.stack.Stack; + +public class InfixExpr { + String expr = null; + + public InfixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + String[] elements = getElementArray(expr); + + Stack numStack = new Stack(); + Stack operStack = new Stack(); + + manageMultiAndDivOper(elements,numStack,operStack); + + return manageAddAndMinusOper(numStack,operStack); + } + + private void manageMultiAndDivOper(String[] elements,Stack numStack,Stack operStack){ + float preElement,nextElement; + for(int i = 0; i < elements.length;i++){ + if(i%2 == 0){ + numStack.push(Float.valueOf(elements[i])); + }else{ + + if(elements[i].equals("+") || elements[i].equals("-")){ + operStack.push(elements[i]); + }else{ + preElement = (Float)numStack.pop(); + i++; + nextElement = Float.valueOf(elements[i]); + numStack.push(doBaseOper(preElement,nextElement,elements[i-1])); + } + } + } + } + + private float manageAddAndMinusOper(Stack numStack,Stack operStack){ + float result = 0f;; + while(!operStack.isEmpty()){ + result = doBaseOper(result,(Float)numStack.pop(),(String)operStack.pop()); + } + result += (Float)numStack.pop(); + return result; + } + + private float doBaseOper(float preData,float nextData,String oper){ + switch(oper){ + case "+": + return preData+nextData; + case "-": + return preData-nextData; + case "*": + return preData*nextData; + case "/": + return preData/nextData; + default: + throw new RuntimeException("could not recognise oper:"+oper); + } + } + + public String[] getElementArray(String expression){ + char[] charArray = expression.toCharArray(); + StringBuffer stringBuffer = new StringBuffer(); + + for(int i = 0;i<charArray.length;i++){ + if(charArray[i] == '+' || charArray[i] == '-' || charArray[i] == '*' || charArray[i] == '/'){ + stringBuffer.append(","+charArray[i]+","); + }else{ + stringBuffer.append(charArray[i]); + } + } + + return stringBuffer.toString().split(","); + } + + + +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/basic/stack/expr/InfixExprTest.java b/group24/121111914/src/com/github/ipk2015/coding2017/basic/stack/expr/InfixExprTest.java new file mode 100644 index 0000000000..c54188804f --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/basic/stack/expr/InfixExprTest.java @@ -0,0 +1,50 @@ +package com.github.ipk2015.coding2017.basic.stack.expr; + + + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class InfixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + //InfixExpr expr = new InfixExpr("300*20+12*5-20/4"); + { + InfixExpr expr = new InfixExpr("2+3*4+5"); + Assert.assertEquals(19.0, expr.evaluate(), 0.001f); + } + { + InfixExpr expr = new InfixExpr("3*20+12*5-40/2"); + Assert.assertEquals(100.0, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("3*20/2"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("20/2*3"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("10-30+50"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + } + +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/AttributeInfo.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/AttributeInfo.java new file mode 100644 index 0000000000..9bf9481980 --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/AttributeInfo.java @@ -0,0 +1,21 @@ +package com.github.ipk2015.coding2017.minijvm.attr; + + + +public abstract class AttributeInfo { + public static final String CODE = "Code"; + public static final String CONST_VALUE = "ConstantValue"; + public static final String EXCEPTIONS = "Exceptions"; + public static final String LINE_NUM_TABLE = "LineNumberTable"; + public static final String LOCAL_VAR_TABLE = "LocalVariableTable"; + public static final String STACK_MAP_TABLE = "StackMapTable"; + int attrNameIndex; + int attrLen ; + public AttributeInfo(int attrNameIndex, int attrLen) { + + this.attrNameIndex = attrNameIndex; + this.attrLen = attrLen; + } + + +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/CodeAttr.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/CodeAttr.java new file mode 100644 index 0000000000..2f141a20a3 --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/CodeAttr.java @@ -0,0 +1,85 @@ +package com.github.ipk2015.coding2017.minijvm.attr; + +import com.github.ipk2015.coding2017.minijvm.clz.ClassFile; +import com.github.ipk2015.coding2017.minijvm.loader.ByteCodeIterator; + +public class CodeAttr extends AttributeInfo { + private int maxStack ; + private int maxLocals ; + private int codeLen ; + private String code; + public String getCode() { + return code; + } + + //private ByteCodeCommand[] cmds ; + //public ByteCodeCommand[] getCmds() { + // return cmds; + //} + private LineNumberTable lineNumTable; + private LocalVariableTable localVarTable; + private StackMapTable stackMapTable; + + public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen,String code /*ByteCodeCommand[] cmds*/) { + super(attrNameIndex, attrLen); + this.maxStack = maxStack; + this.maxLocals = maxLocals; + this.codeLen = codeLen; + this.code = code; + //this.cmds = cmds; + } + + public void setLineNumberTable(LineNumberTable t) { + this.lineNumTable = t; + } + + public void setLocalVariableTable(LocalVariableTable t) { + this.localVarTable = t; + } + + public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ + int attrNameIndex = iter.nextUNToInt(2); + int attrLen = iter.nextUNToInt(4); + int maxStack = iter.nextUNToInt(2); + int maxLocals = iter.nextUNToInt(2); + int codeLen = iter.nextUNToInt(4); + String code = iter.nextUNToHexString(codeLen); + CodeAttr codeAttr = new CodeAttr(attrNameIndex,attrLen,maxStack,maxLocals,codeLen,code); + int exceptionTableLen = iter.nextUNToInt(2); + if(exceptionTableLen != 0){ + throw new RuntimeException("code属性里的异常table长度为:"+exceptionTableLen); + } + int attrCount = iter.nextUNToInt(2); + for(int i = 0;i<attrCount;i++){ + addSonAttr(clzFile,codeAttr,iter); + } + return codeAttr; + } + private void setStackMapTable(StackMapTable t) { + this.stackMapTable = t; + + } + private static void addSonAttr(ClassFile clzFile,CodeAttr codeAttr,ByteCodeIterator iter){ + int attrNameIndex = iter.nextUNToInt(2); + iter.back(2); + String name = clzFile.getConstantPool().getUTF8String(attrNameIndex); + switch(name){ + case AttributeInfo.LINE_NUM_TABLE: + codeAttr.setLineNumberTable(LineNumberTable.parse(iter)); + break; + case AttributeInfo.LOCAL_VAR_TABLE: + codeAttr.setLocalVariableTable(LocalVariableTable.parse(iter)); + break; + case AttributeInfo.STACK_MAP_TABLE: + codeAttr.setStackMapTable(StackMapTable.parse(iter)); + break; + default: + throw new RuntimeException("此属性不存在:"+name); + } + } + + + + + +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/LineNumberTable.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/LineNumberTable.java new file mode 100644 index 0000000000..42875581bd --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/LineNumberTable.java @@ -0,0 +1,53 @@ +package com.github.ipk2015.coding2017.minijvm.attr; + +import java.util.ArrayList; +import java.util.List; + +import com.github.ipk2015.coding2017.minijvm.loader.ByteCodeIterator; + + + +public class LineNumberTable extends AttributeInfo { + List<LineNumberItem> items = new ArrayList<LineNumberItem>(); + + private static class LineNumberItem{ + int startPC; + int lineNum; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLineNum() { + return lineNum; + } + public void setLineNum(int lineNum) { + this.lineNum = lineNum; + } + } + public void addLineNumberItem(LineNumberItem item){ + this.items.add(item); + } + public LineNumberTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + + } + + public static LineNumberTable parse(ByteCodeIterator iter){ + int attrNameIndex = iter.nextUNToInt(2); + int attrLength = iter.nextUNToInt(4); + LineNumberTable lineNumberTable = new LineNumberTable(attrNameIndex,attrLength); + int lineNumTableLen = iter.nextUNToInt(2); + for(int i = 0;i < lineNumTableLen;i++){ + LineNumberItem lineNumberItem = new LineNumberItem(); + lineNumberItem.setStartPC(iter.nextUNToInt(2)); + lineNumberItem.setLineNum(iter.nextUNToInt(2)); + lineNumberTable.addLineNumberItem(lineNumberItem); + } + return lineNumberTable; + } + + + +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/LocalVariableItem.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/LocalVariableItem.java new file mode 100644 index 0000000000..b1c6f61348 --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/LocalVariableItem.java @@ -0,0 +1,39 @@ +package com.github.ipk2015.coding2017.minijvm.attr; + +public class LocalVariableItem { + private int startPC; + private int length; + private int nameIndex; + private int descIndex; + private int index; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getNameIndex() { + return nameIndex; + } + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + public int getDescIndex() { + return descIndex; + } + public void setDescIndex(int descIndex) { + this.descIndex = descIndex; + } + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/LocalVariableTable.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/LocalVariableTable.java new file mode 100644 index 0000000000..d8c3563b2b --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/LocalVariableTable.java @@ -0,0 +1,41 @@ +package com.github.ipk2015.coding2017.minijvm.attr; + + +import java.util.ArrayList; +import java.util.List; + + +import com.github.ipk2015.coding2017.minijvm.loader.ByteCodeIterator; + + + +public class LocalVariableTable extends AttributeInfo{ + + List<LocalVariableItem> items = new ArrayList<LocalVariableItem>(); + + public LocalVariableTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static LocalVariableTable parse(ByteCodeIterator iter){ + int attrNameIndex = iter.nextUNToInt(2); + int attrLength = iter.nextUNToInt(4); + LocalVariableTable table = new LocalVariableTable(attrNameIndex,attrLength); + int tableLen = iter.nextUNToInt(2); + for(int i = 0;i < tableLen;i++){ + LocalVariableItem item = new LocalVariableItem(); + item.setStartPC(iter.nextUNToInt(2)); + item.setLength(iter.nextUNToInt(2)); + item.setNameIndex(iter.nextUNToInt(2)); + item.setDescIndex(iter.nextUNToInt(2)); + item.setIndex(iter.nextUNToInt(2)); + table.addLocalVariableItem(item); + } + return table; + } + private void addLocalVariableItem(LocalVariableItem item) { + this.items.add(item); + } + + +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/StackMapTable.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/StackMapTable.java new file mode 100644 index 0000000000..5d86caa022 --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/StackMapTable.java @@ -0,0 +1,29 @@ +package com.github.ipk2015.coding2017.minijvm.attr; + +import com.github.ipk2015.coding2017.minijvm.loader.ByteCodeIterator; + +public class StackMapTable extends AttributeInfo{ + + private String originalCode; + + public StackMapTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static StackMapTable parse(ByteCodeIterator iter){ + int index = iter.nextUNToInt(2); + int len = iter.nextUNToInt(4); + StackMapTable t = new StackMapTable(index,len); + + //后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 + String code = iter.nextUNToHexString(len); + t.setOriginalCode(code); + + return t; + } + + private void setOriginalCode(String code) { + this.originalCode = code; + + } +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/clz/ClassFile.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/clz/ClassFile.java index 4b64635076..5cecfc3bff 100644 --- a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/clz/ClassFile.java +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/clz/ClassFile.java @@ -1,7 +1,12 @@ package com.github.ipk2015.coding2017.minijvm.clz; +import java.util.ArrayList; +import java.util.List; + import com.github.ipk2015.coding2017.minijvm.constant.ClassInfo; import com.github.ipk2015.coding2017.minijvm.constant.ConstantPool; +import com.github.ipk2015.coding2017.minijvm.field.Field; +import com.github.ipk2015.coding2017.minijvm.method.Method; public class ClassFile { @@ -11,7 +16,8 @@ public class ClassFile { private AccessFlag accessFlag; private ClassIndex clzIndex; private ConstantPool pool; - + private List<Field> fields = new ArrayList<Field>(); + private List<Method> methods = new ArrayList<Method>(); public ClassIndex getClzIndex() { return clzIndex; @@ -48,7 +54,18 @@ public void setClassIndex(ClassIndex clzIndex) { this.clzIndex = clzIndex; } - + public void addField(Field f){ + this.fields.add(f); + } + public List<Field> getFields(){ + return this.fields; + } + public void addMethod(Method m){ + this.methods.add(m); + } + public List<Method> getMethods() { + return methods; + } public void print(){ diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/field/Field.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/field/Field.java new file mode 100644 index 0000000000..37757878d6 --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/field/Field.java @@ -0,0 +1,41 @@ +package com.github.ipk2015.coding2017.minijvm.field; + +import com.github.ipk2015.coding2017.minijvm.constant.ConstantPool; +import com.github.ipk2015.coding2017.minijvm.loader.ByteCodeIterator; + +public class Field { + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + + + private ConstantPool pool; + + public Field( int accessFlag, int nameIndex, int descriptorIndex,ConstantPool pool) { + + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + this.pool = pool; + } + + + + + public static Field parse(ConstantPool pool,ByteCodeIterator iter){ + int accessFlag = iter.nextUNToInt(2); + int nameIndex = iter.nextUNToInt(2); + int descriptorIndex = iter.nextUNToInt(2); + int attrCount = iter.nextUNToInt(2); + if(attrCount != 0){ + throw new RuntimeException("字段的属性不为0"); + } + return new Field(accessFlag,nameIndex,descriptorIndex,pool); + } + + public String toString(){ + + return pool.getUTF8String(nameIndex)+":"+pool.getUTF8String(descriptorIndex); + } +} 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 index 85e970c64a..141331fe4b 100644 --- a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ByteCodeIterator.java +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ByteCodeIterator.java @@ -25,4 +25,7 @@ public byte[] nextUNToArray(int n){ pos=pos+n; return bytes; } + public void back(int n) { + this.pos -= n; + } } diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ClassFileParser.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ClassFileParser.java index bdbbb66271..5cce919b29 100644 --- a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ClassFileParser.java +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ClassFileParser.java @@ -17,6 +17,8 @@ import com.github.ipk2015.coding2017.minijvm.constant.NullConstantInfo; import com.github.ipk2015.coding2017.minijvm.constant.StringInfo; import com.github.ipk2015.coding2017.minijvm.constant.UTF8Info; +import com.github.ipk2015.coding2017.minijvm.field.Field; +import com.github.ipk2015.coding2017.minijvm.method.Method; import com.github.ipk2015.coding2017.minijvm.util.Util; @@ -44,6 +46,12 @@ public ClassFile parse(byte[] codes) { ClassIndex classIndex = parseClassInfex(iterator); classFile.setClassIndex(classIndex); + parseInterfaces(iterator); + + parseFields(classFile,constantPool,iterator); + + parseMethods(classFile,iterator); + return classFile; } @@ -145,5 +153,26 @@ private void meetUTF8Info(ConstantPool pool,ByteCodeIterator iter){ pool.addConstantInfo(info); } + private void parseInterfaces(ByteCodeIterator iter) { + int interfaceCount = iter.nextUNToInt(2); + + System.out.println("interfaceCount:" + interfaceCount); + + // TODO : 如果实现了interface, 这里需要解析 + } + + private void parseFields(ClassFile classFile,ConstantPool pool,ByteCodeIterator iter){ + int count = iter.nextUNToInt(2); + for(int i = 0;i < count;i++){ + classFile.addField(Field.parse(pool, iter)); + } + } + + private void parseMethods(ClassFile classFile,ByteCodeIterator iter){ + int count = iter.nextUNToInt(2); + for(int i = 0;i < count;i++){ + classFile.addMethod(Method.parse(classFile, iter)); + } + } } diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/method/Method.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/method/Method.java new file mode 100644 index 0000000000..3298a36d6b --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/method/Method.java @@ -0,0 +1,70 @@ +package com.github.ipk2015.coding2017.minijvm.method; + +import com.github.ipk2015.coding2017.minijvm.attr.AttributeInfo; +import com.github.ipk2015.coding2017.minijvm.attr.CodeAttr; +import com.github.ipk2015.coding2017.minijvm.clz.ClassFile; +import com.github.ipk2015.coding2017.minijvm.loader.ByteCodeIterator; + +public class Method { + + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private CodeAttr codeAttr; + + private ClassFile clzFile; + + + public ClassFile getClzFile() { + return clzFile; + } + + public int getNameIndex() { + return nameIndex; + } + public int getDescriptorIndex() { + return descriptorIndex; + } + + public CodeAttr getCodeAttr() { + return codeAttr; + } + + public void setCodeAttr(CodeAttr code) { + this.codeAttr = code; + } + + public Method(ClassFile clzFile,int accessFlag, int nameIndex, int descriptorIndex) { + this.clzFile = clzFile; + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + } + + + + + + public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ + int accessFlag = iter.nextUNToInt(2); + int nameIndex = iter.nextUNToInt(2); + int descriptorIndex = iter.nextUNToInt(2); + Method method = new Method(clzFile,accessFlag,nameIndex,descriptorIndex); + int attrCount = iter.nextUNToInt(2); + for(int i = 0;i < attrCount;i++){ + addAttr(clzFile,method,iter); + } + return method; + } + private static void addAttr(ClassFile clzFile,Method method,ByteCodeIterator iter){ + int nameIndex = iter.nextUNToInt(2); + iter.back(2); + String attrName = clzFile.getConstantPool().getUTF8String(nameIndex); + if(AttributeInfo.CODE.equalsIgnoreCase(attrName)){ + method.setCodeAttr(CodeAttr.parse(clzFile, iter)); + }else{ + throw new RuntimeException("方法的此属性不存在:"+attrName); + } + } +} 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 index 911b8356a7..0a3979119d 100644 --- a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/test/ClassFileloaderTest.java +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/test/ClassFileloaderTest.java @@ -3,6 +3,7 @@ import java.io.IOException; +import java.util.List; import org.junit.After; import org.junit.Assert; @@ -16,8 +17,10 @@ import com.github.ipk2015.coding2017.minijvm.constant.MethodRefInfo; import com.github.ipk2015.coding2017.minijvm.constant.NameAndTypeInfo; import com.github.ipk2015.coding2017.minijvm.constant.UTF8Info; +import com.github.ipk2015.coding2017.minijvm.field.Field; import com.github.ipk2015.coding2017.minijvm.loader.ClassFileLoader; import com.github.ipk2015.coding2017.minijvm.loader.ClassFileLoader1; +import com.github.ipk2015.coding2017.minijvm.method.Method; @@ -205,5 +208,76 @@ public void testClassIndex(){ Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); } + /** + * 下面是第三次JVM课应实现的测试用例 + */ + @Test + public void testReadFields(){ + + List<Field> fields = clzFile.getFields(); + Assert.assertEquals(2, fields.size()); + { + Field f = fields.get(0); + Assert.assertEquals("name:Ljava/lang/String;", f.toString()); + } + { + Field f = fields.get(1); + Assert.assertEquals("age:I", f.toString()); + } + } + @Test + public void testMethods(){ + + List<Method> methods = clzFile.getMethods(); + ConstantPool pool = clzFile.getConstantPool(); + + { + Method m = methods.get(0); + assertMethodEquals(pool,m, + "<init>", + "(Ljava/lang/String;I)V", + "2ab7000c2a2bb5000f2a1cb50011b1"); + + } + { + Method m = methods.get(1); + assertMethodEquals(pool,m, + "setName", + "(Ljava/lang/String;)V", + "2a2bb5000fb1"); + + } + { + Method m = methods.get(2); + assertMethodEquals(pool,m, + "setAge", + "(I)V", + "2a1bb50011b1"); + } + { + Method m = methods.get(3); + assertMethodEquals(pool,m, + "sayHello", + "()V", + "b2001c1222b60024b1"); + + } + { + Method m = methods.get(4); + assertMethodEquals(pool,m, + "main", + "([Ljava/lang/String;)V", + "bb000159122b101db7002d4c2bb6002fb1"); + } + } + + private void assertMethodEquals(ConstantPool pool,Method m , String expectedName, String expectedDesc,String expectedCode){ + String methodName = pool.getUTF8String(m.getNameIndex()); + String methodDesc = pool.getUTF8String(m.getDescriptorIndex()); + String code = m.getCodeAttr().getCode(); + Assert.assertEquals(expectedName, methodName); + Assert.assertEquals(expectedDesc, methodDesc); + Assert.assertEquals(expectedCode, code); + } } From 9511be83bd70dd747c066f80fa063ebc6a028927 Mon Sep 17 00:00:00 2001 From: Haochen <haochen_233333@163.com> Date: Wed, 12 Apr 2017 21:27:28 +0800 Subject: [PATCH 241/287] finish fields loading --- .../src/main/java/jvm/attr/AttributeInfo.java | 9 +-- .../main/java/jvm/attr/AttributeParser.java | 32 ++++++++ .../code/src/main/java/jvm/attr/CodeAttr.java | 65 ++++++++-------- .../main/java/jvm/attr/LineNumberTable.java | 42 ----------- .../java/jvm/attr/LineNumberTableAttr.java | 52 +++++++++++++ .../java/jvm/attr/LocalVariableTable.java | 26 ------- .../java/jvm/attr/LocalVariableTableAttr.java | 75 +++++++++++++++++++ .../src/main/java/jvm/attr/StackMapTable.java | 28 ------- .../main/java/jvm/attr/StackMapTableAttr.java | 28 +++++++ .../main/java/jvm/classfile/ClassFile.java | 4 +- .../main/java/jvm/classfile/ClassParser.java | 21 ++++++ .../code/src/main/java/jvm/field/Field.java | 36 +++++++-- .../code/src/main/java/jvm/method/Method.java | 12 +-- .../test/java/jvm/ClassFileLoaderTest.java | 36 ++++----- 14 files changed, 302 insertions(+), 164 deletions(-) create mode 100644 group01/895457260/code/src/main/java/jvm/attr/AttributeParser.java delete mode 100644 group01/895457260/code/src/main/java/jvm/attr/LineNumberTable.java create mode 100644 group01/895457260/code/src/main/java/jvm/attr/LineNumberTableAttr.java delete mode 100644 group01/895457260/code/src/main/java/jvm/attr/LocalVariableTable.java create mode 100644 group01/895457260/code/src/main/java/jvm/attr/LocalVariableTableAttr.java delete mode 100644 group01/895457260/code/src/main/java/jvm/attr/StackMapTable.java create mode 100644 group01/895457260/code/src/main/java/jvm/attr/StackMapTableAttr.java diff --git a/group01/895457260/code/src/main/java/jvm/attr/AttributeInfo.java b/group01/895457260/code/src/main/java/jvm/attr/AttributeInfo.java index 838d0b0852..1ae5cb4c53 100644 --- a/group01/895457260/code/src/main/java/jvm/attr/AttributeInfo.java +++ b/group01/895457260/code/src/main/java/jvm/attr/AttributeInfo.java @@ -7,13 +7,12 @@ public abstract class AttributeInfo { public static final String LINE_NUM_TABLE = "LineNumberTable"; public static final String LOCAL_VAR_TABLE = "LocalVariableTable"; public static final String STACK_MAP_TABLE = "StackMapTable"; + int attrNameIndex; - int attrLen ; - public AttributeInfo(int attrNameIndex, int attrLen) { - + int attrLen; + + AttributeInfo(int attrNameIndex, int attrLen) { this.attrNameIndex = attrNameIndex; this.attrLen = attrLen; } - - } diff --git a/group01/895457260/code/src/main/java/jvm/attr/AttributeParser.java b/group01/895457260/code/src/main/java/jvm/attr/AttributeParser.java new file mode 100644 index 0000000000..6f4b6c29fe --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/attr/AttributeParser.java @@ -0,0 +1,32 @@ +package jvm.attr; + +import jvm.classfile.ConstantPool; +import jvm.classfile.constant.item.impl.UTF8Info; +import jvm.util.ByteCodeIterator; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Created by Haochen on 2017/4/12. + * TODO: + */ +public class AttributeParser { + public static AttributeInfo parse(ByteCodeIterator iterator, ConstantPool constantPool) { + int nameIndex = iterator.nextU2ToInt(); + String name = ((UTF8Info) constantPool.getConstantInfo(nameIndex)).getValue(); + int length = iterator.nextU4ToInt(); + + String className = AttributeParser.class.getPackage().getName() + '.' + name + "Attr"; + try { + Class<?> clazz = Class.forName(className); + Method parse = clazz.getMethod("parse", ByteCodeIterator.class, ConstantPool.class); + byte[] bytes = iterator.getBytes(length); + ByteCodeIterator subIterator = new ByteCodeIterator(bytes); + return (AttributeInfo) parse.invoke(null, nameIndex, length, subIterator, constantPool); + } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/attr/CodeAttr.java b/group01/895457260/code/src/main/java/jvm/attr/CodeAttr.java index e9384082a4..b5f64f515b 100644 --- a/group01/895457260/code/src/main/java/jvm/attr/CodeAttr.java +++ b/group01/895457260/code/src/main/java/jvm/attr/CodeAttr.java @@ -1,26 +1,25 @@ package jvm.attr; -import jvm.classfile.ClassFile; +import jvm.classfile.ConstantPool; import jvm.util.ByteCodeIterator; +import java.util.ArrayList; +import java.util.List; + public class CodeAttr extends AttributeInfo { - private int maxStack ; - private int maxLocals ; - private int codeLen ; + private int maxStack; + private int maxLocals; + private int codeLen; private String code; - public String getCode() { - return code; - } - + private List<AttributeInfo> attributes = new ArrayList<>(); //private ByteCodeCommand[] cmds ; + //public ByteCodeCommand[] getCmds() { // return cmds; //} - private LineNumberTable lineNumTable; - private LocalVariableTable localVarTable; - private StackMapTable stackMapTable; - - public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen,String code /*ByteCodeCommand[] cmds*/) { + + private CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, + int codeLen, String code /*ByteCodeCommand[] cmds*/) { super(attrNameIndex, attrLen); this.maxStack = maxStack; this.maxLocals = maxLocals; @@ -29,26 +28,30 @@ public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int //this.cmds = cmds; } - public void setLineNumberTable(LineNumberTable t) { - this.lineNumTable = t; - } + public static CodeAttr parse(int attrNameIndex, int attrLen, + ByteCodeIterator iterator, ConstantPool constantPool) { + int maxStack = iterator.nextU2ToInt(); + int maxLocals = iterator.nextU2ToInt(); + int codeLen = iterator.nextU4ToInt(); + String code = new String(iterator.getBytes(codeLen)); - public void setLocalVariableTable(LocalVariableTable t) { - this.localVarTable = t; - } - - public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ - - - return null; + int exceptionTableLen = iterator.nextU2ToInt(); + iterator.skip(exceptionTableLen * 8); + + CodeAttr result = new CodeAttr(attrNameIndex, attrLen, maxStack, maxLocals, codeLen, code); + + int attrCount = iterator.nextU2ToInt(); + for (int i = 0; i < attrCount; ++i) { + result.attributes.add(AttributeParser.parse(iterator, constantPool)); + } + return result; } - private void setStackMapTable(StackMapTable t) { - this.stackMapTable = t; - + + public String getCode() { + return code; } - - - - + public List<AttributeInfo> getAttributes() { + return attributes; + } } diff --git a/group01/895457260/code/src/main/java/jvm/attr/LineNumberTable.java b/group01/895457260/code/src/main/java/jvm/attr/LineNumberTable.java deleted file mode 100644 index e31d86525e..0000000000 --- a/group01/895457260/code/src/main/java/jvm/attr/LineNumberTable.java +++ /dev/null @@ -1,42 +0,0 @@ -package jvm.attr; - -import jvm.util.ByteCodeIterator; - -import java.util.ArrayList; -import java.util.List; - -public class LineNumberTable extends AttributeInfo { - List<LineNumberItem> items = new ArrayList<LineNumberItem>(); - - private static class LineNumberItem{ - int startPC; - int lineNum; - public int getStartPC() { - return startPC; - } - public void setStartPC(int startPC) { - this.startPC = startPC; - } - public int getLineNum() { - return lineNum; - } - public void setLineNum(int lineNum) { - this.lineNum = lineNum; - } - } - public void addLineNumberItem(LineNumberItem item){ - this.items.add(item); - } - public LineNumberTable(int attrNameIndex, int attrLen) { - super(attrNameIndex, attrLen); - - } - - public static LineNumberTable parse(ByteCodeIterator iter){ - - return null; - } - - - -} diff --git a/group01/895457260/code/src/main/java/jvm/attr/LineNumberTableAttr.java b/group01/895457260/code/src/main/java/jvm/attr/LineNumberTableAttr.java new file mode 100644 index 0000000000..ab7a9d6adb --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/attr/LineNumberTableAttr.java @@ -0,0 +1,52 @@ +package jvm.attr; + +import jvm.classfile.ConstantPool; +import jvm.util.ByteCodeIterator; + +import java.util.ArrayList; +import java.util.List; + +public class LineNumberTableAttr extends AttributeInfo { + private List<LineNumberItem> items = new ArrayList<>(); + + private LineNumberTableAttr(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static LineNumberTableAttr parse(int attrNameIndex, int attrLen, + ByteCodeIterator iterator, ConstantPool constantPool) { + int tableLength = iterator.nextU2ToInt(); + + LineNumberTableAttr result = new LineNumberTableAttr(attrNameIndex, attrLen); + + for (int i = 0; i < tableLength; ++i) { + int startPC = iterator.nextU2ToInt(); + int lineNumber = iterator.nextU2ToInt(); + LineNumberItem item = new LineNumberItem(startPC, lineNumber); + result.items.add(item); + } + return result; + } + + public List<LineNumberItem> getItems() { + return items; + } + + public static class LineNumberItem { + private int startPc; + private int lineNumber; + + private LineNumberItem(int startPc, int lineNumber) { + this.startPc = startPc; + this.lineNumber = lineNumber; + } + + public int getStartPc() { + return startPc; + } + + public int getLineNumber() { + return lineNumber; + } + } +} diff --git a/group01/895457260/code/src/main/java/jvm/attr/LocalVariableTable.java b/group01/895457260/code/src/main/java/jvm/attr/LocalVariableTable.java deleted file mode 100644 index fef46e9709..0000000000 --- a/group01/895457260/code/src/main/java/jvm/attr/LocalVariableTable.java +++ /dev/null @@ -1,26 +0,0 @@ -package jvm.attr; - - -import jvm.util.ByteCodeIterator; - -import java.util.ArrayList; -import java.util.List; - -public class LocalVariableTable extends AttributeInfo{ - - List<LocalVariableItem> items = new ArrayList<LocalVariableItem>(); - - public LocalVariableTable(int attrNameIndex, int attrLen) { - super(attrNameIndex, attrLen); - } - - public static LocalVariableTable parse(ByteCodeIterator iter){ - - return null; - } - private void addLocalVariableItem(LocalVariableItem item) { - this.items.add(item); - } - - -} diff --git a/group01/895457260/code/src/main/java/jvm/attr/LocalVariableTableAttr.java b/group01/895457260/code/src/main/java/jvm/attr/LocalVariableTableAttr.java new file mode 100644 index 0000000000..1d2f4e9f31 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/attr/LocalVariableTableAttr.java @@ -0,0 +1,75 @@ +package jvm.attr; + + +import jvm.classfile.ConstantPool; +import jvm.util.ByteCodeIterator; + +import java.util.ArrayList; +import java.util.List; + +public class LocalVariableTableAttr extends AttributeInfo { + + List<LocalVariableItem> items = new ArrayList<>(); + + public LocalVariableTableAttr(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static LocalVariableTableAttr parse(int attrNameIndex, int attrLen, + ByteCodeIterator iterator, ConstantPool constantPool) { + int tableLen = iterator.nextU2ToInt(); + + LocalVariableTableAttr result = new LocalVariableTableAttr(attrNameIndex, attrLen); + + for (int i = 0; i < tableLen; ++i) { + int startPC = iterator.nextU2ToInt(); + int length = iterator.nextU2ToInt(); + int nameIndex = iterator.nextU2ToInt(); + int descIndex = iterator.nextU2ToInt(); + int index = iterator.nextU2ToInt(); + LocalVariableItem item = new LocalVariableItem(startPC, length, nameIndex, descIndex, index); + result.items.add(item); + } + return result; + } + + private void addLocalVariableItem(LocalVariableItem item) { + this.items.add(item); + } + + public static class LocalVariableItem { + private int startPC; + private int length; + private int nameIndex; + private int descIndex; + private int index; + + private LocalVariableItem(int startPC, int length, int nameIndex, int descIndex, int index) { + this.startPC = startPC; + this.length = length; + this.nameIndex = nameIndex; + this.descIndex = descIndex; + this.index = index; + } + + public int getStartPC() { + return startPC; + } + + public int getLength() { + return length; + } + + public int getNameIndex() { + return nameIndex; + } + + public int getDescIndex() { + return descIndex; + } + + public int getIndex() { + return index; + } + } +} diff --git a/group01/895457260/code/src/main/java/jvm/attr/StackMapTable.java b/group01/895457260/code/src/main/java/jvm/attr/StackMapTable.java deleted file mode 100644 index 7bf883ff21..0000000000 --- a/group01/895457260/code/src/main/java/jvm/attr/StackMapTable.java +++ /dev/null @@ -1,28 +0,0 @@ -package jvm.attr; - -import jvm.util.ByteCodeIterator; - -public class StackMapTable extends AttributeInfo{ - - private String originalCode; - - public StackMapTable(int attrNameIndex, int attrLen) { - super(attrNameIndex, attrLen); - } - - public static StackMapTable parse(ByteCodeIterator iter){ - int index = iter.nextU2ToInt(); - int len = iter.nextU4ToInt(); - StackMapTable t = new StackMapTable(index,len); - - //后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 - String code = iter.nextHexString(len); - t.setOriginalCode(code); - - return t; - } - - private void setOriginalCode(String code) { - this.originalCode = code; - } -} diff --git a/group01/895457260/code/src/main/java/jvm/attr/StackMapTableAttr.java b/group01/895457260/code/src/main/java/jvm/attr/StackMapTableAttr.java new file mode 100644 index 0000000000..e9a1b6987c --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/attr/StackMapTableAttr.java @@ -0,0 +1,28 @@ +package jvm.attr; + +import jvm.util.ByteCodeIterator; + +public class StackMapTableAttr extends AttributeInfo{ + + private String originalCode; + + private StackMapTableAttr(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static StackMapTableAttr parse(ByteCodeIterator iterator) { + int index = iterator.nextU2ToInt(); + int len = iterator.nextU4ToInt(); + StackMapTableAttr result = new StackMapTableAttr(index, len); + + //后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 + String code = iterator.nextHexString(len); + result.setOriginalCode(code); + + return result; + } + + private void setOriginalCode(String code) { + this.originalCode = code; + } +} 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 0f0d24aaa4..3f3fe9112d 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/ClassFile.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/ClassFile.java @@ -18,8 +18,8 @@ public class ClassFile { ConstantPool constantPool; int minorVersion; int majorVersion; - private List<Field> fields = new ArrayList<>(); - private List<Method> methods = new ArrayList<>(); + List<Field> fields = new ArrayList<>(); + List<Method> methods = new ArrayList<>(); public void addField(Field f){ this.fields.add(f); 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 e46705f4b8..1a3e74405c 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/ClassParser.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/ClassParser.java @@ -4,8 +4,12 @@ import jvm.classfile.constant.item.impl.CountConstant; import jvm.classfile.constant.parser.ConstantParser; import jvm.classfile.constant.parser.ConstantParserFactory; +import jvm.field.Field; +import jvm.method.Method; import jvm.util.ByteCodeIterator; +import java.util.Collection; + /** * Created by Haochen on 2017/4/9. * TODO: @@ -22,6 +26,9 @@ public static ClassFile parse(byte[] bytes) { classFile.constantPool = parseConstantPool(iterator); classFile.accessFlag = parseAccessFlag(iterator); classFile.classIndex = parseClassIndex(iterator); + parseInterfaces(iterator); + parseFields(classFile, iterator); + parseMethods(classFile, iterator); linkConstantReferences(classFile); return classFile; } @@ -61,6 +68,20 @@ private static ClassIndex parseClassIndex(ByteCodeIterator iterator) { return classIndex; } + private static void parseInterfaces(ByteCodeIterator iterator) { + int count = iterator.nextU2ToInt(); + iterator.skip(count * 2); + } + + private static void parseFields(ClassFile classFile, ByteCodeIterator iterator) { + int count = iterator.nextU2ToInt(); + for (int i = 0; i < count; ++i) { + classFile.fields.add(Field.parse(classFile.constantPool, iterator)); + } + } + + private static void parseMethods(ClassFile classFile, ByteCodeIterator iterator) {} + private static void linkConstantReferences(ClassFile classFile) { ConstantPool constantPool = classFile.constantPool; constantPool.forEach(c -> { diff --git a/group01/895457260/code/src/main/java/jvm/field/Field.java b/group01/895457260/code/src/main/java/jvm/field/Field.java index f5eaaf4f86..ad923733d5 100644 --- a/group01/895457260/code/src/main/java/jvm/field/Field.java +++ b/group01/895457260/code/src/main/java/jvm/field/Field.java @@ -1,24 +1,48 @@ package jvm.field; +import jvm.attr.AttributeInfo; +import jvm.attr.AttributeParser; import jvm.classfile.ConstantPool; +import jvm.classfile.constant.item.impl.UTF8Info; import jvm.util.ByteCodeIterator; +import java.util.ArrayList; +import java.util.List; + public class Field { private int accessFlag; private int nameIndex; private int descriptorIndex; - private ConstantPool pool; + private ConstantPool constantPool; + + private List<AttributeInfo> attributes; - public Field( int accessFlag, int nameIndex, int descriptorIndex,ConstantPool pool) { - + public Field(int accessFlag, int nameIndex, int descriptorIndex, + ConstantPool constantPool, List<AttributeInfo> attributes) { this.accessFlag = accessFlag; this.nameIndex = nameIndex; this.descriptorIndex = descriptorIndex; - this.pool = pool; + this.constantPool = constantPool; + this.attributes = attributes; + } + + public static Field parse(ConstantPool constantPool, ByteCodeIterator iterator) { + int access = iterator.nextU2ToInt(); + int name = iterator.nextU2ToInt(); + int descriptor = iterator.nextU2ToInt(); + int attrCount = iterator.nextU2ToInt(); + List<AttributeInfo> attributes = new ArrayList<>(); + for (int i = 0; i < attrCount; ++i) { + attributes.add(AttributeParser.parse(iterator, constantPool)); + } + return new Field(access, name, descriptor, constantPool, attributes); } - public static Field parse(ConstantPool pool, ByteCodeIterator iter){ - return null; + @Override + public String toString() { + String name = ((UTF8Info) constantPool.getConstantInfo(nameIndex)).getValue(); + String desc = ((UTF8Info) constantPool.getConstantInfo(descriptorIndex)).getValue(); + return name + ":" + desc; } } diff --git a/group01/895457260/code/src/main/java/jvm/method/Method.java b/group01/895457260/code/src/main/java/jvm/method/Method.java index 8ba1c3d96c..e087ea24ab 100644 --- a/group01/895457260/code/src/main/java/jvm/method/Method.java +++ b/group01/895457260/code/src/main/java/jvm/method/Method.java @@ -10,12 +10,9 @@ public class Method { private int accessFlag; private int nameIndex; private int descriptorIndex; - private CodeAttr codeAttr; - private ClassFile clzFile; - - + public ClassFile getClzFile() { return clzFile; } @@ -42,7 +39,10 @@ public Method(ClassFile clzFile,int accessFlag, int nameIndex, int descriptorInd this.descriptorIndex = descriptorIndex; } - public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ - return null; + public static Method parse(ClassFile clzFile, ByteCodeIterator iterator) { + int access = iterator.nextU2ToInt(); + int name = iterator.nextU2ToInt(); + int descriptor = iterator.nextU2ToInt(); + return new Method(clzFile, access, name, descriptor); } } diff --git a/group01/895457260/code/src/test/java/jvm/ClassFileLoaderTest.java b/group01/895457260/code/src/test/java/jvm/ClassFileLoaderTest.java index 4f24bf938c..d4bfe0c91b 100644 --- a/group01/895457260/code/src/test/java/jvm/ClassFileLoaderTest.java +++ b/group01/895457260/code/src/test/java/jvm/ClassFileLoaderTest.java @@ -164,24 +164,24 @@ public void testClassIndex() { Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); } -// /** -// * 下面是第三次JVM课应实现的测试用例 -// */ -// @Test -// public void testReadFields() { -// -// List<Field> fields = clzFile.getFields(); -// Assert.assertEquals(2, fields.size()); -// { -// Field f = fields.get(0); -// Assert.assertEquals("name:Ljava/lang/String;", f.toString()); -// } -// { -// Field f = fields.get(1); -// Assert.assertEquals("age:I", f.toString()); -// } -// } -// + /** + * 下面是第三次JVM课应实现的测试用例 + */ + @Test + public void testReadFields() { + + List<Field> fields = clzFile.getFields(); + Assert.assertEquals(2, fields.size()); + { + Field f = fields.get(0); + Assert.assertEquals("name:Ljava/lang/String;", f.toString()); + } + { + Field f = fields.get(1); + Assert.assertEquals("age:I", f.toString()); + } + } + // @Test // public void testMethods() { // From 55cf882e63d9be842245278c92fcd00531471cf5 Mon Sep 17 00:00:00 2001 From: Haochen <haochen_233333@163.com> Date: Wed, 12 Apr 2017 21:52:21 +0800 Subject: [PATCH 242/287] change fields loading --- .../code/src/main/java/jvm/field/Field.java | 37 ++++++++++++++----- .../code/src/test/java/jvm/EmployeeV1.java | 31 ++++++++-------- 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/group01/895457260/code/src/main/java/jvm/field/Field.java b/group01/895457260/code/src/main/java/jvm/field/Field.java index ad923733d5..4093449356 100644 --- a/group01/895457260/code/src/main/java/jvm/field/Field.java +++ b/group01/895457260/code/src/main/java/jvm/field/Field.java @@ -13,30 +13,27 @@ public class Field { private int accessFlag; private int nameIndex; private int descriptorIndex; - private ConstantPool constantPool; - - private List<AttributeInfo> attributes; + private List<AttributeInfo> attributes = new ArrayList<>(); - public Field(int accessFlag, int nameIndex, int descriptorIndex, - ConstantPool constantPool, List<AttributeInfo> attributes) { + public Field(int accessFlag, int nameIndex, int descriptorIndex, ConstantPool constantPool) { this.accessFlag = accessFlag; this.nameIndex = nameIndex; this.descriptorIndex = descriptorIndex; this.constantPool = constantPool; - this.attributes = attributes; } - public static Field parse(ConstantPool constantPool, ByteCodeIterator iterator) { + public static Field parse(ByteCodeIterator iterator, ConstantPool constantPool) { int access = iterator.nextU2ToInt(); int name = iterator.nextU2ToInt(); int descriptor = iterator.nextU2ToInt(); int attrCount = iterator.nextU2ToInt(); - List<AttributeInfo> attributes = new ArrayList<>(); + + Field result = new Field(access, name, descriptor, constantPool); for (int i = 0; i < attrCount; ++i) { - attributes.add(AttributeParser.parse(iterator, constantPool)); + result.attributes.add(AttributeParser.parse(iterator, constantPool)); } - return new Field(access, name, descriptor, constantPool, attributes); + return result; } @Override @@ -45,4 +42,24 @@ public String toString() { String desc = ((UTF8Info) constantPool.getConstantInfo(descriptorIndex)).getValue(); return name + ":" + desc; } + + public int getAccessFlag() { + return accessFlag; + } + + public int getNameIndex() { + return nameIndex; + } + + public int getDescriptorIndex() { + return descriptorIndex; + } + + public ConstantPool getConstantPool() { + return constantPool; + } + + public List<AttributeInfo> getAttributes() { + return attributes; + } } diff --git a/group01/895457260/code/src/test/java/jvm/EmployeeV1.java b/group01/895457260/code/src/test/java/jvm/EmployeeV1.java index 0ab0e5bd1f..12e3d7efdd 100644 --- a/group01/895457260/code/src/test/java/jvm/EmployeeV1.java +++ b/group01/895457260/code/src/test/java/jvm/EmployeeV1.java @@ -1,29 +1,28 @@ -package jvm; +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 void setName(String name) { this.name = name; } - - public void setAge(int age) { - this.age = age; + public void setAge(int age){ + this.age = age; } - - public void sayHello() { - System.out.println("Hello , this is class Employee "); + 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(); + public static void main(String[] args){ + EmployeeV1 p = new EmployeeV1("Andy",29); + p.sayHello(); + } } \ No newline at end of file From 468bfceb718193d3fa52cf3127285037e330628c Mon Sep 17 00:00:00 2001 From: Haochen <haochen_233333@163.com> Date: Wed, 12 Apr 2017 21:53:56 +0800 Subject: [PATCH 243/287] finish methods loading --- .../main/java/jvm/attr/AttributeParser.java | 3 +- .../code/src/main/java/jvm/attr/CodeAttr.java | 2 +- .../main/java/jvm/classfile/ClassParser.java | 9 ++- .../code/src/main/java/jvm/method/Method.java | 60 +++++++++++-------- .../main/java/jvm/util/ByteCodeIterator.java | 2 +- .../code/src/test/java/jvm/EmployeeV1.java | 2 +- 6 files changed, 47 insertions(+), 31 deletions(-) diff --git a/group01/895457260/code/src/main/java/jvm/attr/AttributeParser.java b/group01/895457260/code/src/main/java/jvm/attr/AttributeParser.java index 6f4b6c29fe..d389b71ef3 100644 --- a/group01/895457260/code/src/main/java/jvm/attr/AttributeParser.java +++ b/group01/895457260/code/src/main/java/jvm/attr/AttributeParser.java @@ -20,7 +20,8 @@ public static AttributeInfo parse(ByteCodeIterator iterator, ConstantPool consta String className = AttributeParser.class.getPackage().getName() + '.' + name + "Attr"; try { Class<?> clazz = Class.forName(className); - Method parse = clazz.getMethod("parse", ByteCodeIterator.class, ConstantPool.class); + Method parse = clazz.getMethod("parse", + int.class, int.class, ByteCodeIterator.class, ConstantPool.class); byte[] bytes = iterator.getBytes(length); ByteCodeIterator subIterator = new ByteCodeIterator(bytes); return (AttributeInfo) parse.invoke(null, nameIndex, length, subIterator, constantPool); diff --git a/group01/895457260/code/src/main/java/jvm/attr/CodeAttr.java b/group01/895457260/code/src/main/java/jvm/attr/CodeAttr.java index b5f64f515b..7c7966f149 100644 --- a/group01/895457260/code/src/main/java/jvm/attr/CodeAttr.java +++ b/group01/895457260/code/src/main/java/jvm/attr/CodeAttr.java @@ -33,7 +33,7 @@ public static CodeAttr parse(int attrNameIndex, int attrLen, int maxStack = iterator.nextU2ToInt(); int maxLocals = iterator.nextU2ToInt(); int codeLen = iterator.nextU4ToInt(); - String code = new String(iterator.getBytes(codeLen)); + String code = iterator.nextHexString(codeLen); int exceptionTableLen = iterator.nextU2ToInt(); iterator.skip(exceptionTableLen * 8); 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 1a3e74405c..7d9ff72eb4 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/ClassParser.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/ClassParser.java @@ -76,11 +76,16 @@ private static void parseInterfaces(ByteCodeIterator iterator) { private static void parseFields(ClassFile classFile, ByteCodeIterator iterator) { int count = iterator.nextU2ToInt(); for (int i = 0; i < count; ++i) { - classFile.fields.add(Field.parse(classFile.constantPool, iterator)); + classFile.fields.add(Field.parse(iterator, classFile.constantPool)); } } - private static void parseMethods(ClassFile classFile, ByteCodeIterator iterator) {} + private static void parseMethods(ClassFile classFile, ByteCodeIterator iterator) { + int count = iterator.nextU2ToInt(); + for (int i = 0; i < count; ++i) { + classFile.methods.add(Method.parse(iterator, classFile.constantPool)); + } + } private static void linkConstantReferences(ClassFile classFile) { ConstantPool constantPool = classFile.constantPool; diff --git a/group01/895457260/code/src/main/java/jvm/method/Method.java b/group01/895457260/code/src/main/java/jvm/method/Method.java index e087ea24ab..e9188eccc9 100644 --- a/group01/895457260/code/src/main/java/jvm/method/Method.java +++ b/group01/895457260/code/src/main/java/jvm/method/Method.java @@ -1,48 +1,58 @@ package jvm.method; -import jvm.classfile.ClassFile; +import jvm.attr.AttributeInfo; +import jvm.attr.AttributeParser; import jvm.attr.CodeAttr; +import jvm.classfile.ConstantPool; import jvm.util.ByteCodeIterator; +import java.util.ArrayList; +import java.util.List; + public class Method { - private int accessFlag; private int nameIndex; private int descriptorIndex; - private CodeAttr codeAttr; - private ClassFile clzFile; + private ConstantPool constantPool; + private List<AttributeInfo> attributes = new ArrayList<>(); - public ClassFile getClzFile() { - return clzFile; + public Method(int accessFlag, int nameIndex, int descriptorIndex, ConstantPool constantPool) { + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + this.constantPool = constantPool; } - public int getNameIndex() { - return nameIndex; + public static Method parse(ByteCodeIterator iterator, ConstantPool constantPool) { + int access = iterator.nextU2ToInt(); + int name = iterator.nextU2ToInt(); + int descriptor = iterator.nextU2ToInt(); + int attrCount = iterator.nextU2ToInt(); + Method result = new Method(access, name, descriptor, constantPool); + for (int i = 0; i < attrCount; ++i) { + result.attributes.add(AttributeParser.parse(iterator, constantPool)); + } + return result; } - public int getDescriptorIndex() { - return descriptorIndex; + + public int getAccessFlag() { + return accessFlag; } - - public CodeAttr getCodeAttr() { - return codeAttr; + + public ConstantPool getConstantPool() { + return constantPool; } - public void setCodeAttr(CodeAttr code) { - this.codeAttr = code; + public int getNameIndex() { + return nameIndex; } - public Method(ClassFile clzFile,int accessFlag, int nameIndex, int descriptorIndex) { - this.clzFile = clzFile; - this.accessFlag = accessFlag; - this.nameIndex = nameIndex; - this.descriptorIndex = descriptorIndex; + public List<AttributeInfo> getAttributes() { + return attributes; } - public static Method parse(ClassFile clzFile, ByteCodeIterator iterator) { - int access = iterator.nextU2ToInt(); - int name = iterator.nextU2ToInt(); - int descriptor = iterator.nextU2ToInt(); - return new Method(clzFile, access, name, descriptor); + public int getDescriptorIndex() { + return descriptorIndex; } } diff --git a/group01/895457260/code/src/main/java/jvm/util/ByteCodeIterator.java b/group01/895457260/code/src/main/java/jvm/util/ByteCodeIterator.java index 4f9cfa7fef..a385aee580 100644 --- a/group01/895457260/code/src/main/java/jvm/util/ByteCodeIterator.java +++ b/group01/895457260/code/src/main/java/jvm/util/ByteCodeIterator.java @@ -11,7 +11,7 @@ public ByteCodeIterator(byte[] codes) { } public byte[] getBytes(int len) { - if (pos + len >= codes.length) { + if (pos + len > codes.length) { throw new ArrayIndexOutOfBoundsException(); } diff --git a/group01/895457260/code/src/test/java/jvm/EmployeeV1.java b/group01/895457260/code/src/test/java/jvm/EmployeeV1.java index 12e3d7efdd..84cdf0d4e6 100644 --- a/group01/895457260/code/src/test/java/jvm/EmployeeV1.java +++ b/group01/895457260/code/src/test/java/jvm/EmployeeV1.java @@ -1,4 +1,4 @@ -package com.coderising.jvm.test; +package jvm; public class EmployeeV1 { From ac8fc30a61d708c98987934082f7b000d7525990 Mon Sep 17 00:00:00 2001 From: Haochen <haochen_233333@163.com> Date: Wed, 12 Apr 2017 21:54:20 +0800 Subject: [PATCH 244/287] finish fields and methods loading --- .../test/java/jvm/ClassFileLoaderTest.java | 93 ++++++++++--------- 1 file changed, 47 insertions(+), 46 deletions(-) diff --git a/group01/895457260/code/src/test/java/jvm/ClassFileLoaderTest.java b/group01/895457260/code/src/test/java/jvm/ClassFileLoaderTest.java index d4bfe0c91b..3719b001ed 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.attr.CodeAttr; import jvm.classfile.ClassFile; import jvm.classfile.ClassIndex; import jvm.classfile.ConstantPool; @@ -182,57 +183,57 @@ public void testReadFields() { } } -// @Test -// public void testMethods() { -// -// List<Method> methods = clzFile.getMethods(); -// ConstantPool pool = clzFile.getConstantPool(); -// -// { -// Method m = methods.get(0); -// assertMethodEquals(pool,m, -// "<init>", -// "(Ljava/lang/String;I)V", -// "2ab7000c2a2bb5000f2a1cb50011b1"); -// -// } -// { -// Method m = methods.get(1); -// assertMethodEquals(pool,m, -// "setName", -// "(Ljava/lang/String;)V", -// "2a2bb5000fb1"); -// -// } -// { -// Method m = methods.get(2); -// assertMethodEquals(pool,m, -// "setAge", -// "(I)V", -// "2a1bb50011b1"); -// } -// { -// Method m = methods.get(3); -// assertMethodEquals(pool,m, -// "sayHello", -// "()V", -// "b2001c1222b60024b1"); -// -// } -// { -// Method m = methods.get(4); -// assertMethodEquals(pool,m, -// "main", -// "([Ljava/lang/String;)V", -// "bb000159122b101db7002d4c2bb6002fb1"); -// } -// } + @Test + public void testMethods() { + + List<Method> methods = clzFile.getMethods(); + ConstantPool pool = clzFile.getConstantPool(); + + { + Method m = methods.get(0); + assertMethodEquals(pool,m, + "<init>", + "(Ljava/lang/String;I)V", + "2ab7012a2bb5022a1cb503b1"); + + } + { + Method m = methods.get(1); + assertMethodEquals(pool,m, + "setName", + "(Ljava/lang/String;)V", + "2a2bb502b1"); + + } + { + Method m = methods.get(2); + assertMethodEquals(pool,m, + "setAge", + "(I)V", + "2a1bb503b1"); + } + { + Method m = methods.get(3); + assertMethodEquals(pool,m, + "sayHello", + "()V", + "b204125b606b1"); + + } + { + Method m = methods.get(4); + assertMethodEquals(pool,m, + "main", + "([Ljava/lang/String;)V", + "bb0759128101db7094c2bb60ab1"); + } + } private void assertMethodEquals(ConstantPool pool, Method m, String expectedName, String expectedDesc,String expectedCode) { String methodName = ((UTF8Info) pool.getConstantInfo(m.getNameIndex())).getValue(); String methodDesc = ((UTF8Info) pool.getConstantInfo(m.getDescriptorIndex())).getValue(); - String code = m.getCodeAttr().getCode(); + String code = ((CodeAttr) m.getAttributes().get(0)).getCode(); Assert.assertEquals(expectedName, methodName); Assert.assertEquals(expectedDesc, methodDesc); Assert.assertEquals(expectedCode, code); From 65288c0dc5e4741ce3b94eaea4cc451f0a298f68 Mon Sep 17 00:00:00 2001 From: Haochen <haochen_233333@163.com> Date: Wed, 12 Apr 2017 23:17:01 +0800 Subject: [PATCH 245/287] add clear() to Stack --- .../code/src/main/java/datastructure/basic/Stack.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/group01/895457260/code/src/main/java/datastructure/basic/Stack.java b/group01/895457260/code/src/main/java/datastructure/basic/Stack.java index ab4fc874ae..eeb9c7afba 100644 --- a/group01/895457260/code/src/main/java/datastructure/basic/Stack.java +++ b/group01/895457260/code/src/main/java/datastructure/basic/Stack.java @@ -29,4 +29,8 @@ public boolean isEmpty() { public int size() { return elementData.size(); } + + public void clear() { + elementData = new ArrayList(); + } } From 6f014ef23890e6581d299a7e8d4ca291541f10dd Mon Sep 17 00:00:00 2001 From: Haochen <haochen_233333@163.com> Date: Wed, 12 Apr 2017 23:17:35 +0800 Subject: [PATCH 246/287] finish InfixExpr --- .../src/main/java/algorithm/InfixExpr.java | 140 ++++++++++++++++++ .../test/java/algorithm/InfixExprTest.java | 48 ++++++ 2 files changed, 188 insertions(+) create mode 100644 group01/895457260/code/src/main/java/algorithm/InfixExpr.java create mode 100644 group01/895457260/code/src/test/java/algorithm/InfixExprTest.java diff --git a/group01/895457260/code/src/main/java/algorithm/InfixExpr.java b/group01/895457260/code/src/main/java/algorithm/InfixExpr.java new file mode 100644 index 0000000000..1ddb740364 --- /dev/null +++ b/group01/895457260/code/src/main/java/algorithm/InfixExpr.java @@ -0,0 +1,140 @@ +package algorithm; + +import datastructure.basic.Stack; + +import java.util.ArrayList; +import java.util.List; + +public class InfixExpr { + + Stack numbers = new Stack(); + Stack operators = new Stack(); + + String expr = null; + + public InfixExpr(String expr) { + this.expr = expr; + operators.push("#"); + } + + public float evaluate() throws CalculateException { + numbers.clear(); + operators.clear(); + operators.push("#"); + + String[] split = split(expr); + String[] strs = new String[split.length + 1]; + strs[strs.length - 1] = "#"; + System.arraycopy(split, 0, strs, 0, split.length); + + for (int i = 0; !operators.isEmpty() && i < strs.length; ++i) { + String str = strs[i]; + try { + float number = Float.parseFloat(str); + putNumber(number); + } catch (NumberFormatException e) { + putOperator(str); + } + } + return numbers.isEmpty() ? 0 : (float) numbers.peek(); + } + + private String[] split(String expr) { + List<String> list = new ArrayList<>(); + int startPos = 0; + for (int i = 0, j = 1; j < expr.length(); ++i, ++j) { + char cI = expr.charAt(i); + char cJ = expr.charAt(j); + if (isDigit(cI) ^ isDigit(cJ)) { + list.add(expr.substring(startPos, j)); + startPos = j; + } + } + list.add(expr.substring(startPos)); + return list.toArray(new String[list.size()]); + } + + private boolean isDigit(char c) { + return Character.isDigit(c) || c == '.'; + } + + private void putNumber(float num) { + numbers.push(num); + } + + private void putOperator(String op) throws CalculateException { + int compare = compare(op, (String) operators.peek()); + switch (compare) { + case 1: + operators.push(op); + break; + case 0: + operators.pop(); + break; + case -1: + float num1 = (float) numbers.pop(); + float num2 = (float) numbers.pop(); + String operator = (String) operators.pop(); + float result = calculate(num2, operator, num1); + numbers.push(result); + putOperator(op); + break; + } + } + + private float calculate(float num2, String op, float num1) throws CalculateException { + switch (op) { + case "+": + return num2 + num1; + case "-": + return num2 - num1; + case "*": + return num2 * num1; + case "/": + if (num1 != 0) { + return num2 / num1; + } + } + throw new CalculateException(); + } + + private int compare(String op, String peek) { + int opIndex = indexOf(op); + int peekIndex = indexOf(peek); + return table[opIndex][peekIndex]; + } + + private int indexOf(String op) { + switch (op) { + case "+": + return 0; + case "-": + return 1; + case "*": + return 2; + case "/": + return 3; + case "(": + return 4; + case ")": + return 5; + case "#": + return 6; + } + return 0; + } + + //优先级表 + private int[][] table = { + // + - * / ( ) # + {-1, -1, -1, -1, 1, -1, 1}, // + + {-1, -1, -1, -1, 1, -1, 1}, // - + { 1, 1, -1, -1, 1, -1, 1}, // * + { 1, 1, -1, -1, 1, -1, 1}, // / + { 1, 1, 1, 1, 1, -1, 1}, // ( + {-1, -1, -1, -1, -1, 0, 1}, // ) + {-1, -1, -1, -1, -1, -1, 0} // # + }; + + public static class CalculateException extends Exception {} +} diff --git a/group01/895457260/code/src/test/java/algorithm/InfixExprTest.java b/group01/895457260/code/src/test/java/algorithm/InfixExprTest.java new file mode 100644 index 0000000000..34480d6db7 --- /dev/null +++ b/group01/895457260/code/src/test/java/algorithm/InfixExprTest.java @@ -0,0 +1,48 @@ +package algorithm; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class InfixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() throws InfixExpr.CalculateException { + //InfixExpr expr = new InfixExpr("300*20+12*5-20/4"); + { + InfixExpr expr = new InfixExpr("2+3*4+5"); + Assert.assertEquals(19.0, expr.evaluate(), 0.001f); + } + { + InfixExpr expr = new InfixExpr("3*20+12*5-40/2"); + Assert.assertEquals(100.0, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("3*20/2"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("20/2*3"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("10-30+50"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + } + +} From e209bd51706039ae4adb9144db71afe8284d5585 Mon Sep 17 00:00:00 2001 From: Patrick <Patrick@DESKTOP-JLNF6GI> Date: Wed, 12 Apr 2017 23:55:19 +0800 Subject: [PATCH 247/287] parseField and method --- .../minijvm/loader/ClassFileParser.java | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ClassFileParser.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ClassFileParser.java index 5cce919b29..b12e564b88 100644 --- a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ClassFileParser.java +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ClassFileParser.java @@ -3,7 +3,9 @@ import java.io.UnsupportedEncodingException; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import com.github.ipk2015.coding2017.minijvm.clz.AccessFlag; import com.github.ipk2015.coding2017.minijvm.clz.ClassFile; @@ -48,9 +50,15 @@ public ClassFile parse(byte[] codes) { parseInterfaces(iterator); - parseFields(classFile,constantPool,iterator); + List<Field> parseFields = parseFields(constantPool,iterator); + for(Field f:parseFields){ + classFile.addField(f); + } - parseMethods(classFile,iterator); + List<Method> parseMethods = parseMethods(classFile,iterator); + for(Method m:parseMethods){ + classFile.addMethod(m); + } return classFile; } @@ -161,18 +169,22 @@ private void parseInterfaces(ByteCodeIterator iter) { // TODO : 如果实现了interface, 这里需要解析 } - private void parseFields(ClassFile classFile,ConstantPool pool,ByteCodeIterator iter){ + private List<Field> parseFields(ConstantPool pool,ByteCodeIterator iter){ + List<Field> list = new ArrayList(); int count = iter.nextUNToInt(2); for(int i = 0;i < count;i++){ - classFile.addField(Field.parse(pool, iter)); + list.add(Field.parse(pool, iter)); } + return list; } - private void parseMethods(ClassFile classFile,ByteCodeIterator iter){ + private List<Method> parseMethods(ClassFile classFile,ByteCodeIterator iter){ + List<Method> list = new ArrayList(); int count = iter.nextUNToInt(2); for(int i = 0;i < count;i++){ - classFile.addMethod(Method.parse(classFile, iter)); + list.add(Method.parse(classFile, iter)); } + return list; } } From d9e8de8d52c3db03ebf3109cb020f92ae4d3e49b Mon Sep 17 00:00:00 2001 From: liangduoduo666666 <798277403@qq.com> Date: Thu, 13 Apr 2017 00:33:54 +0800 Subject: [PATCH 248/287] =?UTF-8?q?=E5=AE=8C=E6=88=90=E7=AC=AC=E4=BA=94?= =?UTF-8?q?=E5=91=A8=E4=BD=9C=E4=B8=9A=EF=BC=8C=E5=B9=B6=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../zhouliang/week2/litestruts/struts.xml | 11 - .../src/{week1 => basic}/ArrayList.java | 2 +- .../src/{week1 => basic}/ArrayListTest.java | 2 +- .../src/{week1 => basic}/BinaryTree.java | 2 +- .../src/{week1 => basic}/BinaryTreeNode.java | 2 +- .../src/{week1 => basic}/Iterator.java | 2 +- .../{week4 => basic}/LRU/LRUPageFrame.java | 2 +- .../LRU/LRUPageFrameTest.java | 2 +- .../{week4 => basic}/LRU/MyLRUPageFrame.java | 2 +- .../src/{week1 => basic}/LinkedList.java | 4 +- .../src/{week1 => basic}/LinkedListTest.java | 2 +- .../798277403/src/{week1 => basic}/List.java | 2 +- .../798277403/src/{week1 => basic}/Queue.java | 2 +- .../src/{week1 => basic}/QueueTest.java | 2 +- .../798277403/src/{week1 => basic}/Stack.java | 2 +- .../src/{week1 => basic}/StackTest.java | 2 +- .../src/{week2 => basic}/array/ArrayUtil.java | 2 +- .../{week2 => basic}/array/ArrayUtilTest.java | 2 +- .../linkedlist/LinkedList.java | 2 +- .../linkedlist/LinkedListTest.java | 4 +- .../src/{week3 => basic}/linkedlist/List.java | 2 +- .../798277403/src/basic/stack/StackUtil.java | 116 +++++++++++ .../src/basic/stack/StackUtilTest.java | 77 +++++++ .../{week3 => download}/DownloadThread.java | 6 +- .../{week3 => download}/FileDownloader.java | 8 +- .../{week3 => download}/api/Connection.java | 4 +- .../api/ConnectionException.java | 2 +- .../api/ConnectionManager.java | 2 +- .../api/DownloadListener.java | 2 +- .../impl/ConnectionImpl.java | 8 +- .../impl/ConnectionManagerImpl.java | 8 +- .../test/ConnectionTest.java | 9 +- .../test/FileDownloaderTest.java | 11 +- .../{week2 => }/litestruts/LoginAction.java | 2 +- .../src/{week2 => }/litestruts/Struts.java | 4 +- .../{week2 => }/litestruts/StrutsTest.java | 13 +- .../src/{week2 => }/litestruts/View.java | 2 +- .../src/mini_jvm/clz/AccessFlag.java | 25 +++ .../798277403/src/mini_jvm/clz/ClassFile.java | 65 ++++++ .../src/mini_jvm/clz/ClassIndex.java | 19 ++ .../src/mini_jvm/constant/ClassInfo.java | 24 +++ .../src/mini_jvm/constant/ConstantInfo.java | 29 +++ .../src/mini_jvm/constant/ConstantPool.java | 27 +++ .../src/mini_jvm/constant/FieldRefInfo.java | 54 +++++ .../src/mini_jvm/constant/MethodRefInfo.java | 55 +++++ .../mini_jvm/constant/NameAndTypeInfo.java | 45 +++++ .../mini_jvm/constant/NullConstantInfo.java | 13 ++ .../src/mini_jvm/constant/StringInfo.java | 26 +++ .../src/mini_jvm/constant/UTF8Info.java | 32 +++ .../src/mini_jvm/loader/ByteCodeIterator.java | 55 +++++ .../src/mini_jvm/loader/ClassFileLoader.java | 94 +++++++++ .../src/mini_jvm/loader/ClassFileParser.java | 130 ++++++++++++ .../mini_jvm/test/ClassFileloaderTest.java | 189 ++++++++++++++++++ .../src/mini_jvm/test/EmployeeV1.java | 28 +++ group24/798277403/src/mini_jvm/util/Util.java | 22 ++ .../798277403/src/week2/litestruts/struts.xml | 11 - .../src/week4/loader/ClassFileLoader.java | 67 ------- .../src/week4/test/ClassFileloaderTest.java | 84 -------- .../798277403/src/week4/test/EmployeeV1.java | 29 --- 59 files changed, 1187 insertions(+), 265 deletions(-) delete mode 100644 group24/798277403/out/production/zhouliang/week2/litestruts/struts.xml rename group24/798277403/src/{week1 => basic}/ArrayList.java (99%) rename group24/798277403/src/{week1 => basic}/ArrayListTest.java (98%) rename group24/798277403/src/{week1 => basic}/BinaryTree.java (99%) rename group24/798277403/src/{week1 => basic}/BinaryTreeNode.java (99%) rename group24/798277403/src/{week1 => basic}/Iterator.java (90%) rename group24/798277403/src/{week4 => basic}/LRU/LRUPageFrame.java (99%) rename group24/798277403/src/{week4 => basic}/LRU/LRUPageFrameTest.java (98%) rename group24/798277403/src/{week4 => basic}/LRU/MyLRUPageFrame.java (99%) rename group24/798277403/src/{week1 => basic}/LinkedList.java (98%) rename group24/798277403/src/{week1 => basic}/LinkedListTest.java (98%) rename group24/798277403/src/{week1 => basic}/List.java (93%) rename group24/798277403/src/{week1 => basic}/Queue.java (97%) rename group24/798277403/src/{week1 => basic}/QueueTest.java (97%) rename group24/798277403/src/{week1 => basic}/Stack.java (97%) rename group24/798277403/src/{week1 => basic}/StackTest.java (97%) rename group24/798277403/src/{week2 => basic}/array/ArrayUtil.java (99%) rename group24/798277403/src/{week2 => basic}/array/ArrayUtilTest.java (99%) rename group24/798277403/src/{week3 => basic}/linkedlist/LinkedList.java (99%) rename group24/798277403/src/{week3 => basic}/linkedlist/LinkedListTest.java (95%) rename group24/798277403/src/{week3 => basic}/linkedlist/List.java (89%) create mode 100644 group24/798277403/src/basic/stack/StackUtil.java create mode 100644 group24/798277403/src/basic/stack/StackUtilTest.java rename group24/798277403/src/{week3 => download}/DownloadThread.java (83%) rename group24/798277403/src/{week3 => download}/FileDownloader.java (96%) rename group24/798277403/src/{week3 => download}/api/Connection.java (80%) rename group24/798277403/src/{week3 => download}/api/ConnectionException.java (85%) rename group24/798277403/src/{week3 => download}/api/ConnectionManager.java (89%) rename group24/798277403/src/{week3 => download}/api/DownloadListener.java (76%) rename group24/798277403/src/{week3 => download}/impl/ConnectionImpl.java (91%) rename group24/798277403/src/{week3 => download}/impl/ConnectionManagerImpl.java (57%) rename group24/798277403/src/{week3 => download}/test/ConnectionTest.java (88%) rename group24/798277403/src/{week3 => download}/test/FileDownloaderTest.java (86%) rename group24/798277403/src/{week2 => }/litestruts/LoginAction.java (97%) rename group24/798277403/src/{week2 => }/litestruts/Struts.java (98%) rename group24/798277403/src/{week2 => }/litestruts/StrutsTest.java (84%) rename group24/798277403/src/{week2 => }/litestruts/View.java (93%) create mode 100644 group24/798277403/src/mini_jvm/clz/AccessFlag.java create mode 100644 group24/798277403/src/mini_jvm/clz/ClassFile.java create mode 100644 group24/798277403/src/mini_jvm/clz/ClassIndex.java create mode 100644 group24/798277403/src/mini_jvm/constant/ClassInfo.java create mode 100644 group24/798277403/src/mini_jvm/constant/ConstantInfo.java create mode 100644 group24/798277403/src/mini_jvm/constant/ConstantPool.java create mode 100644 group24/798277403/src/mini_jvm/constant/FieldRefInfo.java create mode 100644 group24/798277403/src/mini_jvm/constant/MethodRefInfo.java create mode 100644 group24/798277403/src/mini_jvm/constant/NameAndTypeInfo.java create mode 100644 group24/798277403/src/mini_jvm/constant/NullConstantInfo.java create mode 100644 group24/798277403/src/mini_jvm/constant/StringInfo.java create mode 100644 group24/798277403/src/mini_jvm/constant/UTF8Info.java create mode 100644 group24/798277403/src/mini_jvm/loader/ByteCodeIterator.java create mode 100644 group24/798277403/src/mini_jvm/loader/ClassFileLoader.java create mode 100644 group24/798277403/src/mini_jvm/loader/ClassFileParser.java create mode 100644 group24/798277403/src/mini_jvm/test/ClassFileloaderTest.java create mode 100644 group24/798277403/src/mini_jvm/test/EmployeeV1.java create mode 100644 group24/798277403/src/mini_jvm/util/Util.java delete mode 100644 group24/798277403/src/week2/litestruts/struts.xml delete mode 100644 group24/798277403/src/week4/loader/ClassFileLoader.java delete mode 100644 group24/798277403/src/week4/test/ClassFileloaderTest.java delete mode 100644 group24/798277403/src/week4/test/EmployeeV1.java diff --git a/group24/798277403/out/production/zhouliang/week2/litestruts/struts.xml b/group24/798277403/out/production/zhouliang/week2/litestruts/struts.xml deleted file mode 100644 index 54550a4174..0000000000 --- a/group24/798277403/out/production/zhouliang/week2/litestruts/struts.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<struts> - <action name="login" class="week2.litestruts.LoginAction"> - <result name="success">/jsp/homepage.jsp</result> - <result name="fail">/jsp/showLogin.jsp</result> - </action> - <action name="logout" class="week2.litestruts.LogoutAction"> - <result name="success">/jsp/welcome.jsp</result> - <result name="error">/jsp/error.jsp</result> - </action> -</struts> diff --git a/group24/798277403/src/week1/ArrayList.java b/group24/798277403/src/basic/ArrayList.java similarity index 99% rename from group24/798277403/src/week1/ArrayList.java rename to group24/798277403/src/basic/ArrayList.java index 03257803df..436ca1f9f2 100644 --- a/group24/798277403/src/week1/ArrayList.java +++ b/group24/798277403/src/basic/ArrayList.java @@ -1,4 +1,4 @@ -package week1; +package basic; import java.util.Arrays; diff --git a/group24/798277403/src/week1/ArrayListTest.java b/group24/798277403/src/basic/ArrayListTest.java similarity index 98% rename from group24/798277403/src/week1/ArrayListTest.java rename to group24/798277403/src/basic/ArrayListTest.java index 98e30a222a..c50af7befa 100644 --- a/group24/798277403/src/week1/ArrayListTest.java +++ b/group24/798277403/src/basic/ArrayListTest.java @@ -1,4 +1,4 @@ -package week1; +package basic; import org.junit.Assert; import org.junit.Before; diff --git a/group24/798277403/src/week1/BinaryTree.java b/group24/798277403/src/basic/BinaryTree.java similarity index 99% rename from group24/798277403/src/week1/BinaryTree.java rename to group24/798277403/src/basic/BinaryTree.java index 3c480dc012..c2d5bb2c24 100644 --- a/group24/798277403/src/week1/BinaryTree.java +++ b/group24/798277403/src/basic/BinaryTree.java @@ -1,4 +1,4 @@ -package week1; +package basic; /** * Created by zhouliang on 2017-03-11. diff --git a/group24/798277403/src/week1/BinaryTreeNode.java b/group24/798277403/src/basic/BinaryTreeNode.java similarity index 99% rename from group24/798277403/src/week1/BinaryTreeNode.java rename to group24/798277403/src/basic/BinaryTreeNode.java index e680d5ed15..599b2b1ca8 100644 --- a/group24/798277403/src/week1/BinaryTreeNode.java +++ b/group24/798277403/src/basic/BinaryTreeNode.java @@ -1,4 +1,4 @@ -package week1; +package basic; /** * 自己实现的BinaryTreeNode diff --git a/group24/798277403/src/week1/Iterator.java b/group24/798277403/src/basic/Iterator.java similarity index 90% rename from group24/798277403/src/week1/Iterator.java rename to group24/798277403/src/basic/Iterator.java index 73ba87c125..4c0fedf988 100644 --- a/group24/798277403/src/week1/Iterator.java +++ b/group24/798277403/src/basic/Iterator.java @@ -1,4 +1,4 @@ -package week1; +package basic; /** * 自己实现的Iterator diff --git a/group24/798277403/src/week4/LRU/LRUPageFrame.java b/group24/798277403/src/basic/LRU/LRUPageFrame.java similarity index 99% rename from group24/798277403/src/week4/LRU/LRUPageFrame.java rename to group24/798277403/src/basic/LRU/LRUPageFrame.java index cbbb26fc7f..e69e051321 100644 --- a/group24/798277403/src/week4/LRU/LRUPageFrame.java +++ b/group24/798277403/src/basic/LRU/LRUPageFrame.java @@ -1,4 +1,4 @@ -package week4.LRU; +package basic.LRU; /** * Created by zhouliang on 2017-04-04. diff --git a/group24/798277403/src/week4/LRU/LRUPageFrameTest.java b/group24/798277403/src/basic/LRU/LRUPageFrameTest.java similarity index 98% rename from group24/798277403/src/week4/LRU/LRUPageFrameTest.java rename to group24/798277403/src/basic/LRU/LRUPageFrameTest.java index 0b6bdf2c25..4993f42e75 100644 --- a/group24/798277403/src/week4/LRU/LRUPageFrameTest.java +++ b/group24/798277403/src/basic/LRU/LRUPageFrameTest.java @@ -1,4 +1,4 @@ -package week4.LRU; +package basic.LRU; import org.junit.Assert; import org.junit.Test; diff --git a/group24/798277403/src/week4/LRU/MyLRUPageFrame.java b/group24/798277403/src/basic/LRU/MyLRUPageFrame.java similarity index 99% rename from group24/798277403/src/week4/LRU/MyLRUPageFrame.java rename to group24/798277403/src/basic/LRU/MyLRUPageFrame.java index 9e720d8589..b2387dbd81 100644 --- a/group24/798277403/src/week4/LRU/MyLRUPageFrame.java +++ b/group24/798277403/src/basic/LRU/MyLRUPageFrame.java @@ -1,4 +1,4 @@ -package week4.LRU; +package basic.LRU; /** * Created by zhouliang on 2017-04-04. diff --git a/group24/798277403/src/week1/LinkedList.java b/group24/798277403/src/basic/LinkedList.java similarity index 98% rename from group24/798277403/src/week1/LinkedList.java rename to group24/798277403/src/basic/LinkedList.java index e0160d0e5f..30d0b4a099 100644 --- a/group24/798277403/src/week1/LinkedList.java +++ b/group24/798277403/src/basic/LinkedList.java @@ -1,4 +1,4 @@ -package week1; +package basic; /** * 自己实现的LinkedList @@ -228,7 +228,7 @@ public void removeRange(int min, int max){ * 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列 * @param list */ - public LinkedList intersection( LinkedList list){ + public LinkedList intersection(LinkedList list){ return null; } } diff --git a/group24/798277403/src/week1/LinkedListTest.java b/group24/798277403/src/basic/LinkedListTest.java similarity index 98% rename from group24/798277403/src/week1/LinkedListTest.java rename to group24/798277403/src/basic/LinkedListTest.java index 9a8a9d936d..0611a1ddb7 100644 --- a/group24/798277403/src/week1/LinkedListTest.java +++ b/group24/798277403/src/basic/LinkedListTest.java @@ -1,4 +1,4 @@ -package week1; +package basic; import org.junit.Before; import org.junit.Test; diff --git a/group24/798277403/src/week1/List.java b/group24/798277403/src/basic/List.java similarity index 93% rename from group24/798277403/src/week1/List.java rename to group24/798277403/src/basic/List.java index 982885508f..c46d81d175 100644 --- a/group24/798277403/src/week1/List.java +++ b/group24/798277403/src/basic/List.java @@ -1,4 +1,4 @@ -package week1; +package basic; /** * 自己定义的List接口 diff --git a/group24/798277403/src/week1/Queue.java b/group24/798277403/src/basic/Queue.java similarity index 97% rename from group24/798277403/src/week1/Queue.java rename to group24/798277403/src/basic/Queue.java index 184f3a5336..371f2f9340 100644 --- a/group24/798277403/src/week1/Queue.java +++ b/group24/798277403/src/basic/Queue.java @@ -1,4 +1,4 @@ -package week1; +package basic; /** * 自己实现的Queue,用自己的LinkedList实现 diff --git a/group24/798277403/src/week1/QueueTest.java b/group24/798277403/src/basic/QueueTest.java similarity index 97% rename from group24/798277403/src/week1/QueueTest.java rename to group24/798277403/src/basic/QueueTest.java index b5a333f64d..8af2de5ada 100644 --- a/group24/798277403/src/week1/QueueTest.java +++ b/group24/798277403/src/basic/QueueTest.java @@ -1,4 +1,4 @@ -package week1; +package basic; import org.junit.Before; import org.junit.Test; diff --git a/group24/798277403/src/week1/Stack.java b/group24/798277403/src/basic/Stack.java similarity index 97% rename from group24/798277403/src/week1/Stack.java rename to group24/798277403/src/basic/Stack.java index f85aa2ada5..e6351da277 100644 --- a/group24/798277403/src/week1/Stack.java +++ b/group24/798277403/src/basic/Stack.java @@ -1,4 +1,4 @@ -package week1; +package basic; /** * 自己实现的Stack diff --git a/group24/798277403/src/week1/StackTest.java b/group24/798277403/src/basic/StackTest.java similarity index 97% rename from group24/798277403/src/week1/StackTest.java rename to group24/798277403/src/basic/StackTest.java index f4213d66d3..921560a0f0 100644 --- a/group24/798277403/src/week1/StackTest.java +++ b/group24/798277403/src/basic/StackTest.java @@ -1,4 +1,4 @@ -package week1; +package basic; import org.junit.Before; import org.junit.Test; diff --git a/group24/798277403/src/week2/array/ArrayUtil.java b/group24/798277403/src/basic/array/ArrayUtil.java similarity index 99% rename from group24/798277403/src/week2/array/ArrayUtil.java rename to group24/798277403/src/basic/array/ArrayUtil.java index 04c03f95e0..e29a4845bf 100644 --- a/group24/798277403/src/week2/array/ArrayUtil.java +++ b/group24/798277403/src/basic/array/ArrayUtil.java @@ -1,4 +1,4 @@ -package week2.array; +package basic.array; import java.util.Arrays; diff --git a/group24/798277403/src/week2/array/ArrayUtilTest.java b/group24/798277403/src/basic/array/ArrayUtilTest.java similarity index 99% rename from group24/798277403/src/week2/array/ArrayUtilTest.java rename to group24/798277403/src/basic/array/ArrayUtilTest.java index 77c99242fa..792c778e75 100644 --- a/group24/798277403/src/week2/array/ArrayUtilTest.java +++ b/group24/798277403/src/basic/array/ArrayUtilTest.java @@ -1,4 +1,4 @@ -package week2.array; +package basic.array; import org.junit.Assert; import org.junit.Before; diff --git a/group24/798277403/src/week3/linkedlist/LinkedList.java b/group24/798277403/src/basic/linkedlist/LinkedList.java similarity index 99% rename from group24/798277403/src/week3/linkedlist/LinkedList.java rename to group24/798277403/src/basic/linkedlist/LinkedList.java index ad4560ad7d..53c9200412 100644 --- a/group24/798277403/src/week3/linkedlist/LinkedList.java +++ b/group24/798277403/src/basic/linkedlist/LinkedList.java @@ -1,4 +1,4 @@ -package week3.linkedlist; +package basic.linkedlist; /** diff --git a/group24/798277403/src/week3/linkedlist/LinkedListTest.java b/group24/798277403/src/basic/linkedlist/LinkedListTest.java similarity index 95% rename from group24/798277403/src/week3/linkedlist/LinkedListTest.java rename to group24/798277403/src/basic/linkedlist/LinkedListTest.java index fa648edfc6..4f74499501 100644 --- a/group24/798277403/src/week3/linkedlist/LinkedListTest.java +++ b/group24/798277403/src/basic/linkedlist/LinkedListTest.java @@ -1,4 +1,4 @@ -package week3.linkedlist; +package basic.linkedlist; import org.junit.Before; import org.junit.Test; @@ -8,7 +8,7 @@ */ public class LinkedListTest { - private week3.linkedlist.LinkedList<Integer> myLinkedList = new week3.linkedlist.LinkedList<>(); + private LinkedList<Integer> myLinkedList = new LinkedList<>(); private java.util.LinkedList<Integer> systemLinkedList = new java.util.LinkedList<>(); diff --git a/group24/798277403/src/week3/linkedlist/List.java b/group24/798277403/src/basic/linkedlist/List.java similarity index 89% rename from group24/798277403/src/week3/linkedlist/List.java rename to group24/798277403/src/basic/linkedlist/List.java index a3245a5eb9..3b9dfb132a 100644 --- a/group24/798277403/src/week3/linkedlist/List.java +++ b/group24/798277403/src/basic/linkedlist/List.java @@ -1,4 +1,4 @@ -package week3.linkedlist; +package basic.linkedlist; /** * 自己定义的List接口 diff --git a/group24/798277403/src/basic/stack/StackUtil.java b/group24/798277403/src/basic/stack/StackUtil.java new file mode 100644 index 0000000000..7e5c157306 --- /dev/null +++ b/group24/798277403/src/basic/stack/StackUtil.java @@ -0,0 +1,116 @@ +package basic.stack; + +import java.util.Stack; + +/** + * Created by zhouliang on 2017-04-08. + */ +class StackUtil { + /** + * 假设栈中的元素是Integer, 从栈顶到栈底是 : 5,4,3,2,1 调用该方法后, 元素次序变为: 1,2,3,4,5 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + */ + public static void reverse(Stack<Integer> s) { + if(s.empty()){ + return; + } + int i = getAndRemoveBottom(s); // 依次返回1、2、3 + reverse(s); + s.push(i); + } + + //移除并返回当前的栈底元素 + private static int getAndRemoveBottom(Stack<Integer> s){ + int result = s.pop(); + if(s.empty()){ + return result; + }else{ + int bottom = getAndRemoveBottom(s); + s.push(result); + return bottom; + } + } + + + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * @param o + */ + public static void remove(Stack<Object> s,Object o) { + if(s.empty()){ + return; + } + Object temp = s.pop(); + if(temp == o){ + return; + } + remove(s,o); + s.push(temp); + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * @param len + * @return + */ + public static Object[] getTop(Stack<Object> s,int len) { + Object[] result = new Object[len]; + int index = 0; + while(index<len){ + result[index] = getIndex(s,index+1); + index++; + } + return result; + } + + //获取第index个元素(从1开始) + private static Object getIndex(Stack<Object> s, int index){ + Object temp = s.pop(); + index--; + if(0 == index){ + s.push(temp); + return temp; + } + Object result = getIndex(s,index); + s.push(temp); + 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[] chars = s.toCharArray(); + Stack<Character> stack = new Stack<Character>(); + for(char c : chars){ + if(c=='(' || c=='[' || c=='{'){ + stack.push(c); + }else if(c==')'){ + char top = stack.peek(); + if(top == '('){ + stack.pop(); + } + }else if(c==']'){ + char top = stack.peek(); + if(top == '['){ + stack.pop(); + } + }else if(c=='}'){ + char top = stack.peek(); + if(top == '{'){ + stack.pop(); + } + } + } + + return stack.empty(); + } +} diff --git a/group24/798277403/src/basic/stack/StackUtilTest.java b/group24/798277403/src/basic/stack/StackUtilTest.java new file mode 100644 index 0000000000..c5ecd1fcbe --- /dev/null +++ b/group24/798277403/src/basic/stack/StackUtilTest.java @@ -0,0 +1,77 @@ +package basic.stack; + +import org.junit.Test; + +import java.util.Stack; + +/** + * Created by zhouliang on 2017-04-08. + */ +public class StackUtilTest { + + @Test + public void testReverse(){ + Stack<Integer> s = new Stack<Integer>(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + while(!s.isEmpty()){ + System.out.println(s.pop()); + } + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + StackUtil.reverse(s); + while(!s.isEmpty()){ + System.out.println(s.pop()); + } + } + + @Test + public void remove(){ + Stack<Object> s = new Stack<Object>(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + + StackUtil.remove(s,3); + while(!s.isEmpty()){ + System.out.println(s.pop()); + } + } + + @Test + public void getTop(){ + Stack<Object> s = new Stack<Object>(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + + Object[] result = StackUtil.getTop(s,2); + while(!s.isEmpty()){ + System.out.println(s.pop()); + } + + for(Object o : result){ + System.out.println(o); + } + } + + @Test + public void isValidPairs(){ + String s = "([e{d}f])"; + String s1 = "([b{x]y})"; + boolean result = StackUtil.isValidPairs(s); + System.out.println(result); + boolean result1 = StackUtil.isValidPairs(s1); + System.out.println(result1); + } +} diff --git a/group24/798277403/src/week3/DownloadThread.java b/group24/798277403/src/download/DownloadThread.java similarity index 83% rename from group24/798277403/src/week3/DownloadThread.java rename to group24/798277403/src/download/DownloadThread.java index 6361f6b394..df55a6fee1 100644 --- a/group24/798277403/src/week3/DownloadThread.java +++ b/group24/798277403/src/download/DownloadThread.java @@ -1,7 +1,7 @@ -package week3; +package download; -import week3.api.Connection; +import download.api.Connection; import java.io.RandomAccessFile; import java.util.concurrent.CyclicBarrier; @@ -13,7 +13,7 @@ class DownloadThread extends Thread{ private int endPos; private CyclicBarrier barrier; private String localFile; - public DownloadThread( Connection conn, int startPos, int endPos, String localFile, CyclicBarrier barrier){ + public DownloadThread(Connection conn, int startPos, int endPos, String localFile, CyclicBarrier barrier){ this.conn = conn; this.startPos = startPos; diff --git a/group24/798277403/src/week3/FileDownloader.java b/group24/798277403/src/download/FileDownloader.java similarity index 96% rename from group24/798277403/src/week3/FileDownloader.java rename to group24/798277403/src/download/FileDownloader.java index 912fc47df3..928c1cf2e5 100644 --- a/group24/798277403/src/week3/FileDownloader.java +++ b/group24/798277403/src/download/FileDownloader.java @@ -1,9 +1,9 @@ -package week3; +package download; -import week3.api.Connection; -import week3.api.ConnectionManager; -import week3.api.DownloadListener; +import download.api.Connection; +import download.api.ConnectionManager; +import download.api.DownloadListener; import java.io.IOException; import java.io.RandomAccessFile; diff --git a/group24/798277403/src/week3/api/Connection.java b/group24/798277403/src/download/api/Connection.java similarity index 80% rename from group24/798277403/src/week3/api/Connection.java rename to group24/798277403/src/download/api/Connection.java index 9c67704364..49ee91a647 100644 --- a/group24/798277403/src/week3/api/Connection.java +++ b/group24/798277403/src/download/api/Connection.java @@ -1,4 +1,4 @@ -package week3.api; +package download.api; import java.io.IOException; @@ -9,7 +9,7 @@ public interface Connection { * @param endPos 结束位置 * @return */ - public byte[] read(int startPos,int endPos) throws IOException; + public byte[] read(int startPos, int endPos) throws IOException; /** * 得到数据内容的长度 * @return diff --git a/group24/798277403/src/week3/api/ConnectionException.java b/group24/798277403/src/download/api/ConnectionException.java similarity index 85% rename from group24/798277403/src/week3/api/ConnectionException.java rename to group24/798277403/src/download/api/ConnectionException.java index a92938a3aa..aa642f6adf 100644 --- a/group24/798277403/src/week3/api/ConnectionException.java +++ b/group24/798277403/src/download/api/ConnectionException.java @@ -1,4 +1,4 @@ -package week3.api; +package download.api; public class ConnectionException extends Exception { public ConnectionException(Exception e){ diff --git a/group24/798277403/src/week3/api/ConnectionManager.java b/group24/798277403/src/download/api/ConnectionManager.java similarity index 89% rename from group24/798277403/src/week3/api/ConnectionManager.java rename to group24/798277403/src/download/api/ConnectionManager.java index 4af7a12be1..de6df6d7c6 100644 --- a/group24/798277403/src/week3/api/ConnectionManager.java +++ b/group24/798277403/src/download/api/ConnectionManager.java @@ -1,4 +1,4 @@ -package week3.api; +package download.api; public interface ConnectionManager { /** diff --git a/group24/798277403/src/week3/api/DownloadListener.java b/group24/798277403/src/download/api/DownloadListener.java similarity index 76% rename from group24/798277403/src/week3/api/DownloadListener.java rename to group24/798277403/src/download/api/DownloadListener.java index da4eb7abc3..4119e46144 100644 --- a/group24/798277403/src/week3/api/DownloadListener.java +++ b/group24/798277403/src/download/api/DownloadListener.java @@ -1,4 +1,4 @@ -package week3.api; +package download.api; public interface DownloadListener { public void notifyFinished(); diff --git a/group24/798277403/src/week3/impl/ConnectionImpl.java b/group24/798277403/src/download/impl/ConnectionImpl.java similarity index 91% rename from group24/798277403/src/week3/impl/ConnectionImpl.java rename to group24/798277403/src/download/impl/ConnectionImpl.java index ca5c79c503..675d042a93 100644 --- a/group24/798277403/src/week3/impl/ConnectionImpl.java +++ b/group24/798277403/src/download/impl/ConnectionImpl.java @@ -1,7 +1,7 @@ -package week3.impl; +package download.impl; -import week3.api.Connection; -import week3.api.ConnectionException; +import download.api.Connection; +import download.api.ConnectionException; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -12,7 +12,7 @@ import java.net.URLConnection; import java.util.Arrays; -class ConnectionImpl implements Connection{ +class ConnectionImpl implements Connection { private URL url; diff --git a/group24/798277403/src/week3/impl/ConnectionManagerImpl.java b/group24/798277403/src/download/impl/ConnectionManagerImpl.java similarity index 57% rename from group24/798277403/src/week3/impl/ConnectionManagerImpl.java rename to group24/798277403/src/download/impl/ConnectionManagerImpl.java index 130d7e5aaa..e721d46194 100644 --- a/group24/798277403/src/week3/impl/ConnectionManagerImpl.java +++ b/group24/798277403/src/download/impl/ConnectionManagerImpl.java @@ -1,8 +1,8 @@ -package week3.impl; +package download.impl; -import week3.api.Connection; -import week3.api.ConnectionException; -import week3.api.ConnectionManager; +import download.api.Connection; +import download.api.ConnectionException; +import download.api.ConnectionManager; public class ConnectionManagerImpl implements ConnectionManager { diff --git a/group24/798277403/src/week3/test/ConnectionTest.java b/group24/798277403/src/download/test/ConnectionTest.java similarity index 88% rename from group24/798277403/src/week3/test/ConnectionTest.java rename to group24/798277403/src/download/test/ConnectionTest.java index 918f4d0707..cd8c9ca04d 100644 --- a/group24/798277403/src/week3/test/ConnectionTest.java +++ b/group24/798277403/src/download/test/ConnectionTest.java @@ -1,12 +1,13 @@ -package week3.test; +package download.test; +import download.api.Connection; +import download.api.ConnectionManager; +import download.impl.ConnectionManagerImpl; 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 { diff --git a/group24/798277403/src/week3/test/FileDownloaderTest.java b/group24/798277403/src/download/test/FileDownloaderTest.java similarity index 86% rename from group24/798277403/src/week3/test/FileDownloaderTest.java rename to group24/798277403/src/download/test/FileDownloaderTest.java index 959796399b..f0337f6bc1 100644 --- a/group24/798277403/src/week3/test/FileDownloaderTest.java +++ b/group24/798277403/src/download/test/FileDownloaderTest.java @@ -1,12 +1,13 @@ -package week3.test; +package download.test; +import download.FileDownloader; +import download.api.ConnectionManager; +import download.api.DownloadListener; +import download.impl.ConnectionManagerImpl; 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 { diff --git a/group24/798277403/src/week2/litestruts/LoginAction.java b/group24/798277403/src/litestruts/LoginAction.java similarity index 97% rename from group24/798277403/src/week2/litestruts/LoginAction.java rename to group24/798277403/src/litestruts/LoginAction.java index f819fd3aa3..8c448e3630 100644 --- a/group24/798277403/src/week2/litestruts/LoginAction.java +++ b/group24/798277403/src/litestruts/LoginAction.java @@ -1,4 +1,4 @@ -package week2.litestruts; +package litestruts; /** * 这是一个用来展示登录的业务类, 其中的用户名和密码都是硬编码的。 diff --git a/group24/798277403/src/week2/litestruts/Struts.java b/group24/798277403/src/litestruts/Struts.java similarity index 98% rename from group24/798277403/src/week2/litestruts/Struts.java rename to group24/798277403/src/litestruts/Struts.java index 4063dcda68..2139dd8551 100644 --- a/group24/798277403/src/week2/litestruts/Struts.java +++ b/group24/798277403/src/litestruts/Struts.java @@ -1,4 +1,4 @@ -package week2.litestruts; +package litestruts; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; @@ -44,7 +44,7 @@ public static View runAction(String actionName, Map<String, String> parameters) View view = new View(); try { db = documentBuilderFactory.newDocumentBuilder(); - Document document = db.parse("src/week2/litestruts/struts.xml"); + Document document = db.parse("src/litestruts/struts.xml"); NodeList nodeList = document.getElementsByTagName("action"); //遍历每一个action节点 diff --git a/group24/798277403/src/week2/litestruts/StrutsTest.java b/group24/798277403/src/litestruts/StrutsTest.java similarity index 84% rename from group24/798277403/src/week2/litestruts/StrutsTest.java rename to group24/798277403/src/litestruts/StrutsTest.java index 5c4379d912..868a78cdba 100644 --- a/group24/798277403/src/week2/litestruts/StrutsTest.java +++ b/group24/798277403/src/litestruts/StrutsTest.java @@ -1,4 +1,4 @@ -package week2.litestruts; +package litestruts; import org.junit.Assert; import org.junit.Test; @@ -7,9 +7,6 @@ import java.util.Map; - - - public class StrutsTest { @Test @@ -22,8 +19,8 @@ public void testLoginActionSuccess() { params.put("password","1234"); - View view = Struts.runAction(actionName,params); - + View view = Struts.runAction(actionName,params); + Assert.assertEquals("/jsp/homepage.jsp", view.getJsp()); Assert.assertEquals("login successful", view.getParameters().get("message")); } @@ -34,8 +31,8 @@ public void testLoginActionFailed() { Map<String,String> params = new HashMap<String,String>(); params.put("name","test"); params.put("password","123456"); //密码和预设的不一致 - - View view = Struts.runAction(actionName,params); + + 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/group24/798277403/src/week2/litestruts/View.java b/group24/798277403/src/litestruts/View.java similarity index 93% rename from group24/798277403/src/week2/litestruts/View.java rename to group24/798277403/src/litestruts/View.java index 01a422a808..1eed614744 100644 --- a/group24/798277403/src/week2/litestruts/View.java +++ b/group24/798277403/src/litestruts/View.java @@ -1,4 +1,4 @@ -package week2.litestruts; +package litestruts; import java.util.Map; diff --git a/group24/798277403/src/mini_jvm/clz/AccessFlag.java b/group24/798277403/src/mini_jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..b6717402da --- /dev/null +++ b/group24/798277403/src/mini_jvm/clz/AccessFlag.java @@ -0,0 +1,25 @@ +package mini_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/group24/798277403/src/mini_jvm/clz/ClassFile.java b/group24/798277403/src/mini_jvm/clz/ClassFile.java new file mode 100644 index 0000000000..4cf756c090 --- /dev/null +++ b/group24/798277403/src/mini_jvm/clz/ClassFile.java @@ -0,0 +1,65 @@ +package mini_jvm.clz; + + +import mini_jvm.constant.ClassInfo; +import mini_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/group24/798277403/src/mini_jvm/clz/ClassIndex.java b/group24/798277403/src/mini_jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..dcc59908f0 --- /dev/null +++ b/group24/798277403/src/mini_jvm/clz/ClassIndex.java @@ -0,0 +1,19 @@ +package mini_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/group24/798277403/src/mini_jvm/constant/ClassInfo.java b/group24/798277403/src/mini_jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..ed39387440 --- /dev/null +++ b/group24/798277403/src/mini_jvm/constant/ClassInfo.java @@ -0,0 +1,24 @@ +package mini_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/group24/798277403/src/mini_jvm/constant/ConstantInfo.java b/group24/798277403/src/mini_jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..d488321043 --- /dev/null +++ b/group24/798277403/src/mini_jvm/constant/ConstantInfo.java @@ -0,0 +1,29 @@ +package mini_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/group24/798277403/src/mini_jvm/constant/ConstantPool.java b/group24/798277403/src/mini_jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..c8d30c78db --- /dev/null +++ b/group24/798277403/src/mini_jvm/constant/ConstantPool.java @@ -0,0 +1,27 @@ +package mini_jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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/798277403/src/mini_jvm/constant/FieldRefInfo.java b/group24/798277403/src/mini_jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..3d74c4244f --- /dev/null +++ b/group24/798277403/src/mini_jvm/constant/FieldRefInfo.java @@ -0,0 +1,54 @@ +package mini_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/group24/798277403/src/mini_jvm/constant/MethodRefInfo.java b/group24/798277403/src/mini_jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..4037881ad8 --- /dev/null +++ b/group24/798277403/src/mini_jvm/constant/MethodRefInfo.java @@ -0,0 +1,55 @@ +package mini_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/group24/798277403/src/mini_jvm/constant/NameAndTypeInfo.java b/group24/798277403/src/mini_jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..badba119df --- /dev/null +++ b/group24/798277403/src/mini_jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,45 @@ +package mini_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/group24/798277403/src/mini_jvm/constant/NullConstantInfo.java b/group24/798277403/src/mini_jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..28d102c997 --- /dev/null +++ b/group24/798277403/src/mini_jvm/constant/NullConstantInfo.java @@ -0,0 +1,13 @@ +package mini_jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo(){ + + } + @Override + public int getType() { + return -1; + } + +} diff --git a/group24/798277403/src/mini_jvm/constant/StringInfo.java b/group24/798277403/src/mini_jvm/constant/StringInfo.java new file mode 100644 index 0000000000..2a9387d247 --- /dev/null +++ b/group24/798277403/src/mini_jvm/constant/StringInfo.java @@ -0,0 +1,26 @@ +package mini_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/group24/798277403/src/mini_jvm/constant/UTF8Info.java b/group24/798277403/src/mini_jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..6fc44f5355 --- /dev/null +++ b/group24/798277403/src/mini_jvm/constant/UTF8Info.java @@ -0,0 +1,32 @@ +package mini_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/group24/798277403/src/mini_jvm/loader/ByteCodeIterator.java b/group24/798277403/src/mini_jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..35ca6420b6 --- /dev/null +++ b/group24/798277403/src/mini_jvm/loader/ByteCodeIterator.java @@ -0,0 +1,55 @@ +package mini_jvm.loader; + +import mini_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 ArrayIndexOutOfBoundsException(); + } + + byte[] data = Arrays.copyOfRange(codes, pos, pos + len); + pos += len; + return data; + } + + 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 nextUxToHexString(int len) { + byte[] tmp = new byte[len]; + + for (int i = 0; i < len; i++) { + tmp[i] = codes[pos++]; + } + return Util.byteToHexString(tmp).toLowerCase(); + + } + + public void back(int n) { + this.pos -= n; + } + +} diff --git a/group24/798277403/src/mini_jvm/loader/ClassFileLoader.java b/group24/798277403/src/mini_jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..db3402aeb6 --- /dev/null +++ b/group24/798277403/src/mini_jvm/loader/ClassFileLoader.java @@ -0,0 +1,94 @@ +package mini_jvm.loader; + +import mini_jvm.clz.ClassFile; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; + +import java.io.*; +import java.util.ArrayList; +import java.util.List; + + +public class ClassFileLoader { + + private List<String> clzPaths = new ArrayList<String>(); + + 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/group24/798277403/src/mini_jvm/loader/ClassFileParser.java b/group24/798277403/src/mini_jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..ad2ca0cdf4 --- /dev/null +++ b/group24/798277403/src/mini_jvm/loader/ClassFileParser.java @@ -0,0 +1,130 @@ +package mini_jvm.loader; + +import mini_jvm.clz.AccessFlag; +import mini_jvm.clz.ClassFile; +import mini_jvm.clz.ClassIndex; +import mini_jvm.constant.*; + +import java.io.UnsupportedEncodingException; + + +public class ClassFileParser { + + public ClassFile parse(byte[] codes) { + ClassFile classFile = new ClassFile(); + ByteCodeIterator iter = new ByteCodeIterator(codes); + //1 先解析魔数 + String magicNumber = iter.nextU4ToHexString(); + if(!magicNumber.equals("cafebabe")){ + return null; + } + + //2 解析次版本号 主版本号 + classFile.setMinorVersion(iter.nextU2ToInt()); + classFile.setMajorVersion(iter.nextU2ToInt()); + + //3 解析常量池 + ConstantPool constantPool = parseConstantPool(iter); + classFile.setConstPool(constantPool); + + //4 解析访问标志 + AccessFlag accessFlag = parseAccessFlag(iter); + classFile.setAccessFlag(accessFlag); + + //5 解析类索引,父类索引,接口索引 + ClassIndex classIndex = parseClassInfex(iter); + classFile.setClassIndex(classIndex); + + return classFile; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + return new AccessFlag(iter.nextU2ToInt()); + } + + private ClassIndex parseClassInfex(ByteCodeIterator iter) { + ClassIndex classIndex = new ClassIndex(); + classIndex.setThisClassIndex(iter.nextU2ToInt()); + classIndex.setSuperClassIndex(iter.nextU2ToInt()); + return classIndex; + } + + private ConstantPool parseConstantPool(ByteCodeIterator iter) { + //常量池容量计数值,从1开始,不引用任何一个常量池项目就标为0 + int countConstant = iter.nextU2ToInt(); + + ConstantPool constantPool = new ConstantPool(); + + //先设置第0个常量项 + constantPool.addConstantInfo(new NullConstantInfo()); + + for(int i=1; i<countConstant; i++){ + int tag = iter.nextU1toInt(); + switch (tag){ + case 1 : + //utf-8编码的字符串 + UTF8Info utf8Str = new UTF8Info(constantPool); + + //解析字符串长度 + int length = iter.nextU2ToInt(); + utf8Str.setLength(length); + //根据长度解析出字符串 + byte[] bytes = iter.getBytes(length); + try { + utf8Str.setValue(new String(bytes,"UTF-8")); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + constantPool.addConstantInfo(utf8Str); + break; + + case 7: + //指向全限定名常量项的索引 + ClassInfo classInfo = new ClassInfo(constantPool); + + int index = iter.nextU2ToInt(); + classInfo.setUtf8Index(index); + + constantPool.addConstantInfo(classInfo); + break; + + case 8: + //指向字符串字面量的索引 + StringInfo stringInfo = new StringInfo(constantPool); + stringInfo.setIndex(iter.nextU2ToInt()); + constantPool.addConstantInfo(stringInfo); + break; + + case 9: + //指向声明字段的类或者接口的Class_info的索引项 + FieldRefInfo fieldRefInfo = new FieldRefInfo(constantPool); + fieldRefInfo.setClassInfoIndex(iter.nextU2ToInt()); + fieldRefInfo.setNameAndTypeIndex(iter.nextU2ToInt()); + constantPool.addConstantInfo(fieldRefInfo); + break; + + case 10: + //指向声明方法的类描述符class_info的索引项 + MethodRefInfo methodRefInfo = new MethodRefInfo(constantPool); + methodRefInfo.setClassInfoIndex(iter.nextU2ToInt()); + methodRefInfo.setNameAndTypeIndex(iter.nextU2ToInt()); + constantPool.addConstantInfo(methodRefInfo); + break; + + case 12: + //指向该字段或方法名称的常量项的索引 + NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(constantPool); + nameAndTypeInfo.setIndex1(iter.nextU2ToInt()); + nameAndTypeInfo.setIndex2(iter.nextU2ToInt()); + constantPool.addConstantInfo(nameAndTypeInfo); + break; + + default: + throw new RuntimeException("the constant pool tag " + tag + " has not been implemented yet."); + } + } + return constantPool; + } + + +} diff --git a/group24/798277403/src/mini_jvm/test/ClassFileloaderTest.java b/group24/798277403/src/mini_jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..e95035946a --- /dev/null +++ b/group24/798277403/src/mini_jvm/test/ClassFileloaderTest.java @@ -0,0 +1,189 @@ +package mini_jvm.test; + +import mini_jvm.clz.ClassFile; +import mini_jvm.clz.ClassIndex; +import mini_jvm.constant.*; +import mini_jvm.loader.ClassFileLoader; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + + + + + + +public class ClassFileloaderTest { + + + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + + static String path2 = "C:\\Users\\zhouliang\\Desktop\\mycoding\\"; + static String path3 = "C:\\Users\\zhouliang\\Desktop\\mycoding\\coding2017\\group24\\798277403\\out\\production\\zhouliang"; + + + static ClassFile clzFile = null; + static { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path2); + 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(path2); + loader.addClassPath(path3); + + String clzPath = loader.getClassPath(); + + Assert.assertEquals(path2+";"+path3,clzPath); + + } + + @Test + public void testClassFileLength() { + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path3); + + String className = "week4.test.EmployeeV1"; + + byte[] byteCodes = loader.readBinaryCode(className); + + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + Assert.assertEquals(1030, byteCodes.length); + + } + + @Test + public void testMagicNumber(){ + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path3); + String className = "week4.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(); + } + + /** + * ---------------------------------------------------------------------- + */ + + + @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("<init>", 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/798277403/src/mini_jvm/test/EmployeeV1.java b/group24/798277403/src/mini_jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..aed78de928 --- /dev/null +++ b/group24/798277403/src/mini_jvm/test/EmployeeV1.java @@ -0,0 +1,28 @@ +package mini_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/group24/798277403/src/mini_jvm/util/Util.java b/group24/798277403/src/mini_jvm/util/Util.java new file mode 100644 index 0000000000..bc2e724f03 --- /dev/null +++ b/group24/798277403/src/mini_jvm/util/Util.java @@ -0,0 +1,22 @@ +package mini_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/group24/798277403/src/week2/litestruts/struts.xml b/group24/798277403/src/week2/litestruts/struts.xml deleted file mode 100644 index 54550a4174..0000000000 --- a/group24/798277403/src/week2/litestruts/struts.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<struts> - <action name="login" class="week2.litestruts.LoginAction"> - <result name="success">/jsp/homepage.jsp</result> - <result name="fail">/jsp/showLogin.jsp</result> - </action> - <action name="logout" class="week2.litestruts.LogoutAction"> - <result name="success">/jsp/welcome.jsp</result> - <result name="error">/jsp/error.jsp</result> - </action> -</struts> diff --git a/group24/798277403/src/week4/loader/ClassFileLoader.java b/group24/798277403/src/week4/loader/ClassFileLoader.java deleted file mode 100644 index 90bce86e77..0000000000 --- a/group24/798277403/src/week4/loader/ClassFileLoader.java +++ /dev/null @@ -1,67 +0,0 @@ -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<String> clzPaths = new ArrayList<String>(); - - 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<clzPaths.size(); i++){ - if(i!=clzPaths.size()-1){ - stringBuilder.append(clzPaths.get(i)).append(";"); - }else{ - stringBuilder.append(clzPaths.get(i)); - } - } - return stringBuilder.toString(); - } -} diff --git a/group24/798277403/src/week4/test/ClassFileloaderTest.java b/group24/798277403/src/week4/test/ClassFileloaderTest.java deleted file mode 100644 index aa8a84176a..0000000000 --- a/group24/798277403/src/week4/test/ClassFileloaderTest.java +++ /dev/null @@ -1,84 +0,0 @@ -package week4.test; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import week4.loader.ClassFileLoader; - -/** - * Created by zhouliang on 2017-04-04. - */ -public class ClassFileloaderTest { - static String path1 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\mini-jvm\\bin"; - static String path2 = "C:\temp"; - static String path3 = "C:\\Users\\zhouliang\\Desktop\\mycoding\\coding2017\\group24\\798277403\\out\\production\\zhouliang"; - - - @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(path3); - - String className = "week3.DownloadThread"; - - byte[] byteCodes = loader.readBinaryCode(className); - - // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 - Assert.assertEquals(1751, byteCodes.length); - - } - - - @Test - public void testMagicNumber(){ - ClassFileLoader loader = new ClassFileLoader(); - loader.addClassPath(path3); - String className = "week4.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/group24/798277403/src/week4/test/EmployeeV1.java b/group24/798277403/src/week4/test/EmployeeV1.java deleted file mode 100644 index bed0f03722..0000000000 --- a/group24/798277403/src/week4/test/EmployeeV1.java +++ /dev/null @@ -1,29 +0,0 @@ -package week4.test; - -/** - * Created by zhouliang on 2017-04-04. - */ -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 e811eafda50f1157f2e4e001d418f433173dce2e Mon Sep 17 00:00:00 2001 From: Haochen <haochen_233333@163.com> Date: Thu, 13 Apr 2017 11:47:17 +0800 Subject: [PATCH 249/287] refactor class file loading --- .../code/src/main/java/jvm/attr/CodeAttr.java | 57 -------------- .../java/jvm/attr/LineNumberTableAttr.java | 52 ------------- .../main/java/jvm/attr/LocalVariableItem.java | 39 ---------- .../java/jvm/attr/LocalVariableTableAttr.java | 75 ------------------- .../main/java/jvm/attr/StackMapTableAttr.java | 28 ------- .../main/java/jvm/classfile/ClassFile.java | 25 ++++--- .../main/java/jvm/classfile/ClassParser.java | 29 +++++-- .../attribute/item}/AttributeInfo.java | 4 +- .../attribute/item/impl/CodeAttr.java | 38 ++++++++++ .../item/impl/LineNumberTableAttr.java | 37 +++++++++ .../item/impl/LocalVariableTableAttr.java | 52 +++++++++++++ .../attribute/item/impl/SourceFileAttr.java | 16 ++++ .../item/impl/StackMapTableAttr.java | 12 +++ .../attribute/parser/AttributeInfoParser.java | 14 ++++ .../attribute/parser}/AttributeParser.java | 12 ++- .../attribute/parser/impl/CodeParser.java | 36 +++++++++ .../parser/impl/LineNumberTableParser.java | 33 ++++++++ .../parser/impl/LocalVariableTableParser.java | 37 +++++++++ .../parser/impl/SourceFileParser.java | 20 +++++ .../parser/impl/StackMapTableParser.java | 25 +++++++ .../constant/item/impl/CountConstant.java | 1 - .../constant/item/impl/DoubleInfo.java | 1 - .../constant/item/impl/FieldRefInfo.java | 1 - .../constant/item/impl/FloatInfo.java | 1 - .../constant/item/impl/IntegerInfo.java | 2 - .../constant/item/impl/InvokeDynamicInfo.java | 1 - .../constant/item/impl/LongInfo.java | 1 - .../constant/item/impl/MethodHandleInfo.java | 1 - .../constant/item/impl/MethodRefInfo.java | 1 - .../constant/item/impl/MethodTypeInfo.java | 1 - .../constant/item/impl/NameAndTypeInfo.java | 1 - .../constant/item/impl/StringInfo.java | 14 +++- .../constant/item/impl/UTF8Info.java | 1 - .../java/jvm/{ => classfile}/field/Field.java | 6 +- .../jvm/{ => classfile}/method/Method.java | 7 +- .../test/java/jvm/ClassFileLoaderTest.java | 6 +- 36 files changed, 386 insertions(+), 301 deletions(-) delete mode 100644 group01/895457260/code/src/main/java/jvm/attr/CodeAttr.java delete mode 100644 group01/895457260/code/src/main/java/jvm/attr/LineNumberTableAttr.java delete mode 100644 group01/895457260/code/src/main/java/jvm/attr/LocalVariableItem.java delete mode 100644 group01/895457260/code/src/main/java/jvm/attr/LocalVariableTableAttr.java delete mode 100644 group01/895457260/code/src/main/java/jvm/attr/StackMapTableAttr.java rename group01/895457260/code/src/main/java/jvm/{attr => classfile/attribute/item}/AttributeInfo.java (84%) create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/attribute/item/impl/CodeAttr.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/attribute/item/impl/LineNumberTableAttr.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/attribute/item/impl/LocalVariableTableAttr.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/attribute/item/impl/SourceFileAttr.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/attribute/item/impl/StackMapTableAttr.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/AttributeInfoParser.java rename group01/895457260/code/src/main/java/jvm/{attr => classfile/attribute/parser}/AttributeParser.java (70%) create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/impl/CodeParser.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/impl/LineNumberTableParser.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/impl/LocalVariableTableParser.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/impl/SourceFileParser.java create mode 100644 group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/impl/StackMapTableParser.java rename group01/895457260/code/src/main/java/jvm/{ => classfile}/field/Field.java (92%) rename group01/895457260/code/src/main/java/jvm/{ => classfile}/method/Method.java (90%) diff --git a/group01/895457260/code/src/main/java/jvm/attr/CodeAttr.java b/group01/895457260/code/src/main/java/jvm/attr/CodeAttr.java deleted file mode 100644 index 7c7966f149..0000000000 --- a/group01/895457260/code/src/main/java/jvm/attr/CodeAttr.java +++ /dev/null @@ -1,57 +0,0 @@ -package jvm.attr; - -import jvm.classfile.ConstantPool; -import jvm.util.ByteCodeIterator; - -import java.util.ArrayList; -import java.util.List; - -public class CodeAttr extends AttributeInfo { - private int maxStack; - private int maxLocals; - private int codeLen; - private String code; - private List<AttributeInfo> attributes = new ArrayList<>(); - //private ByteCodeCommand[] cmds ; - - //public ByteCodeCommand[] getCmds() { - // return cmds; - //} - - private CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, - int codeLen, String code /*ByteCodeCommand[] cmds*/) { - super(attrNameIndex, attrLen); - this.maxStack = maxStack; - this.maxLocals = maxLocals; - this.codeLen = codeLen; - this.code = code; - //this.cmds = cmds; - } - - public static CodeAttr parse(int attrNameIndex, int attrLen, - ByteCodeIterator iterator, ConstantPool constantPool) { - int maxStack = iterator.nextU2ToInt(); - int maxLocals = iterator.nextU2ToInt(); - int codeLen = iterator.nextU4ToInt(); - String code = iterator.nextHexString(codeLen); - - int exceptionTableLen = iterator.nextU2ToInt(); - iterator.skip(exceptionTableLen * 8); - - CodeAttr result = new CodeAttr(attrNameIndex, attrLen, maxStack, maxLocals, codeLen, code); - - int attrCount = iterator.nextU2ToInt(); - for (int i = 0; i < attrCount; ++i) { - result.attributes.add(AttributeParser.parse(iterator, constantPool)); - } - return result; - } - - public String getCode() { - return code; - } - - public List<AttributeInfo> getAttributes() { - return attributes; - } -} diff --git a/group01/895457260/code/src/main/java/jvm/attr/LineNumberTableAttr.java b/group01/895457260/code/src/main/java/jvm/attr/LineNumberTableAttr.java deleted file mode 100644 index ab7a9d6adb..0000000000 --- a/group01/895457260/code/src/main/java/jvm/attr/LineNumberTableAttr.java +++ /dev/null @@ -1,52 +0,0 @@ -package jvm.attr; - -import jvm.classfile.ConstantPool; -import jvm.util.ByteCodeIterator; - -import java.util.ArrayList; -import java.util.List; - -public class LineNumberTableAttr extends AttributeInfo { - private List<LineNumberItem> items = new ArrayList<>(); - - private LineNumberTableAttr(int attrNameIndex, int attrLen) { - super(attrNameIndex, attrLen); - } - - public static LineNumberTableAttr parse(int attrNameIndex, int attrLen, - ByteCodeIterator iterator, ConstantPool constantPool) { - int tableLength = iterator.nextU2ToInt(); - - LineNumberTableAttr result = new LineNumberTableAttr(attrNameIndex, attrLen); - - for (int i = 0; i < tableLength; ++i) { - int startPC = iterator.nextU2ToInt(); - int lineNumber = iterator.nextU2ToInt(); - LineNumberItem item = new LineNumberItem(startPC, lineNumber); - result.items.add(item); - } - return result; - } - - public List<LineNumberItem> getItems() { - return items; - } - - public static class LineNumberItem { - private int startPc; - private int lineNumber; - - private LineNumberItem(int startPc, int lineNumber) { - this.startPc = startPc; - this.lineNumber = lineNumber; - } - - public int getStartPc() { - return startPc; - } - - public int getLineNumber() { - return lineNumber; - } - } -} diff --git a/group01/895457260/code/src/main/java/jvm/attr/LocalVariableItem.java b/group01/895457260/code/src/main/java/jvm/attr/LocalVariableItem.java deleted file mode 100644 index cc408c9f3e..0000000000 --- a/group01/895457260/code/src/main/java/jvm/attr/LocalVariableItem.java +++ /dev/null @@ -1,39 +0,0 @@ -package jvm.attr; - -public class LocalVariableItem { - private int startPC; - private int length; - private int nameIndex; - private int descIndex; - private int index; - public int getStartPC() { - return startPC; - } - public void setStartPC(int startPC) { - this.startPC = startPC; - } - public int getLength() { - return length; - } - public void setLength(int length) { - this.length = length; - } - public int getNameIndex() { - return nameIndex; - } - public void setNameIndex(int nameIndex) { - this.nameIndex = nameIndex; - } - public int getDescIndex() { - return descIndex; - } - public void setDescIndex(int descIndex) { - this.descIndex = descIndex; - } - public int getIndex() { - return index; - } - public void setIndex(int index) { - this.index = index; - } -} diff --git a/group01/895457260/code/src/main/java/jvm/attr/LocalVariableTableAttr.java b/group01/895457260/code/src/main/java/jvm/attr/LocalVariableTableAttr.java deleted file mode 100644 index 1d2f4e9f31..0000000000 --- a/group01/895457260/code/src/main/java/jvm/attr/LocalVariableTableAttr.java +++ /dev/null @@ -1,75 +0,0 @@ -package jvm.attr; - - -import jvm.classfile.ConstantPool; -import jvm.util.ByteCodeIterator; - -import java.util.ArrayList; -import java.util.List; - -public class LocalVariableTableAttr extends AttributeInfo { - - List<LocalVariableItem> items = new ArrayList<>(); - - public LocalVariableTableAttr(int attrNameIndex, int attrLen) { - super(attrNameIndex, attrLen); - } - - public static LocalVariableTableAttr parse(int attrNameIndex, int attrLen, - ByteCodeIterator iterator, ConstantPool constantPool) { - int tableLen = iterator.nextU2ToInt(); - - LocalVariableTableAttr result = new LocalVariableTableAttr(attrNameIndex, attrLen); - - for (int i = 0; i < tableLen; ++i) { - int startPC = iterator.nextU2ToInt(); - int length = iterator.nextU2ToInt(); - int nameIndex = iterator.nextU2ToInt(); - int descIndex = iterator.nextU2ToInt(); - int index = iterator.nextU2ToInt(); - LocalVariableItem item = new LocalVariableItem(startPC, length, nameIndex, descIndex, index); - result.items.add(item); - } - return result; - } - - private void addLocalVariableItem(LocalVariableItem item) { - this.items.add(item); - } - - public static class LocalVariableItem { - private int startPC; - private int length; - private int nameIndex; - private int descIndex; - private int index; - - private LocalVariableItem(int startPC, int length, int nameIndex, int descIndex, int index) { - this.startPC = startPC; - this.length = length; - this.nameIndex = nameIndex; - this.descIndex = descIndex; - this.index = index; - } - - public int getStartPC() { - return startPC; - } - - public int getLength() { - return length; - } - - public int getNameIndex() { - return nameIndex; - } - - public int getDescIndex() { - return descIndex; - } - - public int getIndex() { - return index; - } - } -} diff --git a/group01/895457260/code/src/main/java/jvm/attr/StackMapTableAttr.java b/group01/895457260/code/src/main/java/jvm/attr/StackMapTableAttr.java deleted file mode 100644 index e9a1b6987c..0000000000 --- a/group01/895457260/code/src/main/java/jvm/attr/StackMapTableAttr.java +++ /dev/null @@ -1,28 +0,0 @@ -package jvm.attr; - -import jvm.util.ByteCodeIterator; - -public class StackMapTableAttr extends AttributeInfo{ - - private String originalCode; - - private StackMapTableAttr(int attrNameIndex, int attrLen) { - super(attrNameIndex, attrLen); - } - - public static StackMapTableAttr parse(ByteCodeIterator iterator) { - int index = iterator.nextU2ToInt(); - int len = iterator.nextU4ToInt(); - StackMapTableAttr result = new StackMapTableAttr(index, len); - - //后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 - String code = iterator.nextHexString(len); - result.setOriginalCode(code); - - return result; - } - - private void setOriginalCode(String code) { - this.originalCode = code; - } -} 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 3f3fe9112d..41f983a086 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/ClassFile.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/ClassFile.java @@ -1,9 +1,10 @@ package jvm.classfile; +import jvm.classfile.attribute.item.AttributeInfo; import jvm.classfile.constant.item.impl.ClassInfo; -import jvm.field.Field; -import jvm.method.Method; +import jvm.classfile.field.Field; +import jvm.classfile.method.Method; import java.util.ArrayList; import java.util.List; @@ -18,23 +19,25 @@ public class ClassFile { ConstantPool constantPool; int minorVersion; int majorVersion; + List<ClassInfo> interfaces = new ArrayList<>(); List<Field> fields = new ArrayList<>(); List<Method> methods = new ArrayList<>(); + List<AttributeInfo> attributes = new ArrayList<>(); - public void addField(Field f){ - this.fields.add(f); + public List<ClassInfo> getInterfaces() { + return this.interfaces; } - public List<Field> getFields(){ + public List<Field> getFields() { return this.fields; } - public void addMethod(Method m){ - this.methods.add(m); - } public List<Method> getMethods() { return methods; } + public List<AttributeInfo> getAttributes() { + return attributes; + } - public void print(){ + public void print() { if(this.accessFlag.isPublicClass()){ System.out.println("Access flag : public "); } @@ -42,13 +45,13 @@ public void print(){ System.out.println("Super Class Name:"+ getSuperClassName()); } - private String getClassName(){ + private String getClassName() { int thisClassIndex = this.classIndex.getThisClassIndex(); ClassInfo thisClass = (ClassInfo)this.getConstantPool().getConstantInfo(thisClassIndex); return thisClass.getClassName(); } - private String getSuperClassName(){ + private String getSuperClassName() { ClassInfo superClass = (ClassInfo)this.getConstantPool() .getConstantInfo(this.classIndex.getSuperClassIndex()); return superClass.getClassName(); 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 7d9ff72eb4..fa3a07527d 100644 --- a/group01/895457260/code/src/main/java/jvm/classfile/ClassParser.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/ClassParser.java @@ -1,15 +1,16 @@ package jvm.classfile; +import jvm.classfile.attribute.item.AttributeInfo; +import jvm.classfile.attribute.parser.AttributeParser; import jvm.classfile.constant.item.IReference; +import jvm.classfile.constant.item.impl.ClassInfo; import jvm.classfile.constant.item.impl.CountConstant; import jvm.classfile.constant.parser.ConstantParser; import jvm.classfile.constant.parser.ConstantParserFactory; -import jvm.field.Field; -import jvm.method.Method; +import jvm.classfile.field.Field; +import jvm.classfile.method.Method; import jvm.util.ByteCodeIterator; -import java.util.Collection; - /** * Created by Haochen on 2017/4/9. * TODO: @@ -26,13 +27,22 @@ public static ClassFile parse(byte[] bytes) { classFile.constantPool = parseConstantPool(iterator); classFile.accessFlag = parseAccessFlag(iterator); classFile.classIndex = parseClassIndex(iterator); - parseInterfaces(iterator); + parseInterfaces(classFile, iterator); parseFields(classFile, iterator); parseMethods(classFile, iterator); + parseAttributes(classFile, iterator); linkConstantReferences(classFile); return classFile; } + private static void parseAttributes(ClassFile classFile, ByteCodeIterator iterator) { + int count = iterator.nextU2ToInt(); + for (int i = 0; i < count; ++i) { + AttributeInfo attribute = AttributeParser.parse(iterator, classFile.constantPool); + classFile.attributes.add(attribute); + } + } + private static int parseMinorVersion(ByteCodeIterator iterator) { return iterator.nextU2ToInt(); } @@ -68,9 +78,14 @@ private static ClassIndex parseClassIndex(ByteCodeIterator iterator) { return classIndex; } - private static void parseInterfaces(ByteCodeIterator iterator) { + private static void parseInterfaces(ClassFile classFile, ByteCodeIterator iterator) { int count = iterator.nextU2ToInt(); - iterator.skip(count * 2); + ConstantPool constantPool = classFile.constantPool; + for (int i = 0; i < count; ++i) { + int index = iterator.nextU2ToInt(); + ClassInfo info = (ClassInfo) constantPool.getConstantInfo(index); + classFile.interfaces.add(info); + } } private static void parseFields(ClassFile classFile, ByteCodeIterator iterator) { diff --git a/group01/895457260/code/src/main/java/jvm/attr/AttributeInfo.java b/group01/895457260/code/src/main/java/jvm/classfile/attribute/item/AttributeInfo.java similarity index 84% rename from group01/895457260/code/src/main/java/jvm/attr/AttributeInfo.java rename to group01/895457260/code/src/main/java/jvm/classfile/attribute/item/AttributeInfo.java index 1ae5cb4c53..595c12ac9b 100644 --- a/group01/895457260/code/src/main/java/jvm/attr/AttributeInfo.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/attribute/item/AttributeInfo.java @@ -1,4 +1,4 @@ -package jvm.attr; +package jvm.classfile.attribute.item; public abstract class AttributeInfo { public static final String CODE = "Code"; @@ -11,7 +11,7 @@ public abstract class AttributeInfo { int attrNameIndex; int attrLen; - AttributeInfo(int attrNameIndex, int attrLen) { + public AttributeInfo(int attrNameIndex, int attrLen) { this.attrNameIndex = attrNameIndex; this.attrLen = attrLen; } diff --git a/group01/895457260/code/src/main/java/jvm/classfile/attribute/item/impl/CodeAttr.java b/group01/895457260/code/src/main/java/jvm/classfile/attribute/item/impl/CodeAttr.java new file mode 100644 index 0000000000..75c7383bd8 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/attribute/item/impl/CodeAttr.java @@ -0,0 +1,38 @@ +package jvm.classfile.attribute.item.impl; + +import jvm.classfile.attribute.item.AttributeInfo; + +import java.util.ArrayList; +import java.util.List; + +public class CodeAttr extends AttributeInfo { + private int maxStack; + private int maxLocals; + private int codeLen; + private String code; + private List<AttributeInfo> attributes = new ArrayList<>(); + //private ByteCodeCommand[] cmds ; + + //public ByteCodeCommand[] getCmds() { + // return cmds; + //} + + public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, + int codeLen, String code, List<AttributeInfo> attributes /*ByteCodeCommand[] cmds*/) { + super(attrNameIndex, attrLen); + this.maxStack = maxStack; + this.maxLocals = maxLocals; + this.codeLen = codeLen; + this.code = code; + this.attributes = attributes; + //this.cmds = cmds; + } + + public String getCode() { + return code; + } + + public List<AttributeInfo> getAttributes() { + return attributes; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/attribute/item/impl/LineNumberTableAttr.java b/group01/895457260/code/src/main/java/jvm/classfile/attribute/item/impl/LineNumberTableAttr.java new file mode 100644 index 0000000000..c2a75a95c5 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/attribute/item/impl/LineNumberTableAttr.java @@ -0,0 +1,37 @@ +package jvm.classfile.attribute.item.impl; + +import jvm.classfile.attribute.item.AttributeInfo; + +import java.util.ArrayList; +import java.util.List; + +public class LineNumberTableAttr extends AttributeInfo { + private List<LineNumberItem> items = new ArrayList<>(); + + public LineNumberTableAttr(int attrNameIndex, int attrLen, List<LineNumberItem> items) { + super(attrNameIndex, attrLen); + this.items = items; + } + + public List<LineNumberItem> getItems() { + return items; + } + + public static class LineNumberItem { + private int startPc; + private int lineNumber; + + public LineNumberItem(int startPc, int lineNumber) { + this.startPc = startPc; + this.lineNumber = lineNumber; + } + + public int getStartPc() { + return startPc; + } + + public int getLineNumber() { + return lineNumber; + } + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/attribute/item/impl/LocalVariableTableAttr.java b/group01/895457260/code/src/main/java/jvm/classfile/attribute/item/impl/LocalVariableTableAttr.java new file mode 100644 index 0000000000..fce15e7365 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/attribute/item/impl/LocalVariableTableAttr.java @@ -0,0 +1,52 @@ +package jvm.classfile.attribute.item.impl; + +import jvm.classfile.attribute.item.AttributeInfo; + +import java.util.ArrayList; +import java.util.List; + +public class LocalVariableTableAttr extends AttributeInfo { + + List<LocalVariableItem> items = new ArrayList<>(); + + public LocalVariableTableAttr(int attrNameIndex, int attrLen, List<LocalVariableItem> items) { + super(attrNameIndex, attrLen); + this.items = items; + } + + public static class LocalVariableItem { + private int startPC; + private int length; + private int nameIndex; + private int descIndex; + private int index; + + public LocalVariableItem(int startPC, int length, int nameIndex, int descIndex, int index) { + this.startPC = startPC; + this.length = length; + this.nameIndex = nameIndex; + this.descIndex = descIndex; + this.index = index; + } + + public int getStartPC() { + return startPC; + } + + public int getLength() { + return length; + } + + public int getNameIndex() { + return nameIndex; + } + + public int getDescIndex() { + return descIndex; + } + + public int getIndex() { + return index; + } + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/attribute/item/impl/SourceFileAttr.java b/group01/895457260/code/src/main/java/jvm/classfile/attribute/item/impl/SourceFileAttr.java new file mode 100644 index 0000000000..55921f5035 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/attribute/item/impl/SourceFileAttr.java @@ -0,0 +1,16 @@ +package jvm.classfile.attribute.item.impl; + +import jvm.classfile.attribute.item.AttributeInfo; + +/** + * Created by Haochen on 2017/4/13. + * TODO: + */ +public class SourceFileAttr extends AttributeInfo { + private int sourceFileIndex; + + public SourceFileAttr(int attrNameIndex, int attrLen, int sourceFileIndex) { + super(attrNameIndex, attrLen); + this.sourceFileIndex = sourceFileIndex; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/attribute/item/impl/StackMapTableAttr.java b/group01/895457260/code/src/main/java/jvm/classfile/attribute/item/impl/StackMapTableAttr.java new file mode 100644 index 0000000000..cda2709020 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/attribute/item/impl/StackMapTableAttr.java @@ -0,0 +1,12 @@ +package jvm.classfile.attribute.item.impl; + +import jvm.classfile.attribute.item.AttributeInfo; + +public class StackMapTableAttr extends AttributeInfo { + private String originalCode; + + public StackMapTableAttr(int attrNameIndex, int attrLen, String originalCode) { + super(attrNameIndex, attrLen); + this.originalCode = originalCode; + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/AttributeInfoParser.java b/group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/AttributeInfoParser.java new file mode 100644 index 0000000000..7ac80cf179 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/AttributeInfoParser.java @@ -0,0 +1,14 @@ +package jvm.classfile.attribute.parser; + +import jvm.classfile.attribute.item.AttributeInfo; +import jvm.classfile.ConstantPool; +import jvm.util.ByteCodeIterator; + +/** + * Created by Haochen on 2017/4/13. + * TODO: + */ +public interface AttributeInfoParser { + AttributeInfo parse(int attrNameIndex, int attrLen, + ByteCodeIterator iterator, ConstantPool constantPool); +} diff --git a/group01/895457260/code/src/main/java/jvm/attr/AttributeParser.java b/group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/AttributeParser.java similarity index 70% rename from group01/895457260/code/src/main/java/jvm/attr/AttributeParser.java rename to group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/AttributeParser.java index d389b71ef3..e67850037b 100644 --- a/group01/895457260/code/src/main/java/jvm/attr/AttributeParser.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/AttributeParser.java @@ -1,5 +1,6 @@ -package jvm.attr; +package jvm.classfile.attribute.parser; +import jvm.classfile.attribute.item.AttributeInfo; import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.impl.UTF8Info; import jvm.util.ByteCodeIterator; @@ -17,15 +18,18 @@ public static AttributeInfo parse(ByteCodeIterator iterator, ConstantPool consta String name = ((UTF8Info) constantPool.getConstantInfo(nameIndex)).getValue(); int length = iterator.nextU4ToInt(); - String className = AttributeParser.class.getPackage().getName() + '.' + name + "Attr"; + String className = AttributeParser.class.getPackage().getName() + + ".impl." + name + "Parser"; try { Class<?> clazz = Class.forName(className); Method parse = clazz.getMethod("parse", int.class, int.class, ByteCodeIterator.class, ConstantPool.class); byte[] bytes = iterator.getBytes(length); ByteCodeIterator subIterator = new ByteCodeIterator(bytes); - return (AttributeInfo) parse.invoke(null, nameIndex, length, subIterator, constantPool); - } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + return (AttributeInfo) parse.invoke(clazz.newInstance(), + nameIndex, length, subIterator, constantPool); + } catch (ClassNotFoundException | NoSuchMethodException + | IllegalAccessException | InvocationTargetException | InstantiationException e) { e.printStackTrace(); } return null; diff --git a/group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/impl/CodeParser.java b/group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/impl/CodeParser.java new file mode 100644 index 0000000000..2ee74f020a --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/impl/CodeParser.java @@ -0,0 +1,36 @@ +package jvm.classfile.attribute.parser.impl; + +import jvm.classfile.attribute.item.AttributeInfo; +import jvm.classfile.attribute.parser.AttributeParser; +import jvm.classfile.attribute.item.impl.CodeAttr; +import jvm.classfile.attribute.parser.AttributeInfoParser; +import jvm.classfile.ConstantPool; +import jvm.util.ByteCodeIterator; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Haochen on 2017/4/13. + * TODO: + */ +public class CodeParser implements AttributeInfoParser { + @Override + public AttributeInfo parse(int attrNameIndex, int attrLen, + ByteCodeIterator iterator, ConstantPool constantPool) { + int maxStack = iterator.nextU2ToInt(); + int maxLocals = iterator.nextU2ToInt(); + int codeLen = iterator.nextU4ToInt(); + String code = iterator.nextHexString(codeLen); + + int exceptionTableLen = iterator.nextU2ToInt(); + iterator.skip(exceptionTableLen * 8); + + int attrCount = iterator.nextU2ToInt(); + List<AttributeInfo> attributes = new ArrayList<>(); + for (int i = 0; i < attrCount; ++i) { + attributes.add(AttributeParser.parse(iterator, constantPool)); + } + return new CodeAttr(attrNameIndex, attrLen, maxStack, maxLocals, codeLen, code, attributes); + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/impl/LineNumberTableParser.java b/group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/impl/LineNumberTableParser.java new file mode 100644 index 0000000000..8586ada746 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/impl/LineNumberTableParser.java @@ -0,0 +1,33 @@ +package jvm.classfile.attribute.parser.impl; + +import jvm.classfile.attribute.item.AttributeInfo; +import jvm.classfile.attribute.item.impl.LineNumberTableAttr; +import jvm.classfile.attribute.parser.AttributeInfoParser; +import jvm.classfile.ConstantPool; +import jvm.util.ByteCodeIterator; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Haochen on 2017/4/13. + * TODO: + */ +public class LineNumberTableParser implements AttributeInfoParser { + @Override + public AttributeInfo parse(int attrNameIndex, int attrLen, + ByteCodeIterator iterator, ConstantPool constantPool) { + int tableLength = iterator.nextU2ToInt(); + + List<LineNumberTableAttr.LineNumberItem> items = new ArrayList<>(); + + for (int i = 0; i < tableLength; ++i) { + int startPC = iterator.nextU2ToInt(); + int lineNumber = iterator.nextU2ToInt(); + LineNumberTableAttr.LineNumberItem item = + new LineNumberTableAttr.LineNumberItem(startPC, lineNumber); + items.add(item); + } + return new LineNumberTableAttr(attrNameIndex, attrLen, items); + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/impl/LocalVariableTableParser.java b/group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/impl/LocalVariableTableParser.java new file mode 100644 index 0000000000..9507ae3f37 --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/impl/LocalVariableTableParser.java @@ -0,0 +1,37 @@ +package jvm.classfile.attribute.parser.impl; + +import jvm.classfile.attribute.item.AttributeInfo; +import jvm.classfile.attribute.item.impl.LocalVariableTableAttr; +import jvm.classfile.attribute.parser.AttributeInfoParser; +import jvm.classfile.ConstantPool; +import jvm.util.ByteCodeIterator; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Haochen on 2017/4/13. + * TODO: + */ +public class LocalVariableTableParser implements AttributeInfoParser { + @Override + public AttributeInfo parse(int attrNameIndex, int attrLen, + ByteCodeIterator iterator, ConstantPool constantPool) { + int tableLen = iterator.nextU2ToInt(); + + List<LocalVariableTableAttr.LocalVariableItem> items = new ArrayList<>(); + + for (int i = 0; i < tableLen; ++i) { + int startPC = iterator.nextU2ToInt(); + int length = iterator.nextU2ToInt(); + int nameIndex = iterator.nextU2ToInt(); + int descIndex = iterator.nextU2ToInt(); + int index = iterator.nextU2ToInt(); + LocalVariableTableAttr.LocalVariableItem item = + new LocalVariableTableAttr.LocalVariableItem( + startPC, length, nameIndex, descIndex, index); + items.add(item); + } + return new LocalVariableTableAttr(attrNameIndex, attrLen ,items); + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/impl/SourceFileParser.java b/group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/impl/SourceFileParser.java new file mode 100644 index 0000000000..0c8561b21c --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/impl/SourceFileParser.java @@ -0,0 +1,20 @@ +package jvm.classfile.attribute.parser.impl; + +import jvm.classfile.attribute.item.AttributeInfo; +import jvm.classfile.attribute.item.impl.SourceFileAttr; +import jvm.classfile.attribute.parser.AttributeInfoParser; +import jvm.classfile.ConstantPool; +import jvm.util.ByteCodeIterator; + +/** + * Created by Haochen on 2017/4/13. + * TODO: + */ +public class SourceFileParser implements AttributeInfoParser { + @Override + public AttributeInfo parse(int attrNameIndex, int attrLen, + ByteCodeIterator iterator, ConstantPool constantPool) { + int sourceFileIndex = iterator.nextU2ToInt(); + return new SourceFileAttr(attrNameIndex, attrLen, sourceFileIndex); + } +} diff --git a/group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/impl/StackMapTableParser.java b/group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/impl/StackMapTableParser.java new file mode 100644 index 0000000000..087edcffcf --- /dev/null +++ b/group01/895457260/code/src/main/java/jvm/classfile/attribute/parser/impl/StackMapTableParser.java @@ -0,0 +1,25 @@ +package jvm.classfile.attribute.parser.impl; + +import jvm.classfile.attribute.item.AttributeInfo; +import jvm.classfile.attribute.item.impl.StackMapTableAttr; +import jvm.classfile.attribute.parser.AttributeInfoParser; +import jvm.classfile.ConstantPool; +import jvm.util.ByteCodeIterator; + +/** + * Created by Haochen on 2017/4/13. + * TODO: + */ +public class StackMapTableParser implements AttributeInfoParser { + @Override + public AttributeInfo parse(int attrNameIndex, int attrLen, + ByteCodeIterator iterator, ConstantPool constantPool) { + int index = iterator.nextU2ToInt(); + int len = iterator.nextU4ToInt(); + + //后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 + String code = iterator.nextHexString(len); + + return new StackMapTableAttr(index, len, code); + } +} 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 8d6593a1c0..1d671fcbda 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,6 +1,5 @@ package jvm.classfile.constant.item.impl; -import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.Constant; /** 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 b65e8d82db..8fa38452f6 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,6 +1,5 @@ package jvm.classfile.constant.item.impl; -import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.Constant; /** 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 ed5ba84212..a7f51f51ba 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,6 +1,5 @@ package jvm.classfile.constant.item.impl; -import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.Constant; /** 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 707d548586..1368c07674 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,6 +1,5 @@ package jvm.classfile.constant.item.impl; -import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.Constant; /** 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 2bbc08144d..e345f94994 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,8 +1,6 @@ package jvm.classfile.constant.item.impl; -import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.Constant; -import jvm.util.ByteUtils; /** * Created by Haochen on 2017/4/9. 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 0e8d478a2f..91caadbb46 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,6 +1,5 @@ package jvm.classfile.constant.item.impl; -import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.Constant; /** 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 7e61808e3a..c740e39f30 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,6 +1,5 @@ package jvm.classfile.constant.item.impl; -import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.Constant; /** 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 d1e32ec581..c7b6fbe4ac 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,6 +1,5 @@ package jvm.classfile.constant.item.impl; -import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.Constant; /** 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 41f1020359..c52903956c 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,6 +1,5 @@ package jvm.classfile.constant.item.impl; -import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.Constant; /** 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 4e4df13b48..9b7e7cba1f 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,6 +1,5 @@ package jvm.classfile.constant.item.impl; -import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.Constant; /** 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 dfc9b54b28..c783b969e7 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,6 +1,5 @@ package jvm.classfile.constant.item.impl; -import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.Constant; /** 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 c7b001c08e..6e7548db05 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 @@ -2,13 +2,15 @@ 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 StringInfo implements Constant { +public class StringInfo implements Constant, IReference { private int stringIndex; + private String value; public StringInfo(int stringIndex) { this.stringIndex = stringIndex; @@ -19,7 +21,13 @@ public int size() { return 3; } - public int getStringIndex() { - return stringIndex; + public String getValue() { + return value; + } + + @Override + public void linkReference(ConstantPool constantPool) { + UTF8Info info = (UTF8Info) constantPool.getConstantInfo(stringIndex); + value = info.getValue(); } } 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 42edd32e44..86d139fb7c 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,6 +1,5 @@ package jvm.classfile.constant.item.impl; -import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.Constant; import java.io.UnsupportedEncodingException; diff --git a/group01/895457260/code/src/main/java/jvm/field/Field.java b/group01/895457260/code/src/main/java/jvm/classfile/field/Field.java similarity index 92% rename from group01/895457260/code/src/main/java/jvm/field/Field.java rename to group01/895457260/code/src/main/java/jvm/classfile/field/Field.java index 4093449356..dcf6975543 100644 --- a/group01/895457260/code/src/main/java/jvm/field/Field.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/field/Field.java @@ -1,7 +1,7 @@ -package jvm.field; +package jvm.classfile.field; -import jvm.attr.AttributeInfo; -import jvm.attr.AttributeParser; +import jvm.classfile.attribute.item.AttributeInfo; +import jvm.classfile.attribute.parser.AttributeParser; import jvm.classfile.ConstantPool; import jvm.classfile.constant.item.impl.UTF8Info; import jvm.util.ByteCodeIterator; diff --git a/group01/895457260/code/src/main/java/jvm/method/Method.java b/group01/895457260/code/src/main/java/jvm/classfile/method/Method.java similarity index 90% rename from group01/895457260/code/src/main/java/jvm/method/Method.java rename to group01/895457260/code/src/main/java/jvm/classfile/method/Method.java index e9188eccc9..6068124fa3 100644 --- a/group01/895457260/code/src/main/java/jvm/method/Method.java +++ b/group01/895457260/code/src/main/java/jvm/classfile/method/Method.java @@ -1,8 +1,7 @@ -package jvm.method; +package jvm.classfile.method; -import jvm.attr.AttributeInfo; -import jvm.attr.AttributeParser; -import jvm.attr.CodeAttr; +import jvm.classfile.attribute.item.AttributeInfo; +import jvm.classfile.attribute.parser.AttributeParser; import jvm.classfile.ConstantPool; import jvm.util.ByteCodeIterator; diff --git a/group01/895457260/code/src/test/java/jvm/ClassFileLoaderTest.java b/group01/895457260/code/src/test/java/jvm/ClassFileLoaderTest.java index 3719b001ed..23a2341d8f 100644 --- a/group01/895457260/code/src/test/java/jvm/ClassFileLoaderTest.java +++ b/group01/895457260/code/src/test/java/jvm/ClassFileLoaderTest.java @@ -1,6 +1,6 @@ package jvm; -import jvm.attr.CodeAttr; +import jvm.classfile.attribute.item.impl.CodeAttr; import jvm.classfile.ClassFile; import jvm.classfile.ClassIndex; import jvm.classfile.ConstantPool; @@ -9,8 +9,8 @@ import jvm.classfile.constant.item.impl.NameAndTypeInfo; import jvm.classfile.constant.item.impl.UTF8Info; import jvm.exception.ReadClassException; -import jvm.field.Field; -import jvm.method.Method; +import jvm.classfile.field.Field; +import jvm.classfile.method.Method; import org.junit.After; import org.junit.Assert; import org.junit.Before; From 773f534676bcd11fdc905b268f5474a97a30c2b9 Mon Sep 17 00:00:00 2001 From: DonaldY <448641125@qq.com> Date: Thu, 13 Apr 2017 21:01:28 +0800 Subject: [PATCH 250/287] update --- group24/448641125/src/com/donaldy/jvm/test/EmployeeV1.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/group24/448641125/src/com/donaldy/jvm/test/EmployeeV1.java b/group24/448641125/src/com/donaldy/jvm/test/EmployeeV1.java index 41c3d22871..b4b35ce835 100644 --- a/group24/448641125/src/com/donaldy/jvm/test/EmployeeV1.java +++ b/group24/448641125/src/com/donaldy/jvm/test/EmployeeV1.java @@ -2,6 +2,7 @@ public class EmployeeV1 { + private String name; private int age; @@ -22,5 +23,6 @@ public void sayHello() { public static void main(String[] args){ EmployeeV1 p = new EmployeeV1("Andy",29); p.sayHello(); + } } \ No newline at end of file From 3268a72a0613931196c7916e3d2fad1daeaf3496 Mon Sep 17 00:00:00 2001 From: ZhaoHongxin <zhaohongxin621@126.com> Date: Thu, 13 Apr 2017 23:46:25 +0800 Subject: [PATCH 251/287] go on jvm --- .../coderising/jvm/attr/AttributeInfo.java | 19 + .../src/com/coderising/jvm/attr/CodeAttr.java | 56 +++ .../coderising/jvm/attr/LineNumberTable.java | 42 +++ .../jvm/attr/LocalVariableItem.java | 39 ++ .../jvm/attr/LocalVariableTable.java | 28 ++ .../coderising/jvm/attr/StackMapTable.java | 30 ++ .../src/com/coderising/jvm/clz/ClassFile.java | 17 +- .../src/com/coderising/jvm/field/Field.java | 45 +++ .../jvm/loader/ByteCodeIterator.java | 17 + .../jvm/loader/ClassFileParser.java | 29 ++ .../src/com/coderising/jvm/method/Method.java | 67 ++++ .../jvm/test/ClassFileloaderTest.java | 71 ++++ .../src/com/coding/basic/ArrayList.java | 79 +++++ .../src/com/coding/basic/ArrayListTest.java | 31 ++ .../src/com/coding/basic/BinaryTreeNode.java | 32 ++ .../src/com/coding/basic/Iterator.java | 7 + .../src/com/coding/basic/LinkedList.java | 334 ++++++++++++++++++ .../src/com/coding/basic/LinkedListTest.java | 79 +++++ .../mini-jvm/src/com/coding/basic/List.java | 10 + .../mini-jvm/src/com/coding/basic/Queue.java | 25 ++ .../src/com/coding/basic/QueueTest.java | 24 ++ .../mini-jvm/src/com/coding/basic/Stack.java | 28 ++ .../src/com/coding/basic/StackTest.java | 26 ++ 23 files changed, 1134 insertions(+), 1 deletion(-) create mode 100644 group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/AttributeInfo.java create mode 100644 group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java create mode 100644 group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java create mode 100644 group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/LocalVariableItem.java create mode 100644 group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java create mode 100644 group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/StackMapTable.java create mode 100644 group05/1094051862/mini-jvm/src/com/coderising/jvm/field/Field.java create mode 100644 group05/1094051862/mini-jvm/src/com/coderising/jvm/method/Method.java create mode 100644 group05/1094051862/mini-jvm/src/com/coding/basic/ArrayList.java create mode 100644 group05/1094051862/mini-jvm/src/com/coding/basic/ArrayListTest.java create mode 100644 group05/1094051862/mini-jvm/src/com/coding/basic/BinaryTreeNode.java create mode 100644 group05/1094051862/mini-jvm/src/com/coding/basic/Iterator.java create mode 100644 group05/1094051862/mini-jvm/src/com/coding/basic/LinkedList.java create mode 100644 group05/1094051862/mini-jvm/src/com/coding/basic/LinkedListTest.java create mode 100644 group05/1094051862/mini-jvm/src/com/coding/basic/List.java create mode 100644 group05/1094051862/mini-jvm/src/com/coding/basic/Queue.java create mode 100644 group05/1094051862/mini-jvm/src/com/coding/basic/QueueTest.java create mode 100644 group05/1094051862/mini-jvm/src/com/coding/basic/Stack.java create mode 100644 group05/1094051862/mini-jvm/src/com/coding/basic/StackTest.java diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/AttributeInfo.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/AttributeInfo.java new file mode 100644 index 0000000000..89fb53394e --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/AttributeInfo.java @@ -0,0 +1,19 @@ +package com.coderising.jvm.attr; + +public abstract class AttributeInfo { + public static final String CODE = "Code"; + public static final String CONST_VALUE = "ConstantValue"; + public static final String EXCEPTIONS = "Exceptions"; + public static final String LINE_NUM_TABLE = "LineNumberTable"; + public static final String LOCAL_VAR_TABLE = "LocalVariableTable"; + public static final String STACK_MAP_TABLE = "StackMapTable"; + int attrNameIndex; + int attrLen ; + public AttributeInfo(int attrNameIndex, int attrLen) { + + this.attrNameIndex = attrNameIndex; + this.attrLen = attrLen; + } + + +} diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java new file mode 100644 index 0000000000..b0c67b4b93 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java @@ -0,0 +1,56 @@ +package com.coderising.jvm.attr; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.loader.ByteCodeIterator; + + +public class CodeAttr extends AttributeInfo { + private int maxStack ; + private int maxLocals ; + private int codeLen ; + private String code; + public String getCode() { + return code; + } + + //private ByteCodeCommand[] cmds ; + //public ByteCodeCommand[] getCmds() { + // return cmds; + //} + private LineNumberTable lineNumTable; + private LocalVariableTable localVarTable; + private StackMapTable stackMapTable; + + public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen,String code /*ByteCodeCommand[] cmds*/) { + super(attrNameIndex, attrLen); + this.maxStack = maxStack; + this.maxLocals = maxLocals; + this.codeLen = codeLen; + this.code = code; + //this.cmds = cmds; + } + + public void setLineNumberTable(LineNumberTable t) { + this.lineNumTable = t; + } + + public void setLocalVariableTable(LocalVariableTable t) { + this.localVarTable = t; + } + + public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ + + + return null; + } + private void setStackMapTable(StackMapTable t) { + this.stackMapTable = t; + + } + + + + + +} diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java new file mode 100644 index 0000000000..22941f83b1 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java @@ -0,0 +1,42 @@ +package com.coderising.jvm.attr; + +import java.util.ArrayList; +import java.util.List; + +import com.coderising.jvm.loader.ByteCodeIterator; + +public class LineNumberTable extends AttributeInfo { + List<LineNumberItem> items = new ArrayList<LineNumberItem>(); + + private static class LineNumberItem{ + int startPC; + int lineNum; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLineNum() { + return lineNum; + } + public void setLineNum(int lineNum) { + this.lineNum = lineNum; + } + } + public void addLineNumberItem(LineNumberItem item){ + this.items.add(item); + } + public LineNumberTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + + } + + public static LineNumberTable parse(ByteCodeIterator iter){ + + return null; + } + + + +} diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/LocalVariableItem.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/LocalVariableItem.java new file mode 100644 index 0000000000..3eb2654e36 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/LocalVariableItem.java @@ -0,0 +1,39 @@ +package com.coderising.jvm.attr; + +public class LocalVariableItem { + private int startPC; + private int length; + private int nameIndex; + private int descIndex; + private int index; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getNameIndex() { + return nameIndex; + } + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + public int getDescIndex() { + return descIndex; + } + public void setDescIndex(int descIndex) { + this.descIndex = descIndex; + } + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } +} diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java new file mode 100644 index 0000000000..fa69dc9bdb --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java @@ -0,0 +1,28 @@ +package com.coderising.jvm.attr; + + +import java.util.ArrayList; +import java.util.List; + +import com.coderising.jvm.constant.ConstantPool; + +import com.coderising.jvm.loader.ByteCodeIterator; + +public class LocalVariableTable extends AttributeInfo{ + + List<LocalVariableItem> items = new ArrayList<LocalVariableItem>(); + + public LocalVariableTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static LocalVariableTable parse(ByteCodeIterator iter){ + + return null; + } + private void addLocalVariableItem(LocalVariableItem item) { + this.items.add(item); + } + + +} diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/StackMapTable.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/StackMapTable.java new file mode 100644 index 0000000000..44c5d90d46 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/StackMapTable.java @@ -0,0 +1,30 @@ +package com.coderising.jvm.attr; + + +import com.coderising.jvm.loader.ByteCodeIterator; + +public class StackMapTable extends AttributeInfo{ + + private String originalCode; + + public StackMapTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static StackMapTable parse(ByteCodeIterator iter){ + int index = iter.nextU2ToInt(); + int len = iter.nextU4ToInt(); + StackMapTable t = new StackMapTable(index,len); + + //后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 + String code = iter.nextUxToHexString(len); + t.setOriginalCode(code); + + return t; + } + + private void setOriginalCode(String code) { + this.originalCode = code; + + } +} 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 index 1b5a8b95a6..a43b350531 100644 --- a/group05/1094051862/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java @@ -2,7 +2,9 @@ import com.coderising.jvm.constant.ClassInfo; import com.coderising.jvm.constant.ConstantPool; - +import com.coderising.jvm.field.Field; +import com.coding.basic.ArrayList; +import com.coding.basic.List; public class ClassFile { private int minorVersion; @@ -12,7 +14,20 @@ public class ClassFile { private ClassIndex clzIndex; private ConstantPool pool; + private List fields = new ArrayList(); + + public void addField(Field f) { + fields.add(f); + } + public List getFields() { + return fields; + } + + public void setFields(List fields) { + this.fields = fields; + } + public ClassIndex getClzIndex() { return clzIndex; } diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/field/Field.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/field/Field.java new file mode 100644 index 0000000000..6656090d22 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/field/Field.java @@ -0,0 +1,45 @@ +package com.coderising.jvm.field; + +import javax.management.RuntimeErrorException; + +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.UTF8Info; +import com.coderising.jvm.loader.ByteCodeIterator; + + +public class Field { + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + + + private ConstantPool pool; + + public Field( int accessFlag, int nameIndex, int descriptorIndex,ConstantPool pool) { + + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + this.pool = pool; + } + + + + + public static Field parse(ConstantPool pool,ByteCodeIterator iter){ + int accessFlag = iter.nextU2toInt(); + int nameIndex = iter.nextU2toInt(); + int descriptorIndex = iter.nextU2toInt(); + int attributesCount = iter.nextU2toInt(); + + Field f = new Field(accessFlag, nameIndex, descriptorIndex, pool); + + if (attributesCount > 0) { + throw new RuntimeException("Field attributes have not been parsed !"); + } + + return f; + } + +} 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 index 9c7c2fa591..69593e37f4 100644 --- a/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java @@ -32,8 +32,25 @@ 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 nextUxToHexString(int len) { + byte[] tmp = new byte[len]; + + for (int i = 0; i < len; i++) { + tmp[i] = codes[pos++]; + } + return Util.byteToHexString(tmp).toLowerCase(); + + } + + public void back(int n) { + this.pos -= n; + } } 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 index 0c58bff290..b7ea187e94 100644 --- a/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java @@ -13,6 +13,7 @@ import com.coderising.jvm.constant.NullConstantInfo; import com.coderising.jvm.constant.StringInfo; import com.coderising.jvm.constant.UTF8Info; +import com.coderising.jvm.field.Field; public class ClassFileParser { @@ -30,11 +31,31 @@ public ClassFile parse(byte[] codes) { ConstantPool pool = parseConstantPool(iter); clzFile.setConstPool(pool); + clzFile.setAccessFlag(parseAccessFlag(iter)); clzFile.setClassIndex(parseClassIndex(iter)); + + parseInterfaces(iter);//如果实现接口,需要进一步解析 + + parseFields(clzFile, iter); + + parrsMethods(clzFile, iter); return clzFile; } + private void parrsMethods(ClassFile clzFile, ByteCodeIterator iter) { + + } + + private void parseFields(ClassFile clzFile, ByteCodeIterator iter) { + int fieldCount = iter.nextU2toInt(); + System.out.println("fieldCount:" + fieldCount); + for (int i = 0; i < fieldCount; i++) { + Field f = Field.parse(clzFile.getConstantPool(), iter); + clzFile.addField(f); + } + } + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { //int flagValue = iter.nextU2toInt(); return new AccessFlag(iter.nextU2toInt()); @@ -113,5 +134,13 @@ private ConstantPool parseConstantPool(ByteCodeIterator iter) { return pool; } + private void parseInterfaces(ByteCodeIterator iter) { + int interfaceCount = iter.nextU2toInt(); + + System.out.println("interfaceCount:" + interfaceCount); + + // TODO : 如果实现了interface, 这里需要解析 + } + } diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/method/Method.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/method/Method.java new file mode 100644 index 0000000000..8ad9b7d7fa --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/method/Method.java @@ -0,0 +1,67 @@ +package com.coderising.jvm.method; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.attr.AttributeInfo; +import com.coderising.jvm.attr.CodeAttr; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.UTF8Info; +import com.coderising.jvm.loader.ByteCodeIterator; + + + +public class Method { + + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private CodeAttr codeAttr; + + private ClassFile clzFile; + + + public ClassFile getClzFile() { + return clzFile; + } + + public int getNameIndex() { + return nameIndex; + } + public int getDescriptorIndex() { + return descriptorIndex; + } + + public CodeAttr getCodeAttr() { + return codeAttr; + } + + public void setCodeAttr(CodeAttr code) { + this.codeAttr = code; + } + + public Method(ClassFile clzFile,int accessFlag, int nameIndex, int descriptorIndex) { + this.clzFile = clzFile; + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + } + + + public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ + int accessFlag = iter.nextU2toInt(); + int nameIndex = iter.nextU2toInt(); + int descriptorIndex = iter.nextU2toInt(); + int attributesCount = iter.nextU2toInt(); + + Method m = new Method(clzFile, accessFlag, nameIndex, descriptorIndex); + + for (int i = 0; i < attributesCount; i++) { + int attrNameIndex = iter.nextU2toInt(); + String attrName = clzFile.getConstantPool().getUTF8String(attrNameIndex); + + + } + 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 a595370848..2210a51934 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 @@ -200,4 +200,75 @@ public void testClassIndex(){ Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); } + /** + * 下面是第三次JVM课应实现的测试用例 + */ + /* @Test + public void testReadFields(){ + + List<Field> fields = clzFile.getFields(); + Assert.assertEquals(2, fields.size()); + { + Field f = fields.get(0); + Assert.assertEquals("name:Ljava/lang/String;", f.toString()); + } + { + Field f = fields.get(1); + Assert.assertEquals("age:I", f.toString()); + } + } + @Test + public void testMethods(){ + + List<Method> methods = clzFile.getMethods(); + ConstantPool pool = clzFile.getConstantPool(); + + { + Method m = methods.get(0); + assertMethodEquals(pool,m, + "<init>", + "(Ljava/lang/String;I)V", + "2ab7000c2a2bb5000f2a1cb50011b1"); + + } + { + Method m = methods.get(1); + assertMethodEquals(pool,m, + "setName", + "(Ljava/lang/String;)V", + "2a2bb5000fb1"); + + } + { + Method m = methods.get(2); + assertMethodEquals(pool,m, + "setAge", + "(I)V", + "2a1bb50011b1"); + } + { + Method m = methods.get(3); + assertMethodEquals(pool,m, + "sayHello", + "()V", + "b2001c1222b60024b1"); + + } + { + Method m = methods.get(4); + assertMethodEquals(pool,m, + "main", + "([Ljava/lang/String;)V", + "bb000159122b101db7002d4c2bb6002fb1"); + } + } + + private void assertMethodEquals(ConstantPool pool,Method m , String expectedName, String expectedDesc,String expectedCode){ + String methodName = pool.getUTF8String(m.getNameIndex()); + String methodDesc = pool.getUTF8String(m.getDescriptorIndex()); + String code = m.getCodeAttr().getCode(); + Assert.assertEquals(expectedName, methodName); + Assert.assertEquals(expectedDesc, methodDesc); + Assert.assertEquals(expectedCode, code); + }*/ } diff --git a/group05/1094051862/mini-jvm/src/com/coding/basic/ArrayList.java b/group05/1094051862/mini-jvm/src/com/coding/basic/ArrayList.java new file mode 100644 index 0000000000..2e837dd195 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coding/basic/ArrayList.java @@ -0,0 +1,79 @@ +package com.coding.basic; + +import java.util.Arrays; + +public class ArrayList implements List { + + private int size = 0; + + private Object[] elementData = new Object[10]; + + private int increaseSize = 10; + private void increaseArray() { + Object[] newData = Arrays.copyOf(elementData, elementData.length + increaseSize); + elementData = newData; + } + public void add(Object o){ + if (size == elementData.length) { + increaseArray(); + elementData[size++] = o; + } else { + elementData[size++] = o; + } + } + public void add(int index, Object o){ + if (index < 0 || index > size) { + System.out.println("错误提示:index > size || index < 0"); + return; + } + Object temp; + for (int i = index; i < size; i++) { + temp = elementData[i]; + elementData[i] = o; + o = temp; + } + elementData[size ++] = o; + } + + public Object get(int index){ + if (index < 0 || index > size ){ + return null; + } + return elementData[index]; + } + + public Object remove(int index){ + if (index < 0 || index > size ){ + return null; + } + Object result = elementData[index]; + for (int i = index; i < size-1; i++) { + elementData[i] = elementData[i + 1]; + } + elementData[size-1] = null; + size --; + return result; + } + + public int size(){ + return size; + } + + public Iterator iterator(){ + return new Iterator() { + private int cusor = 0; + @Override + public Object next() { + if (!hasNext()) { + System.out.println("next: !hasNext"); + return null; + } + return elementData[cusor ++]; + } + @Override + public boolean hasNext() { + return cusor < size; + } + }; + } +} diff --git a/group05/1094051862/mini-jvm/src/com/coding/basic/ArrayListTest.java b/group05/1094051862/mini-jvm/src/com/coding/basic/ArrayListTest.java new file mode 100644 index 0000000000..c733e4e7a9 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coding/basic/ArrayListTest.java @@ -0,0 +1,31 @@ +package com.coding.basic; + +import org.junit.Assert; +import org.junit.Test; + +public class ArrayListTest { + + @Test + public void test() { + List list = new ArrayList(); + for(int i = 0; i < 10; i++) { + list.add(i); + } + Assert.assertEquals(10, list.size()); + list.add(11); + list.add(3,99); + Assert.assertEquals(99, list.get(3)); + Assert.assertEquals(12, list.size()); + Assert.assertEquals(99, list.remove(3)); + Assert.assertEquals(11, list.size()); + Iterator iterator = list.iterator(); + for (int i = 0; i< list.size(); i++) { + System.out.println(list.get(i)); + } + System.out.println("======"); + while (iterator.hasNext()) { + System.out.println(iterator.next()); + } + } + +} diff --git a/group05/1094051862/mini-jvm/src/com/coding/basic/BinaryTreeNode.java b/group05/1094051862/mini-jvm/src/com/coding/basic/BinaryTreeNode.java new file mode 100644 index 0000000000..266eff3d56 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coding/basic/BinaryTreeNode.java @@ -0,0 +1,32 @@ +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; + } + + public BinaryTreeNode insert(Object o){ + return null; + } + +} diff --git a/group05/1094051862/mini-jvm/src/com/coding/basic/Iterator.java b/group05/1094051862/mini-jvm/src/com/coding/basic/Iterator.java new file mode 100644 index 0000000000..dbe8b9afb2 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coding/basic/Iterator.java @@ -0,0 +1,7 @@ +package com.coding.basic; + +public interface Iterator { + public boolean hasNext(); + public Object next(); + +} diff --git a/group05/1094051862/mini-jvm/src/com/coding/basic/LinkedList.java b/group05/1094051862/mini-jvm/src/com/coding/basic/LinkedList.java new file mode 100644 index 0000000000..e05587dd02 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coding/basic/LinkedList.java @@ -0,0 +1,334 @@ +package com.coding.basic; + +import java.util.Arrays; + +public class LinkedList implements List { + + private Node head; + private Node last; + private int size = 0; + + public void add(Object o) { + if (head == null) { + head = new Node(o, null); + size++; + return; + } + Node n = new Node(o, null); + if (last == null) { + last = n; + head.next = last; + } + last.next = n; + last = n; + size++; + } + + public void add(int index, Object o) { + if (index < 0 || index > size) { + System.out.println("linkedList.add: index < 0 || index > size"); + return; + } + if (index == size) { + add(o); + return; + } + if (index == 0) { + addFirst(o); + return; + } + Node pre = head; + for (int i = 1; i < index; i++) { + pre = pre.next; + } + Node post = pre.next; + Node n = new Node(o, post); + pre.next = n; + size++; + } + + public Object get(int index) { + return this.getNode(index).data; + } + + public Node getNode(int index) { + if (index == 0) { + return this.head; + } + Node n = head; + for (int i = 1; i <= index; i++) { + n = n.next; + } + return n; + } + + public Object remove(int index) { + if (index < 0 || index >= size) { + System.out.println("remove :index < 0 || index >= size"); + return null; + } + if (index == 0) { + return removeFirst(); + } + if (index == size - 1) { + return removeLast(); + } + Node pre = head; + for (int i = 1; i < index; i++) { + pre = pre.next; + } + Node n = pre.next; + Node post = n.next; + n.next = null; + pre.next = post; + size--; + return n.data; + } + + public int size() { + return size; + } + + public void addFirst(Object o) { + Node n = new Node(o, head); + head = n; + size++; + return; + } + + public void addLast(Object o) { + Node n = new Node(o, null); + last.next = n; + last = n; + size++; + return; + } + + public Object removeFirst() { + Object o = head.data; + Node n = head.next; + head.next = null; + head = n; + size--; + return o; + } + + public Object removeLast() { + Node preLast = head; + for (int i = 1; i < size; i++) { + preLast = preLast.next; + } + preLast.next = null; + Object o = last.data; + last = preLast; + size--; + return o; + } + + public Iterator iterator() { + return new Iterator() { + int cusor = 0; + Node current = head; + + @Override + public Object next() { + if (!hasNext()) { + System.out.println("next : !hasNext"); + return null; + } + Object o = current.data; + current = current.next; + cusor++; + return o; + } + + @Override + public boolean hasNext() { + return cusor < size; + } + }; + } + + private static class Node { + + Object data; + Node next; + + public Node(Object data, Node next) { + this.data = data; + this.next = next; + } + } + + /** + * 把该链表逆置 例如链表为 3->7->10 , 逆置后变为 10->7->3 + */ + public void reverse() { + if (this.size() < 2) { + return; + } + for (int i = this.size() - 1; i > 0; i--) { + this.getNode(i).next = this.getNode(i - 1); + } + Node temp = this.last; + this.last = this.head; + this.head = temp; + } + + /** + * 删除一个单链表的前半部分 例如:list = 2->5->7->8 , 删除以后的值为 7->8 如果list = 2->5->7->8->10 + * ,删除以后的值为7,8,10 + */ + public void removeFirstHalf() { + + int delSize = this.size() >> 1; + + Node temp = this.getNode(delSize);// getNode(index) + // 方法依赖前面元素的next指针,所以此语句在for循环前面 + + for (int i = delSize - 1; i >= 0; i--) { + this.getNode(i).next = null; + this.size--; + } + + this.head = temp;// 由于getNode(index) 方法如果index传入0 + // ,返回head,所以此语句要方法for循环后面 + } + + /** + * 从第i个元素开始, 删除length 个元素 , 注意i从0开始 + * + * @param i + * @param length + */ + public void remove(int i, int length) { + if (i < 0 || length < 0 || this.size() < i + length) { + return; + } + if (i == 0 && this.size() == length) { + this.head = null; + this.size = 0; + this.last = null; + return; + } + Node iNode = this.getNode(i - 1); + Node pre = this.getNode(i + length - 1); + Node post = this.getNode(i + length); + pre.next = null; + iNode.next = post; + this.size = this.size() - 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) { + Iterator select = list.iterator(); + Iterator original = this.iterator(); + int[] result = new int[this.size()]; + int cosur = 0; + while (select.hasNext()) { + int s = (int) select.next(); + String selStr = String.valueOf(s); + while (original.hasNext()) { + int o = (int) original.next(); + String oriStr = String.valueOf(o); + if (oriStr.contains(selStr)) { + result[0] = o; + cosur++; + break; + } + } + } + return Arrays.copyOf(result, cosur - 1); + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 从当前链表中中删除在list中出现的元素 + * + * @param list + */ + + public void subtract(LinkedList list) { + Iterator select = list.iterator(); + Iterator original = this.iterator(); + int[] result = new int[this.size()]; + int cosur = 0; + while (select.hasNext()) { + int sel = (int) select.next(); + + while (original.hasNext()) { + int ori = (int) original.next(); + cosur++; + if (ori == sel) { + remove(cosur); + } + } + } + } + + /** + * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) + */ + public void removeDuplicateValues() { + if (this.size() == 0) { + return; + } + for (int i = this.size(); i > 0; i--) { + if ((int) get(i) == (int) get(i - 1)) { + this.remove(i); + } + } + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 试写一高效的算法,删除表中所有值大于min且小于max的元素(若表中存在这样的元素) + * + * @param min + * @param max + */ + public void removeRange(int min, int max) { + int minIndex = 0; + int maxIndex = 0; + for (int i = this.size(); i > 0; i--) { + if (max > (int) get(i)) { + maxIndex = i; + } + } + for (int i = 0; i < maxIndex; i++) { + if (min < (int) get(i)) { + minIndex = i; + } + } + remove(minIndex, maxIndex - minIndex); + } + + /** + * 假设当前链表和参数list指定的链表均以元素依值递增有序排列(同一表中的元素值各不相同) + * 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列 + * + * @param list + */ + public LinkedList intersection(LinkedList list) { + LinkedList result = new LinkedList(); + Iterator select = list.iterator(); + Iterator original = this.iterator(); + + int sel = (int) select.next(); + int ori = (int) original.next(); + while (original.hasNext() && select.hasNext()) { + if (ori == sel) { + result.add(ori); + } else if (ori < sel) { + ori = (int) original.next(); + } else { + sel = (int) select.next(); + } + } + return result; + } +} diff --git a/group05/1094051862/mini-jvm/src/com/coding/basic/LinkedListTest.java b/group05/1094051862/mini-jvm/src/com/coding/basic/LinkedListTest.java new file mode 100644 index 0000000000..db55063435 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coding/basic/LinkedListTest.java @@ -0,0 +1,79 @@ +package com.coding.basic; + +import junit.framework.Assert; + +import org.junit.Test; + +public class LinkedListTest extends LinkedList { + + @Test + public void test() { + List list = new LinkedList(); + list.add(0); + list.add(1); + list.add(2); + list.add(3); + list.add(4); + list.add(5); + list.add(3, 33); + list.add(0, 100); + list.add(8,800); + Assert.assertEquals(9, list.size()); + Assert.assertEquals(100, list.get(0)); + Assert.assertEquals(0, list.get(1)); + Assert.assertEquals(1, list.get(2)); + Assert.assertEquals(2, list.get(3)); + Assert.assertEquals(33, list.get(4)); + Assert.assertEquals(3, list.get(5)); + Assert.assertEquals(4, list.get(6)); + Assert.assertEquals(800, list.get(8)); + Iterator iterator = list.iterator(); + while (iterator.hasNext()) { + System.out.println(iterator.next()); + } + } + @Test + public void testReverse() { + LinkedList list = new LinkedList(); + list.add(1); + list.add(2); + list.add(3); + list.add(4); + list.add(5); + list.add(6); + list.add(7); + Iterator iterator = list.iterator(); + while (iterator.hasNext()) { + System.out.print(iterator.next()); + } + System.out.println(); + list.reverse(); + Iterator iterator2 = list.iterator(); + while (iterator2.hasNext()) { + System.out.print(iterator2.next()); + } + System.out.println(); + list.removeFirstHalf(); + Iterator iterator3 = list.iterator(); + while (iterator3.hasNext()) { + System.out.print(iterator3.next()); + } + System.out.println(); + + } + @Test + public void testRemove() { + LinkedList list = new LinkedList(); + int i = 0; + while( i < 20) { + list.add(i); + i ++; + } + list.remove(3, 10); + Iterator iterator = list.iterator(); + while (iterator.hasNext()) { + System.out.print(iterator.next()); + } + } + +} diff --git a/group05/1094051862/mini-jvm/src/com/coding/basic/List.java b/group05/1094051862/mini-jvm/src/com/coding/basic/List.java new file mode 100644 index 0000000000..0a09990083 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coding/basic/List.java @@ -0,0 +1,10 @@ +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(); + public Iterator iterator(); +} diff --git a/group05/1094051862/mini-jvm/src/com/coding/basic/Queue.java b/group05/1094051862/mini-jvm/src/com/coding/basic/Queue.java new file mode 100644 index 0000000000..e16a80b13c --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coding/basic/Queue.java @@ -0,0 +1,25 @@ +package com.coding.basic; + +public class Queue { + private List list = new ArrayList(); + private int size = 0; + public void enQueue(Object o){ + list.add(o); + size ++; + } + + public Object deQueue(){ + if (size == 0) + return null; + size --; + return list.remove(0); + } + + public boolean isEmpty(){ + return size == 0; + } + + public int size(){ + return size; + } +} diff --git a/group05/1094051862/mini-jvm/src/com/coding/basic/QueueTest.java b/group05/1094051862/mini-jvm/src/com/coding/basic/QueueTest.java new file mode 100644 index 0000000000..1feee8dde1 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coding/basic/QueueTest.java @@ -0,0 +1,24 @@ +package com.coding.basic; + +import static org.junit.Assert.*; +import junit.framework.Assert; + +import org.junit.Test; + +public class QueueTest { + + @Test + public void test() { + Queue queue = new Queue(); + for (int i = 0; i < 100; i++) { + queue.enQueue(i); + } + Assert.assertEquals(100, queue.size()); + for (int i = 0; i < 100; i++) { + Assert.assertEquals(i, queue.deQueue()); + } + Assert.assertEquals(0, queue.size()); + + } + +} diff --git a/group05/1094051862/mini-jvm/src/com/coding/basic/Stack.java b/group05/1094051862/mini-jvm/src/com/coding/basic/Stack.java new file mode 100644 index 0000000000..57eae3d31d --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coding/basic/Stack.java @@ -0,0 +1,28 @@ +package com.coding.basic; + +public class Stack { + private List elementData = new ArrayList(); + private int size = 0; + public void push(Object o){ + elementData.add(o); + size ++; + } + + public Object pop(){ + if (size == 0) + return null; + return elementData.remove(--size); + } + + public Object peek(){ + if (size == 0) + return null; + return elementData.get(size - 1); + } + public boolean isEmpty(){ + return size == 0; + } + public int size(){ + return size; + } +} diff --git a/group05/1094051862/mini-jvm/src/com/coding/basic/StackTest.java b/group05/1094051862/mini-jvm/src/com/coding/basic/StackTest.java new file mode 100644 index 0000000000..e3eabe44a1 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coding/basic/StackTest.java @@ -0,0 +1,26 @@ +package com.coding.basic; + +import static org.junit.Assert.*; +import junit.framework.Assert; + +import org.junit.BeforeClass; +import org.junit.Test; + +public class StackTest { + + @Test + public void test() { + Stack stack = new Stack(); + for (int i = 0; i < 100; i++) { + stack.push(i); + } + Assert.assertEquals(100, stack.size()); + Assert.assertEquals(99, stack.pop()); + for (int i = 98; i >= 0; i--) { + Assert.assertEquals(i, stack.peek()); + Assert.assertEquals(i, stack.pop()); + } + Assert.assertEquals(0, stack.size()); + } + +} From b0bfd1e14bc680d3d90b3c040c9c303f600e951f Mon Sep 17 00:00:00 2001 From: zheng <765324639@qq.com> Date: Fri, 14 Apr 2017 11:33:04 +0800 Subject: [PATCH 252/287] =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E6=A0=88=E8=BF=9B=E8=A1=8C=E4=B8=AD=E5=BA=8F=E8=A1=A8=E8=BE=BE?= =?UTF-8?q?=E5=BC=8F=E6=B1=82=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../datastructure/stack/expr/InfixExpr.java | 75 +++++++++++++++++++ .../java/datastructure/stack/expr/Token.java | 51 +++++++++++++ .../datastructure/stack/expr/TokenParser.java | 66 ++++++++++++++++ .../stack/expr/InfixExprTest.java | 48 ++++++++++++ .../stack/expr/TokenParserTest.java | 29 +++++++ 5 files changed, 269 insertions(+) create mode 100644 group01/765324639/src/main/java/datastructure/stack/expr/InfixExpr.java create mode 100644 group01/765324639/src/main/java/datastructure/stack/expr/Token.java create mode 100644 group01/765324639/src/main/java/datastructure/stack/expr/TokenParser.java create mode 100644 group01/765324639/src/test/java/datastructure/stack/expr/InfixExprTest.java create mode 100644 group01/765324639/src/test/java/datastructure/stack/expr/TokenParserTest.java diff --git a/group01/765324639/src/main/java/datastructure/stack/expr/InfixExpr.java b/group01/765324639/src/main/java/datastructure/stack/expr/InfixExpr.java new file mode 100644 index 0000000000..febd242e75 --- /dev/null +++ b/group01/765324639/src/main/java/datastructure/stack/expr/InfixExpr.java @@ -0,0 +1,75 @@ +package datastructure.stack.expr; + +import java.util.List; +import java.util.Stack; + +public class InfixExpr { + String expr = null; + + public InfixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + TokenParser tokenParser = new TokenParser(expr); + List<Token> tokenList = tokenParser.parse(); + + Stack<Token> operaStack = new Stack<>(); + Stack<Float> floatStack = new Stack<>(); + + for (int i = 0; i < tokenList.size(); i++) { + if (Token.OPERATOR.equals(tokenList.get(i).getType())) { + if (operaStack.isEmpty()) { + operaStack.push(tokenList.get(i)); + } else { + Token topToken = operaStack.peek(); + if (tokenList.get(i).comparePriority(topToken) > 0) { + operaStack.push(tokenList.get(i)); + } else { + float result = stackTopCalculate(operaStack, floatStack); + floatStack.push(result); + + i--; + } + } + } else { + floatStack.push(Float.valueOf(tokenList.get(i).getValue())); + } + } + while (!operaStack.empty()) { + float temp = stackTopCalculate(operaStack, floatStack); + floatStack.push(temp); + } + return floatStack.pop(); + } + + private float stackTopCalculate(Stack<Token> operaStack, Stack<Float> floatStack) { + String operator = operaStack.pop().getValue(); + float num2 = floatStack.pop(); + float num1 = floatStack.pop(); + float result = calculate(operator, num1, num2); + return result; + } + + private float calculate(String operator, float num1, float num2) { + float result = 0; + switch (operator.charAt(0)) { + case '+': + result = num1 + num2; + break; + case '-': + result = num1 - num2; + break; + case '*': + result = num1 * num2; + break; + case '/': + result = num1 / num2; + break; + default: + throw new IllegalArgumentException(); + } + return result; + } + +} diff --git a/group01/765324639/src/main/java/datastructure/stack/expr/Token.java b/group01/765324639/src/main/java/datastructure/stack/expr/Token.java new file mode 100644 index 0000000000..44a019197d --- /dev/null +++ b/group01/765324639/src/main/java/datastructure/stack/expr/Token.java @@ -0,0 +1,51 @@ +package datastructure.stack.expr; + +public class Token { + + public static final String NUMBER = "number"; + + public static final String OPERATOR = "operator"; + + private String type; + + private String value; + + public Token(String type, String value) { + this.type = type; + this.value = value; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public int comparePriority(Token token) { + String higherLevel = "*/"; + String lowerLevel = "+-"; + if (higherLevel.contains(token.getValue())) { + if (higherLevel.contains(this.value)) { + return 0; + } + return -1; + } else if (lowerLevel.contains(token.getValue())){ + if (lowerLevel.contains(this.value)) { + return 0; + } + return 1; + } else { + throw new RuntimeException("不支持的运算符"); + } + } +} diff --git a/group01/765324639/src/main/java/datastructure/stack/expr/TokenParser.java b/group01/765324639/src/main/java/datastructure/stack/expr/TokenParser.java new file mode 100644 index 0000000000..e1add57663 --- /dev/null +++ b/group01/765324639/src/main/java/datastructure/stack/expr/TokenParser.java @@ -0,0 +1,66 @@ +package datastructure.stack.expr; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class TokenParser { + + private String expr; + + private List<Token> tokenList = new ArrayList<>(); + + public TokenParser(String expr) { + this.expr = expr; + } + + public List<Token> parse() { + if (expr == null || "".equals(expr)) { + return Collections.emptyList(); + } + + char[] charArray = expr.toCharArray(); + for (int i = 0; i < charArray.length; i++) { + if (isNumber(charArray[i])) { + i = addFullNumber(charArray, i); + i--; + } else if (isOperator(charArray[i])) { + addOperator(charArray[i]); + } + } + return tokenList; + } + + private boolean isNumber(char c) { + String numbers = "0123456789"; + if (numbers.indexOf(c) != -1) { + return true; + } + return false; + } + + private boolean isOperator(char c) { + String supplyOperator = "+-*/"; + if (supplyOperator.indexOf(supplyOperator) != -1) { + return true; + } + return false; + } + + private int addFullNumber(char[] charArray, int i) { + StringBuilder builder = new StringBuilder(); + for (; i < charArray.length; i++) { + if (isNumber(charArray[i])) { + builder.append(charArray[i]); + } else { + break; + } + } + tokenList.add(new Token(Token.NUMBER, builder.toString())); + return i; + } + + private void addOperator(char c) { + tokenList.add(new Token(Token.OPERATOR, String.valueOf(c))); + } +} diff --git a/group01/765324639/src/test/java/datastructure/stack/expr/InfixExprTest.java b/group01/765324639/src/test/java/datastructure/stack/expr/InfixExprTest.java new file mode 100644 index 0000000000..9746dcdb79 --- /dev/null +++ b/group01/765324639/src/test/java/datastructure/stack/expr/InfixExprTest.java @@ -0,0 +1,48 @@ +package datastructure.stack.expr; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class InfixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + //InfixExpr expr = new InfixExpr("300*20+12*5-20/4"); + { + InfixExpr expr = new InfixExpr("2+3*4+5"); + Assert.assertEquals(19.0, expr.evaluate(), 0.001f); + } + { + InfixExpr expr = new InfixExpr("3*20+12*5-40/2"); + Assert.assertEquals(100.0, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("3*20/2"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("20/2*3"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("10-30+50"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + } + +} diff --git a/group01/765324639/src/test/java/datastructure/stack/expr/TokenParserTest.java b/group01/765324639/src/test/java/datastructure/stack/expr/TokenParserTest.java new file mode 100644 index 0000000000..073d4e4b24 --- /dev/null +++ b/group01/765324639/src/test/java/datastructure/stack/expr/TokenParserTest.java @@ -0,0 +1,29 @@ +package datastructure.stack.expr; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; + +public class TokenParserTest { + + @Test + public void test() { + + { + TokenParser tokenParser = new TokenParser("2+3*4+5"); + List<Token> tokenList = tokenParser.parse(); + Assert.assertEquals("2", tokenList.get(0).getValue()); + Assert.assertEquals("*", tokenList.get(3).getValue()); + Assert.assertEquals("5", tokenList.get(6).getValue()); + } + { + TokenParser tokenParser = new TokenParser("3*20+12*5-40/2"); + List<Token> tokenList = tokenParser.parse(); + Assert.assertEquals("20", tokenList.get(2).getValue()); + Assert.assertEquals("12", tokenList.get(4).getValue()); + Assert.assertEquals("5", tokenList.get(6).getValue()); + } + + } +} From fcc7c89d74d334ef4f3c7aed1812d5a85d20be7d Mon Sep 17 00:00:00 2001 From: onlyliuxin <14703250@qq.com> Date: Fri, 14 Apr 2017 13:59:39 +0800 Subject: [PATCH 253/287] refactor --- .../data-structure/src/com/coding/basic/stack/StackUtil.java | 5 ++++- .../src/com/coding/basic/stack/StackUtilTest.java | 2 -- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/liuxin/data-structure/src/com/coding/basic/stack/StackUtil.java b/liuxin/data-structure/src/com/coding/basic/stack/StackUtil.java index 7fb450d0a0..5f4236e875 100644 --- a/liuxin/data-structure/src/com/coding/basic/stack/StackUtil.java +++ b/liuxin/data-structure/src/com/coding/basic/stack/StackUtil.java @@ -16,6 +16,7 @@ public static void bad_reverse(Stack<Integer> s) { } + public static void reverse_247565311(Stack<Integer> s){ if(s == null || s.isEmpty()) { return; @@ -114,7 +115,9 @@ public static Object[] getTop(Stack s,int len) { break; } } - + while(!tmpStack.isEmpty()){ + s.push(tmpStack.pop()); + } return result; } /** diff --git a/liuxin/data-structure/src/com/coding/basic/stack/StackUtilTest.java b/liuxin/data-structure/src/com/coding/basic/stack/StackUtilTest.java index d0df46a052..d70302d7a1 100644 --- a/liuxin/data-structure/src/com/coding/basic/stack/StackUtilTest.java +++ b/liuxin/data-structure/src/com/coding/basic/stack/StackUtilTest.java @@ -1,7 +1,5 @@ package com.coding.basic.stack; -import static org.junit.Assert.fail; - import java.util.Stack; import org.junit.After; From 2461d51d539449ad8a52b5644d167da3928f5d61 Mon Sep 17 00:00:00 2001 From: onlyliuxin <14703250@qq.com> Date: Fri, 14 Apr 2017 14:23:56 +0800 Subject: [PATCH 254/287] refactor --- .../src/com/coderising/jvm/attr/CodeAttr.java | 68 ++++++++++++++++++- .../coderising/jvm/attr/LineNumberTable.java | 28 +++++++- .../jvm/attr/LocalVariableTable.java | 38 +++++++++-- .../src/com/coderising/jvm/field/Field.java | 21 +++++- .../jvm/loader/ClassFileParser.java | 30 ++++++-- .../src/com/coderising/jvm/method/Method.java | 41 ++++++++++- 6 files changed, 211 insertions(+), 15 deletions(-) diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java b/liuxin/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java index b0c67b4b93..e00a6a6d49 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java @@ -39,10 +39,74 @@ public void setLocalVariableTable(LocalVariableTable t) { this.localVarTable = t; } - public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ +public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ + int attrNameIndex = iter.nextU2ToInt(); + int attrLen = iter.nextU4ToInt(); + int maxStack = iter.nextU2ToInt(); + int maxLocals = iter.nextU2ToInt(); + int codeLen = iter.nextU4ToInt(); - return null; + String code = iter.nextUxToHexString(codeLen); + + System.out.println(code); + + //ByteCodeCommand[] cmds = ByteCodeCommand.parse(clzFile,code); + + CodeAttr codeAttr = new CodeAttr(attrNameIndex,attrLen, maxStack,maxLocals,codeLen,code); + + int exceptionTableLen = iter.nextU2ToInt(); + //TODO 处理exception + if(exceptionTableLen>0){ + String exTable = iter.nextUxToHexString(exceptionTableLen); + System.out.println("Encountered exception table , just ignore it :" + exTable); + + } + + + int subAttrCount = iter.nextU2ToInt(); + + for(int x=1; x<=subAttrCount; x++){ + int subAttrIndex = iter.nextU2ToInt(); + String subAttrName = clzFile.getConstantPool().getUTF8String(subAttrIndex); + + //已经向前移动了U2, 现在退回去。 + iter.back(2); + //line item table + if(AttributeInfo.LINE_NUM_TABLE.equalsIgnoreCase(subAttrName)){ + + LineNumberTable t = LineNumberTable.parse(iter); + codeAttr.setLineNumberTable(t); + } + else if(AttributeInfo.LOCAL_VAR_TABLE.equalsIgnoreCase(subAttrName)){ + LocalVariableTable t = LocalVariableTable.parse(iter); + codeAttr.setLocalVariableTable(t); + } + else if (AttributeInfo.STACK_MAP_TABLE.equalsIgnoreCase(subAttrName)){ + StackMapTable t = StackMapTable.parse(iter); + codeAttr.setStackMapTable(t); + } + else{ + throw new RuntimeException("Need code to process " + subAttrName); + } + + + } + + return codeAttr; + } + + + public String toString(ConstantPool pool){ + StringBuilder buffer = new StringBuilder(); + buffer.append("Code:").append(code).append("\n"); + /*for(int i=0;i<cmds.length;i++){ + buffer.append(cmds[i].toString(pool)).append("\n"); + }*/ + buffer.append("\n"); + buffer.append(this.lineNumTable.toString()); + buffer.append(this.localVarTable.toString(pool)); + return buffer.toString(); } private void setStackMapTable(StackMapTable t) { this.stackMapTable = t; diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java b/liuxin/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java index 22941f83b1..7ee5d1bc5e 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.List; + import com.coderising.jvm.loader.ByteCodeIterator; public class LineNumberTable extends AttributeInfo { @@ -34,7 +35,32 @@ public LineNumberTable(int attrNameIndex, int attrLen) { public static LineNumberTable parse(ByteCodeIterator iter){ - return null; + int index = iter.nextU2ToInt(); + int len = iter.nextU4ToInt(); + + LineNumberTable table = new LineNumberTable(index,len); + + int itemLen = iter.nextU2ToInt(); + + for(int i=1; i<=itemLen; i++){ + LineNumberItem item = new LineNumberItem(); + item.setStartPC(iter.nextU2ToInt()); + item.setLineNum(iter.nextU2ToInt()); + table.addLineNumberItem(item); + } + return table; + } + + public String toString(){ + StringBuilder buffer = new StringBuilder(); + buffer.append("Line Number Table:\n"); + for(LineNumberItem item : items){ + buffer.append("startPC:"+item.getStartPC()).append(","); + buffer.append("lineNum:"+item.getLineNum()).append("\n"); + } + buffer.append("\n"); + return buffer.toString(); + } diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java b/liuxin/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java index fa69dc9bdb..2e332f170d 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java @@ -16,13 +16,43 @@ public LocalVariableTable(int attrNameIndex, int attrLen) { super(attrNameIndex, attrLen); } - public static LocalVariableTable parse(ByteCodeIterator iter){ - - return null; - } + private void addLocalVariableItem(LocalVariableItem item) { this.items.add(item); } + public static LocalVariableTable parse(ByteCodeIterator iter){ + + int index = iter.nextU2ToInt(); + int len = iter.nextU4ToInt(); + + LocalVariableTable table = new LocalVariableTable(index,len); + + int itemLen = iter.nextU2ToInt(); + + for(int i=1; i<=itemLen; i++){ + LocalVariableItem item = new LocalVariableItem(); + item.setStartPC(iter.nextU2ToInt()); + item.setLength(iter.nextU2ToInt()); + item.setNameIndex(iter.nextU2ToInt()); + item.setDescIndex(iter.nextU2ToInt()); + item.setIndex(iter.nextU2ToInt()); + table.addLocalVariableItem(item); + } + return table; + } + + public String toString(ConstantPool pool){ + StringBuilder buffer = new StringBuilder(); + buffer.append("Local Variable Table:\n"); + for(LocalVariableItem item : items){ + buffer.append("startPC:"+item.getStartPC()).append(","); + buffer.append("name:"+pool.getUTF8String(item.getNameIndex())).append(","); + buffer.append("desc:"+pool.getUTF8String(item.getDescIndex())).append(","); + buffer.append("slotIndex:"+ item.getIndex()).append("\n"); + } + buffer.append("\n"); + return buffer.toString(); + } } diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/field/Field.java b/liuxin/mini-jvm/src/com/coderising/jvm/field/Field.java index 09bae5a1ae..0267f3145e 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/field/Field.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/field/Field.java @@ -22,12 +22,29 @@ public Field( int accessFlag, int nameIndex, int descriptorIndex,ConstantPool po this.pool = pool; } - + public String toString() { + String name = ((UTF8Info)pool.getConstantInfo(this.nameIndex)).getValue(); + + String desc = ((UTF8Info)pool.getConstantInfo(this.descriptorIndex)).getValue(); + return name +":"+ desc; + } public static Field parse(ConstantPool pool,ByteCodeIterator iter){ - return null; + int accessFlag = iter.nextU2ToInt(); + int nameIndex = iter.nextU2ToInt(); + int descIndex = iter.nextU2ToInt(); + int attribCount = iter.nextU2ToInt(); + //System.out.println("field attribute count:"+ attribCount); + + Field f = new Field(accessFlag, nameIndex, descIndex,pool); + + if(attribCount > 0){ + throw new RuntimeException("Field Attribute has not been implemented"); + } + + return f; } } diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java b/liuxin/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java index 444ec4c60d..4b258706c8 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java @@ -45,6 +45,9 @@ public ClassFile parse(byte[] codes) { parseInterfaces(iter); + parseFileds(clzFile, iter); + + parseMethods(clzFile, iter); return clzFile; } @@ -52,9 +55,7 @@ public ClassFile parse(byte[] codes) { private AccessFlag parseAccessFlag(ByteCodeIterator iter) { AccessFlag flag = new AccessFlag(iter.nextU2ToInt()); - // System.out.println("Is public class: " + flag.isPublicClass()); - // System.out.println("Is final class : " + flag.isFinalClass()); - + return flag; } @@ -76,7 +77,7 @@ private ConstantPool parseConstantPool(ByteCodeIterator iter) { int constPoolCount = iter.nextU2ToInt(); - System.out.println("Constant Pool Count :" + constPoolCount); + //System.out.println("Constant Pool Count :" + constPoolCount); ConstantPool pool = new ConstantPool(); @@ -146,6 +147,25 @@ private void parseInterfaces(ByteCodeIterator iter) { // TODO : 如果实现了interface, 这里需要解析 } - + private void parseFileds(ClassFile clzFile, ByteCodeIterator iter) { + int fieldCount = iter.nextU2ToInt(); + + for (int i = 1; i <= fieldCount; i++) { + Field f = Field.parse(clzFile.getConstantPool(), iter); + clzFile.addField(f); + } + + } + + private void parseMethods(ClassFile clzFile, ByteCodeIterator iter) { + + int methodCount = iter.nextU2ToInt(); + + for (int i = 1; i <= methodCount; i++) { + Method m = Method.parse(clzFile, iter); + clzFile.addMethod(m); + } + + } } diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/method/Method.java b/liuxin/mini-jvm/src/com/coderising/jvm/method/Method.java index ba5f7848d1..6821b2137d 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/method/Method.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/method/Method.java @@ -50,8 +50,47 @@ public Method(ClassFile clzFile,int accessFlag, int nameIndex, int descriptorInd +public String toString() { + + ConstantPool pool = this.clzFile.getConstantPool(); + StringBuilder buffer = new StringBuilder(); + + String name = ((UTF8Info)pool.getConstantInfo(this.nameIndex)).getValue(); + + String desc = ((UTF8Info)pool.getConstantInfo(this.descriptorIndex)).getValue(); + + buffer.append(name).append(":").append(desc).append("\n"); + + buffer.append(this.codeAttr.toString(pool)); + + return buffer.toString(); + } + public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ - return null; + int accessFlag = iter.nextU2ToInt(); + int nameIndex = iter.nextU2ToInt(); + int descIndex = iter.nextU2ToInt(); + int attribCount = iter.nextU2ToInt(); + + + Method m = new Method(clzFile, accessFlag, nameIndex, descIndex); + + for( int j=1; j<= attribCount; j++){ + + int attrNameIndex = iter.nextU2ToInt(); + String attrName = clzFile.getConstantPool().getUTF8String(attrNameIndex); + iter.back(2); + + if(AttributeInfo.CODE.equalsIgnoreCase(attrName)){ + CodeAttr codeAttr = CodeAttr.parse(clzFile, iter); + m.setCodeAttr(codeAttr); + } else{ + throw new RuntimeException("only CODE attribute is implemented , please implement the "+ attrName); + } + + } + + return m ; } } From 6b80b433a5fbb5624f93bcc6706a294cada72ecb Mon Sep 17 00:00:00 2001 From: gabywong <qinwa.wong@gmail.com> Date: Fri, 14 Apr 2017 20:16:41 +0800 Subject: [PATCH 255/287] 3.16 --- group15/1513_121469918/HomeWork/.gitignore | 1 - .../coding/basic/stuck/expr/InfixExpr.java | 64 ++++++++++ .../basic/stuck/expr/InfixExprTest.java | 48 +++++++ .../coding/basic/stuck/expr/Token.java | 36 ++++++ .../coding/basic/stuck/expr/TokenParser.java | 55 ++++++++ .../coderising/jvm/attr/AttributeInfo.java | 19 +++ .../src/coderising/jvm/attr/CodeAttr.java | 120 ++++++++++++++++++ .../coderising/jvm/attr/LineNumberTable.java | 68 ++++++++++ .../jvm/attr/LocalVariableItem.java | 39 ++++++ .../jvm/attr/LocalVariableTable.java | 58 +++++++++ .../coderising/jvm/attr/StackMapTable.java | 30 +++++ .../src/coderising/jvm/clz/ClassFile.java | 21 ++- .../src/coderising/jvm/field/Field.java | 50 ++++++++ .../jvm/loader/ByteCodeIterator.java | 30 ++++- .../jvm/loader/ClassFileParser.java | 60 ++++++++- .../src/coderising/jvm/method/Method.java | 96 ++++++++++++++ .../jvm/test/ClassFileloaderTest.java | 79 +++++++++++- 17 files changed, 857 insertions(+), 17 deletions(-) create mode 100644 group15/1513_121469918/HomeWork/src/task0416/coding/basic/stuck/expr/InfixExpr.java create mode 100644 group15/1513_121469918/HomeWork/src/task0416/coding/basic/stuck/expr/InfixExprTest.java create mode 100644 group15/1513_121469918/HomeWork/src/task0416/coding/basic/stuck/expr/Token.java create mode 100644 group15/1513_121469918/HomeWork/src/task0416/coding/basic/stuck/expr/TokenParser.java create mode 100644 group15/1513_121469918/mini-jvm/src/coderising/jvm/attr/AttributeInfo.java create mode 100644 group15/1513_121469918/mini-jvm/src/coderising/jvm/attr/CodeAttr.java create mode 100644 group15/1513_121469918/mini-jvm/src/coderising/jvm/attr/LineNumberTable.java create mode 100644 group15/1513_121469918/mini-jvm/src/coderising/jvm/attr/LocalVariableItem.java create mode 100644 group15/1513_121469918/mini-jvm/src/coderising/jvm/attr/LocalVariableTable.java create mode 100644 group15/1513_121469918/mini-jvm/src/coderising/jvm/attr/StackMapTable.java create mode 100644 group15/1513_121469918/mini-jvm/src/coderising/jvm/field/Field.java create mode 100644 group15/1513_121469918/mini-jvm/src/coderising/jvm/method/Method.java diff --git a/group15/1513_121469918/HomeWork/.gitignore b/group15/1513_121469918/HomeWork/.gitignore index c92e089b1e..e6416c5be6 100644 --- a/group15/1513_121469918/HomeWork/.gitignore +++ b/group15/1513_121469918/HomeWork/.gitignore @@ -1,3 +1,2 @@ /bin/ /lib/ -/.settings/ \ No newline at end of file diff --git a/group15/1513_121469918/HomeWork/src/task0416/coding/basic/stuck/expr/InfixExpr.java b/group15/1513_121469918/HomeWork/src/task0416/coding/basic/stuck/expr/InfixExpr.java new file mode 100644 index 0000000000..ab9c56317d --- /dev/null +++ b/group15/1513_121469918/HomeWork/src/task0416/coding/basic/stuck/expr/InfixExpr.java @@ -0,0 +1,64 @@ +package task0416.coding.basic.stuck.expr; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +public class InfixExpr { + String expr = null; + + public InfixExpr(String expr) { + this.expr = expr; + } + /* + + */ + public float evaluate() { + Stack<Token> oStack = new Stack<>(); + Stack<Float> nStack = new Stack<>(); + + TokenParser tp = new TokenParser(expr); + List<Token> array = tp.getParserList(); + + for (int i = 0; i < array.size(); i++) { + Token t = array.get(i); + String type = t.getType(); + + if(type.equals(Token.NUMBER)){ + nStack.push(Float.valueOf(t.getValue())); + }else if(type.equals(Token.OPERATOR)){ + if(oStack.isEmpty()||t.getLevel()>oStack.peek().getLevel()){ + oStack.push(t); + }else{ + nStack.push(operation(nStack,oStack)); + oStack.push(t); + } + } + } + while(!oStack.isEmpty()){ + nStack.push(operation(nStack,oStack)); + } + return nStack.peek(); + } + private Float operation(Stack<Float> nStack, Stack<Token> oStack) { + Float num1 = nStack.pop(); + Float num2 = nStack.pop(); + String operator = oStack.pop().getValue(); + + switch(operator){ + case "+": + return num2+num1; + case "-": + return num2-num1; + case "*": + return num2*num1; + case "/": + return num2/num1; + } + return null; + } + + + + +} diff --git a/group15/1513_121469918/HomeWork/src/task0416/coding/basic/stuck/expr/InfixExprTest.java b/group15/1513_121469918/HomeWork/src/task0416/coding/basic/stuck/expr/InfixExprTest.java new file mode 100644 index 0000000000..ca93f9edad --- /dev/null +++ b/group15/1513_121469918/HomeWork/src/task0416/coding/basic/stuck/expr/InfixExprTest.java @@ -0,0 +1,48 @@ +package task0416.coding.basic.stuck.expr; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class InfixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + //InfixExpr expr = new InfixExpr("300*20+12*5-20/4"); + { + InfixExpr expr = new InfixExpr("2+3*4+5"); + Assert.assertEquals(19.0, expr.evaluate(), 0.001f); + } + { + InfixExpr expr = new InfixExpr("3*20+12*5-40/2"); + Assert.assertEquals(100.0, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("3*20/2"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("20/2*3"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("10-30+50"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + } + +} diff --git a/group15/1513_121469918/HomeWork/src/task0416/coding/basic/stuck/expr/Token.java b/group15/1513_121469918/HomeWork/src/task0416/coding/basic/stuck/expr/Token.java new file mode 100644 index 0000000000..50ae8f27aa --- /dev/null +++ b/group15/1513_121469918/HomeWork/src/task0416/coding/basic/stuck/expr/Token.java @@ -0,0 +1,36 @@ +package task0416.coding.basic.stuck.expr; + +public class Token { + static final String OPERATOR = "operator"; + static final String NUMBER = "number"; + static final int LEVEL_ADD_SUB = 1; + static final int LEVEL_MUL_DIV = 2; + + private String value; + private int level; + private String type; + + public Token(String type,String value){ + this.type = type; + this.value = value; + } + + public String getValue() { + return value; + } + public void setValue(String value) { + this.value = value; + } + public int getLevel() { + return level; + } + public void setLevel(int level) { + this.level = level; + } + public String getType() { + return type; + } + public void setType(String type) { + this.type = type; + } +} diff --git a/group15/1513_121469918/HomeWork/src/task0416/coding/basic/stuck/expr/TokenParser.java b/group15/1513_121469918/HomeWork/src/task0416/coding/basic/stuck/expr/TokenParser.java new file mode 100644 index 0000000000..3ea319af4d --- /dev/null +++ b/group15/1513_121469918/HomeWork/src/task0416/coding/basic/stuck/expr/TokenParser.java @@ -0,0 +1,55 @@ +package task0416.coding.basic.stuck.expr; + +import java.util.ArrayList; +import java.util.List; + +import javax.print.attribute.standard.MediaSize.ISO; + +public class TokenParser { + private String expr; + + TokenParser(String expr){ + this.expr = expr; + } + + public List<Token> getParserList(){ + List<Token> array = new ArrayList<>(); + char[] chs = expr.toCharArray(); + int i = 0; + while(i<chs.length){ + char c = chs[i]; + if(isOperator(c)){ + Token t = new Token(Token.OPERATOR,String.valueOf(c)); + if("+".equals(String.valueOf(c))||"-".equals(String.valueOf(c))){ + t.setLevel(Token.LEVEL_ADD_SUB); + }else{ + t.setLevel(Token.LEVEL_MUL_DIV); + } + array.add(t); + i++; + }else if(Character.isDigit(c)){ + int nextOperatorIndex = nextOperatorIndex(i,expr); + String value = expr.substring(i, nextOperatorIndex); + Token t = new Token(Token.NUMBER,value); + array.add(t); + i = nextOperatorIndex; + } + } + return array; + } + private int nextOperatorIndex(int i, String expr2) { + char[] chs = expr2.toCharArray(); + for (int j = i; j < chs.length; j++) { + if(isOperator(chs[j])){ + return j; + } + } + return chs.length; + } + + boolean isOperator(char ch){ + String s = String.valueOf(ch); + boolean result = "+".equals(s)||"-".equals(s)||"*".equals(s)||"/".equals(s); + return result; + } +} diff --git a/group15/1513_121469918/mini-jvm/src/coderising/jvm/attr/AttributeInfo.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/attr/AttributeInfo.java new file mode 100644 index 0000000000..774ed3d1a9 --- /dev/null +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/attr/AttributeInfo.java @@ -0,0 +1,19 @@ +package coderising.jvm.attr; + +public abstract class AttributeInfo { + public static final String CODE = "Code"; + public static final String CONST_VALUE = "ConstantValue"; + public static final String EXCEPTIONS = "Exceptions"; + public static final String LINE_NUM_TABLE = "LineNumberTable"; + public static final String LOCAL_VAR_TABLE = "LocalVariableTable"; + public static final String STACK_MAP_TABLE = "StackMapTable"; + int attrNameIndex; + int attrLen ; + public AttributeInfo(int attrNameIndex, int attrLen) { + + this.attrNameIndex = attrNameIndex; + this.attrLen = attrLen; + } + + +} diff --git a/group15/1513_121469918/mini-jvm/src/coderising/jvm/attr/CodeAttr.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/attr/CodeAttr.java new file mode 100644 index 0000000000..cc28cd2707 --- /dev/null +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/attr/CodeAttr.java @@ -0,0 +1,120 @@ +package coderising.jvm.attr; + +import coderising.jvm.clz.ClassFile; +import coderising.jvm.constant.ConstantPool; +import coderising.jvm.loader.ByteCodeIterator; + + +public class CodeAttr extends AttributeInfo { + private int maxStack ; + private int maxLocals ; + private int codeLen ; + private String code; + public String getCode() { + return code; + } + + //private ByteCodeCommand[] cmds ; + //public ByteCodeCommand[] getCmds() { + // return cmds; + //} + private LineNumberTable lineNumTable; + private LocalVariableTable localVarTable; + private StackMapTable stackMapTable; + + public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen,String code /*ByteCodeCommand[] cmds*/) { + super(attrNameIndex, attrLen); + this.maxStack = maxStack; + this.maxLocals = maxLocals; + this.codeLen = codeLen; + this.code = code; + //this.cmds = cmds; + } + + public void setLineNumberTable(LineNumberTable t) { + this.lineNumTable = t; + } + + public void setLocalVariableTable(LocalVariableTable t) { + this.localVarTable = t; + } + +public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ + + int attrNameIndex = iter.nextU2ToInt(); + int attrLen = iter.nextU4ToInt(); + int maxStack = iter.nextU2ToInt(); + int maxLocals = iter.nextU2ToInt(); + int codeLen = iter.nextU4ToInt(); + + String code = iter.nextUxToHexString(codeLen); + + System.out.println(code); + + //ByteCodeCommand[] cmds = ByteCodeCommand.parse(clzFile,code); + + CodeAttr codeAttr = new CodeAttr(attrNameIndex,attrLen, maxStack,maxLocals,codeLen,code); + + int exceptionTableLen = iter.nextU2ToInt(); + //TODO 处理exception + if(exceptionTableLen>0){ + String exTable = iter.nextUxToHexString(exceptionTableLen); + System.out.println("Encountered exception table , just ignore it :" + exTable); + + } + + + int subAttrCount = iter.nextU2ToInt(); + + for(int x=1; x<=subAttrCount; x++){ + int subAttrIndex = iter.nextU2ToInt(); + String subAttrName = clzFile.getConstantPool().getUTF8String(subAttrIndex); + + //已经向前移动了U2, 现在退回去。 + iter.back(2); + //line item table + if(AttributeInfo.LINE_NUM_TABLE.equalsIgnoreCase(subAttrName)){ + + LineNumberTable t = LineNumberTable.parse(iter); + codeAttr.setLineNumberTable(t); + } + else if(AttributeInfo.LOCAL_VAR_TABLE.equalsIgnoreCase(subAttrName)){ + LocalVariableTable t = LocalVariableTable.parse(iter); + codeAttr.setLocalVariableTable(t); + } + else if (AttributeInfo.STACK_MAP_TABLE.equalsIgnoreCase(subAttrName)){ + StackMapTable t = StackMapTable.parse(iter); + codeAttr.setStackMapTable(t); + } + else{ + throw new RuntimeException("Need code to process " + subAttrName); + } + + + } + + return codeAttr; + } + + + public String toString(ConstantPool pool){ + StringBuilder buffer = new StringBuilder(); + buffer.append("Code:").append(code).append("\n"); + /*for(int i=0;i<cmds.length;i++){ + buffer.append(cmds[i].toString(pool)).append("\n"); + }*/ + buffer.append("\n"); + buffer.append(this.lineNumTable.toString()); + buffer.append(this.localVarTable.toString(pool)); + return buffer.toString(); + } + private void setStackMapTable(StackMapTable t) { + this.stackMapTable = t; + + } + + + + + +} diff --git a/group15/1513_121469918/mini-jvm/src/coderising/jvm/attr/LineNumberTable.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/attr/LineNumberTable.java new file mode 100644 index 0000000000..6bb2997138 --- /dev/null +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/attr/LineNumberTable.java @@ -0,0 +1,68 @@ +package coderising.jvm.attr; + +import java.util.ArrayList; +import java.util.List; + + +import coderising.jvm.loader.ByteCodeIterator; + +public class LineNumberTable extends AttributeInfo { + List<LineNumberItem> items = new ArrayList<LineNumberItem>(); + + private static class LineNumberItem{ + int startPC; + int lineNum; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLineNum() { + return lineNum; + } + public void setLineNum(int lineNum) { + this.lineNum = lineNum; + } + } + public void addLineNumberItem(LineNumberItem item){ + this.items.add(item); + } + public LineNumberTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + + } + + public static LineNumberTable parse(ByteCodeIterator iter){ + + int index = iter.nextU2ToInt(); + int len = iter.nextU4ToInt(); + + LineNumberTable table = new LineNumberTable(index,len); + + int itemLen = iter.nextU2ToInt(); + + for(int i=1; i<=itemLen; i++){ + LineNumberItem item = new LineNumberItem(); + item.setStartPC(iter.nextU2ToInt()); + item.setLineNum(iter.nextU2ToInt()); + table.addLineNumberItem(item); + } + return table; + } + + public String toString(){ + StringBuilder buffer = new StringBuilder(); + buffer.append("Line Number Table:\n"); + for(LineNumberItem item : items){ + buffer.append("startPC:"+item.getStartPC()).append(","); + buffer.append("lineNum:"+item.getLineNum()).append("\n"); + } + buffer.append("\n"); + return buffer.toString(); + + } + + + +} diff --git a/group15/1513_121469918/mini-jvm/src/coderising/jvm/attr/LocalVariableItem.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/attr/LocalVariableItem.java new file mode 100644 index 0000000000..afb7093863 --- /dev/null +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/attr/LocalVariableItem.java @@ -0,0 +1,39 @@ +package coderising.jvm.attr; + +public class LocalVariableItem { + private int startPC; + private int length; + private int nameIndex; + private int descIndex; + private int index; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getNameIndex() { + return nameIndex; + } + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + public int getDescIndex() { + return descIndex; + } + public void setDescIndex(int descIndex) { + this.descIndex = descIndex; + } + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } +} diff --git a/group15/1513_121469918/mini-jvm/src/coderising/jvm/attr/LocalVariableTable.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/attr/LocalVariableTable.java new file mode 100644 index 0000000000..d8cb119b23 --- /dev/null +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/attr/LocalVariableTable.java @@ -0,0 +1,58 @@ +package coderising.jvm.attr; + + +import java.util.ArrayList; +import java.util.List; + +import coderising.jvm.constant.ConstantPool; + +import coderising.jvm.loader.ByteCodeIterator; + +public class LocalVariableTable extends AttributeInfo{ + + List<LocalVariableItem> items = new ArrayList<LocalVariableItem>(); + + public LocalVariableTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + + private void addLocalVariableItem(LocalVariableItem item) { + this.items.add(item); + } + + public static LocalVariableTable parse(ByteCodeIterator iter){ + + int index = iter.nextU2ToInt(); + int len = iter.nextU4ToInt(); + + LocalVariableTable table = new LocalVariableTable(index,len); + + int itemLen = iter.nextU2ToInt(); + + for(int i=1; i<=itemLen; i++){ + LocalVariableItem item = new LocalVariableItem(); + item.setStartPC(iter.nextU2ToInt()); + item.setLength(iter.nextU2ToInt()); + item.setNameIndex(iter.nextU2ToInt()); + item.setDescIndex(iter.nextU2ToInt()); + item.setIndex(iter.nextU2ToInt()); + table.addLocalVariableItem(item); + } + return table; + } + + + public String toString(ConstantPool pool){ + StringBuilder buffer = new StringBuilder(); + buffer.append("Local Variable Table:\n"); + for(LocalVariableItem item : items){ + buffer.append("startPC:"+item.getStartPC()).append(","); + buffer.append("name:"+pool.getUTF8String(item.getNameIndex())).append(","); + buffer.append("desc:"+pool.getUTF8String(item.getDescIndex())).append(","); + buffer.append("slotIndex:"+ item.getIndex()).append("\n"); + } + buffer.append("\n"); + return buffer.toString(); + } +} diff --git a/group15/1513_121469918/mini-jvm/src/coderising/jvm/attr/StackMapTable.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/attr/StackMapTable.java new file mode 100644 index 0000000000..741820e732 --- /dev/null +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/attr/StackMapTable.java @@ -0,0 +1,30 @@ +package coderising.jvm.attr; + + +import coderising.jvm.loader.ByteCodeIterator; + +public class StackMapTable extends AttributeInfo{ + + private String originalCode; + + public StackMapTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static StackMapTable parse(ByteCodeIterator iter){ + int index = iter.nextU2ToInt(); + int len = iter.nextU4ToInt(); + StackMapTable t = new StackMapTable(index,len); + + //后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 + String code = iter.nextUxToHexString(len); + t.setOriginalCode(code); + + return t; + } + + private void setOriginalCode(String code) { + this.originalCode = code; + + } +} diff --git a/group15/1513_121469918/mini-jvm/src/coderising/jvm/clz/ClassFile.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/clz/ClassFile.java index 33b8d3a519..b56fc54162 100644 --- a/group15/1513_121469918/mini-jvm/src/coderising/jvm/clz/ClassFile.java +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/clz/ClassFile.java @@ -1,7 +1,12 @@ package coderising.jvm.clz; +import java.util.ArrayList; +import java.util.List; + import coderising.jvm.constant.ClassInfo; import coderising.jvm.constant.ConstantPool; +import coderising.jvm.field.Field; +import coderising.jvm.method.Method; public class ClassFile { @@ -11,7 +16,8 @@ public class ClassFile { private AccessFlag accessFlag; private ClassIndex clzIndex; private ConstantPool pool; - + private List<Field> fields = new ArrayList<Field>(); + private List<Method> methods = new ArrayList<Method>(); public ClassIndex getClzIndex() { return clzIndex; @@ -48,7 +54,18 @@ public void setClassIndex(ClassIndex clzIndex) { this.clzIndex = clzIndex; } - + public void addField(Field f){ + this.fields.add(f); + } + public List<Field> getFields(){ + return this.fields; + } + public void addMethod(Method m){ + this.methods.add(m); + } + public List<Method> getMethods() { + return methods; + } public void print(){ diff --git a/group15/1513_121469918/mini-jvm/src/coderising/jvm/field/Field.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/field/Field.java new file mode 100644 index 0000000000..69f08d350d --- /dev/null +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/field/Field.java @@ -0,0 +1,50 @@ +package coderising.jvm.field; + +import coderising.jvm.constant.ConstantPool; +import coderising.jvm.constant.UTF8Info; +import coderising.jvm.loader.ByteCodeIterator; + + +public class Field { + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + + + private ConstantPool pool; + + public Field( int accessFlag, int nameIndex, int descriptorIndex,ConstantPool pool) { + + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + this.pool = pool; + } + + public String toString() { + String name = ((UTF8Info)pool.getConstantInfo(this.nameIndex)).getValue(); + + String desc = ((UTF8Info)pool.getConstantInfo(this.descriptorIndex)).getValue(); + return name +":"+ desc; + } + + + public static Field parse(ConstantPool pool,ByteCodeIterator iter){ + + int accessFlag = iter.nextU2ToInt(); + int nameIndex = iter.nextU2ToInt(); + int descIndex = iter.nextU2ToInt(); + int attribCount = iter.nextU2ToInt(); + //System.out.println("field attribute count:"+ attribCount); + + Field f = new Field(accessFlag, nameIndex, descIndex,pool); + + if(attribCount > 0){ + throw new RuntimeException("Field Attribute has not been implemented"); + } + + return f; + } + +} 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 index cf01b4d9e1..bee04eb8ed 100644 --- a/group15/1513_121469918/mini-jvm/src/coderising/jvm/loader/ByteCodeIterator.java +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/loader/ByteCodeIterator.java @@ -1,5 +1,7 @@ package coderising.jvm.loader; +import java.util.Arrays; + import coderising.jvm.util.Util; public class ByteCodeIterator { @@ -8,6 +10,15 @@ public class ByteCodeIterator { public ByteCodeIterator(byte[] codes){ this.codes = codes; } + 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; + } public String nextU4ToHexString() { byte[] bys = new byte[]{codes[pos++],codes[pos++],codes[pos++],codes[pos++]}; return Util.byteToHexString(bys); @@ -21,12 +32,19 @@ 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++]; + public String nextUxToHexString(int len) { + byte[] tmp = new byte[len]; + + for (int i = 0; i < len; i++) { + tmp[i] = codes[pos++]; } - String result = new String(bys); - return result; + return Util.byteToHexString(tmp).toLowerCase(); + + } + public void back(int n) { + this.pos -= n; + } + public int nextU4ToInt() { + return Util.byteToInt(new byte[] { codes[pos++], codes[pos++], codes[pos++], codes[pos++] }); } } diff --git a/group15/1513_121469918/mini-jvm/src/coderising/jvm/loader/ClassFileParser.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/loader/ClassFileParser.java index 1d7e712226..fe8deff0a8 100644 --- a/group15/1513_121469918/mini-jvm/src/coderising/jvm/loader/ClassFileParser.java +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/loader/ClassFileParser.java @@ -1,5 +1,7 @@ package coderising.jvm.loader; +import java.io.UnsupportedEncodingException; + import coderising.jvm.clz.AccessFlag; import coderising.jvm.clz.ClassFile; import coderising.jvm.clz.ClassIndex; @@ -11,6 +13,8 @@ import coderising.jvm.constant.NullConstantInfo; import coderising.jvm.constant.StringInfo; import coderising.jvm.constant.UTF8Info; +import coderising.jvm.field.Field; +import coderising.jvm.method.Method; public class ClassFileParser { @@ -35,6 +39,12 @@ public ClassFile parse(byte[] codes) { ClassIndex clzindex = parseClassInfex(iter); clzFile.setClassIndex(clzindex); + parseInterfaces(iter); + + parseFileds(clzFile, iter); + + parseMethods(clzFile, iter); + return clzFile; } @@ -56,14 +66,22 @@ private ConstantPool parseConstantPool(ByteCodeIterator iter) { for(int i =1;i<poolSize;i++){ int tag = iter.nextU1ToInt(); - System.out.println("tag:"+i+":"+tag); + switch (tag){ case 1: - UTF8Info utf8Info = new UTF8Info(pool); - utf8Info.setLength(iter.nextU2ToInt()); - String value = iter.nextString(utf8Info.getLength()); - utf8Info.setValue(value); - pool.addConstantInfo(utf8Info); + int len = iter.nextU2ToInt(); + byte[] data = iter.getBytes(len); + String value = null; + try { + value = new String(data, "UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + UTF8Info utf8Str = new UTF8Info(pool); + utf8Str.setLength(len); + utf8Str.setValue(value); + pool.addConstantInfo(utf8Str); break; case 4: break; @@ -96,10 +114,40 @@ private ConstantPool parseConstantPool(ByteCodeIterator iter) { nati.setIndex2(iter.nextU2ToInt()); pool.addConstantInfo(nati); break; + default: + throw new RuntimeException("noFoundConstantIndex:"+tag); } } + System.out.println("Finished reading Constant pool "); return pool; } + private void parseInterfaces(ByteCodeIterator iter) { + int interfaceCount = iter.nextU2ToInt(); + + System.out.println("interfaceCount:" + interfaceCount); + + // TODO : 如果实现了interface, 这里需要解析 + } + + private void parseFileds(ClassFile clzFile, ByteCodeIterator iter) { + int fieldCount = iter.nextU2ToInt(); + + for (int i = 1; i <= fieldCount; i++) { + Field f = Field.parse(clzFile.getConstantPool(), iter); + clzFile.addField(f); + } + + } + + private void parseMethods(ClassFile clzFile, ByteCodeIterator iter) { + int methodCount = iter.nextU2ToInt(); + + for (int i = 1; i <= methodCount; i++) { + Method m = Method.parse(clzFile, iter); + clzFile.addMethod(m); + } + + } } diff --git a/group15/1513_121469918/mini-jvm/src/coderising/jvm/method/Method.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/method/Method.java new file mode 100644 index 0000000000..636ab11d8c --- /dev/null +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/method/Method.java @@ -0,0 +1,96 @@ +package coderising.jvm.method; + +import coderising.jvm.clz.ClassFile; +import coderising.jvm.attr.AttributeInfo; +import coderising.jvm.attr.CodeAttr; +import coderising.jvm.constant.ConstantPool; +import coderising.jvm.constant.UTF8Info; +import coderising.jvm.loader.ByteCodeIterator; + + + +public class Method { + + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private CodeAttr codeAttr; + + private ClassFile clzFile; + + + public ClassFile getClzFile() { + return clzFile; + } + + public int getNameIndex() { + return nameIndex; + } + public int getDescriptorIndex() { + return descriptorIndex; + } + + public CodeAttr getCodeAttr() { + return codeAttr; + } + + public void setCodeAttr(CodeAttr code) { + this.codeAttr = code; + } + + public Method(ClassFile clzFile,int accessFlag, int nameIndex, int descriptorIndex) { + this.clzFile = clzFile; + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + } + + + + + +public String toString() { + + ConstantPool pool = this.clzFile.getConstantPool(); + StringBuilder buffer = new StringBuilder(); + + String name = ((UTF8Info)pool.getConstantInfo(this.nameIndex)).getValue(); + + String desc = ((UTF8Info)pool.getConstantInfo(this.descriptorIndex)).getValue(); + + buffer.append(name).append(":").append(desc).append("\n"); + + buffer.append(this.codeAttr.toString(pool)); + + return buffer.toString(); + } + + public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ + int accessFlag = iter.nextU2ToInt(); + int nameIndex = iter.nextU2ToInt(); + int descIndex = iter.nextU2ToInt(); + int attribCount = iter.nextU2ToInt(); + + + Method m = new Method(clzFile, accessFlag, nameIndex, descIndex); + + for( int j=1; j<= attribCount; j++){ + + int attrNameIndex = iter.nextU2ToInt(); + String attrName = clzFile.getConstantPool().getUTF8String(attrNameIndex); + iter.back(2); + + if(AttributeInfo.CODE.equalsIgnoreCase(attrName)){ + CodeAttr codeAttr = CodeAttr.parse(clzFile, iter); + m.setCodeAttr(codeAttr); + } else{ + throw new RuntimeException("only CODE attribute is implemented , please implement the "+ attrName); + } + + } + + return m ; + + } +} diff --git a/group15/1513_121469918/mini-jvm/src/coderising/jvm/test/ClassFileloaderTest.java b/group15/1513_121469918/mini-jvm/src/coderising/jvm/test/ClassFileloaderTest.java index ecf9df9cee..9bb523f872 100644 --- a/group15/1513_121469918/mini-jvm/src/coderising/jvm/test/ClassFileloaderTest.java +++ b/group15/1513_121469918/mini-jvm/src/coderising/jvm/test/ClassFileloaderTest.java @@ -1,6 +1,8 @@ package coderising.jvm.test; +import java.util.List; + import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -13,13 +15,15 @@ import coderising.jvm.constant.MethodRefInfo; import coderising.jvm.constant.NameAndTypeInfo; import coderising.jvm.constant.UTF8Info; +import coderising.jvm.field.Field; import coderising.jvm.loader.ClassFileLoader; +import coderising.jvm.method.Method; public class ClassFileloaderTest { private static final String FULL_QUALIFIED_CLASS_NAME = "coderising/jvm/test/EmployeeV1"; - static String path1 = "D:\\Downloads\\mini-jvm\\bin"; + static String path1 = "D:\\develop\\GitHub\\coding2017\\group15\\1513_121469918\\mini-jvm\\bin"; static String path2 = "C:\temp"; static ClassFile clzFile = null; @@ -29,7 +33,7 @@ public class ClassFileloaderTest { String className = "coderising.jvm.test.EmployeeV1"; clzFile = loader.loadClass(className); - //clzFile.print(); + clzFile.print(); } @@ -192,7 +196,78 @@ public void testClassIndex(){ Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); } + + /** + * 下面是第三次JVM课应实现的测试用例 + */ + @Test + public void testReadFields(){ + + List<Field> fields = clzFile.getFields(); + Assert.assertEquals(2, fields.size()); + { + Field f = fields.get(0); + Assert.assertEquals("name:Ljava/lang/String;", f.toString()); + } + { + Field f = fields.get(1); + Assert.assertEquals("age:I", f.toString()); + } + } + @Test + public void testMethods(){ + + List<Method> methods = clzFile.getMethods(); + ConstantPool pool = clzFile.getConstantPool(); + + { + Method m = methods.get(0); + assertMethodEquals(pool,m, + "<init>", + "(Ljava/lang/String;I)V", + "2ab7000c2a2bb5000f2a1cb50011b1"); + + } + { + Method m = methods.get(1); + assertMethodEquals(pool,m, + "setName", + "(Ljava/lang/String;)V", + "2a2bb5000fb1"); + + } + { + Method m = methods.get(2); + assertMethodEquals(pool,m, + "setAge", + "(I)V", + "2a1bb50011b1"); + } + { + Method m = methods.get(3); + assertMethodEquals(pool,m, + "sayHello", + "()V", + "b2001c1222b60024b1"); + + } + { + Method m = methods.get(4); + assertMethodEquals(pool,m, + "main", + "([Ljava/lang/String;)V", + "bb000159122b101db7002d4c2bb6002fb1"); + } + } + private void assertMethodEquals(ConstantPool pool,Method m , String expectedName, String expectedDesc,String expectedCode){ + String methodName = pool.getUTF8String(m.getNameIndex()); + String methodDesc = pool.getUTF8String(m.getDescriptorIndex()); + String code = m.getCodeAttr().getCode(); + Assert.assertEquals(expectedName, methodName); + Assert.assertEquals(expectedDesc, methodDesc); + Assert.assertEquals(expectedCode, code); + } } From 8fb3a9ce12514452d45b696ec401b398e7428533 Mon Sep 17 00:00:00 2001 From: RalfNick <wang_lxin@163.com> Date: Sat, 15 Apr 2017 11:33:13 +0800 Subject: [PATCH 256/287] Ralf homework-6 --- .../data-struct/com/ralf/stack/MyStack.java" | 42 +++ .../com/ralf/stack/StackUtil.java" | 173 ++++++++++++ .../com/ralf/stack/StackUtilsTest.java" | 87 ++++++ .../com/ralf/stack/expr/ExprIterator.java" | 57 ++++ .../com/ralf/stack/expr/InfixExpr.java" | 112 ++++++++ .../com/ralf/stack/expr/InfixExprTest.java" | 49 ++++ .../jvm/attribute/AttributeInfo.java" | 20 ++ .../coderising/jvm/attribute/CodeAttr.java" | 87 ++++++ .../jvm/attribute/LineNumberTable.java" | 62 ++++ .../jvm/attribute/LocalVariableItem.java" | 51 ++++ .../jvm/attribute/LocalVariableTable.java" | 45 +++ .../jvm/attribute/StackMapTable.java" | 36 +++ .../coderising/jvm/clasfile/AccessFlag.java" | 22 ++ .../coderising/jvm/clasfile/ClassFile.java" | 85 ++++++ .../coderising/jvm/clasfile/ClassIndex.java" | 21 ++ .../coderising/jvm/constant/ClassInfo.java" | 29 ++ .../jvm/constant/ConstantInfo.java" | 26 ++ .../jvm/constant/ConstantPool.java" | 25 ++ .../jvm/constant/FieldRefInfo.java" | 63 +++++ .../coderising/jvm/constant/MethodInfo.java" | 62 ++++ .../jvm/constant/NameAndTypeInfo.java" | 46 +++ .../jvm/constant/NullConstantInfo.java" | 11 + .../coderising/jvm/constant/StringInfo.java" | 32 +++ .../coderising/jvm/constant/Utf8Info.java" | 30 ++ .../com/coderising/jvm/field/JField.java" | 44 +++ .../jvm/loader/ByteCodeIterator.java" | 67 +++++ .../jvm/loader/ClassFileLoader.java" | 96 +++++++ .../jvm/loader/ClassFileParser.java" | 169 +++++++++++ .../com/coderising/jvm/method/JMethod.java" | 81 ++++++ .../jvm/test/ClassFileLoaderTest.java" | 266 ++++++++++++++++++ .../com/coderising/jvm/test/EmployeeV1.java" | 32 +++ .../com/coderising/jvm/utils/Util.java" | 22 ++ 32 files changed, 2050 insertions(+) create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/MyStack.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/StackUtil.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/StackUtilsTest.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/expr/ExprIterator.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/expr/InfixExpr.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/expr/InfixExprTest.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/attribute/AttributeInfo.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/attribute/CodeAttr.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/attribute/LineNumberTable.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/attribute/LocalVariableItem.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/attribute/LocalVariableTable.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/attribute/StackMapTable.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/clasfile/AccessFlag.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/clasfile/ClassFile.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/clasfile/ClassIndex.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/ClassInfo.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/ConstantInfo.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/ConstantPool.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/FieldRefInfo.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/MethodInfo.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/NameAndTypeInfo.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/NullConstantInfo.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/StringInfo.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/Utf8Info.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/field/JField.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/loader/ByteCodeIterator.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\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\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/loader/ClassFileParser.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/method/JMethod.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\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\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/test/EmployeeV1.java" create mode 100644 "group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/utils/Util.java" diff --git "a/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/MyStack.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/MyStack.java" new file mode 100644 index 0000000000..147ee9e15f --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/MyStack.java" @@ -0,0 +1,42 @@ +package com.ralf.stack; + +import java.util.LinkedList; +import java.util.NoSuchElementException; + +/** + * ʵֻݽṹջ + * + * @author Ralf + * + */ +public class MyStack<T> { + + private LinkedList<T> linkedList = new LinkedList<>(); + + public MyStack() { + + } + + 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\345\205\255\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/StackUtil.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/StackUtil.java" new file mode 100644 index 0000000000..758178131c --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/StackUtil.java" @@ -0,0 +1,173 @@ +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 <T> + */ + public static <T> void reverse(MyStack<T> 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]); + } + + } + + public static void bad_reverse(MyStack<Integer> s) { + if(s == null || s.isEmpty()){ + return; + } + MyStack<Integer> tmpStack = new MyStack<>(); + while(!s.isEmpty()){ + tmpStack.push(s.pop()); + } + + s = tmpStack; + + } + + + /** + * ɾջеijԪ ע⣺ֻʹStackĻpush,pop,peek,isEmpty ʹһջ + * + * @param o + */ + public static <T> void remove(MyStack<T> s, T o) { + if (s.isEmpty()) { + System.out.println("ջΪգ"); + return; + } + MyStack<T> 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 <T> void PopAndPush(MyStack<T> s, MyStack<T> 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> T[] getTop(MyStack<T> s, int len) { + + if (s.isEmpty() || len > s.size()) { + return null; + } + MyStack<T> 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еDzdzɶԳֵġ s = + * "([e{d}f])" , ַеdzɶԳ֣ ÷true s = "([b{x]y})", + * ַеŲdzɶԳֵģ ÷false; + * + * @param s + * @return + */ + public static <T> boolean isValidPairs(String s) { + + char[] ch = s.toCharArray(); + if (ch.length < 1) { + return false; + } + + MyStack<String> leftStack = new MyStack<>(); + MyStack<String> 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<String> leftStack, + MyStack<String> 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\345\205\255\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/StackUtilsTest.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/StackUtilsTest.java" new file mode 100644 index 0000000000..f547c5e0c1 --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\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<Integer> 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<Integer> 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<Integer> 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\345\205\255\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/expr/ExprIterator.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/expr/ExprIterator.java" new file mode 100644 index 0000000000..d82db3e915 --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/expr/ExprIterator.java" @@ -0,0 +1,57 @@ +package com.ralf.stack.expr; + +import java.util.ArrayList; + +public class ExprIterator { + + private int operPos; + private int numPos; + private ArrayList<String> operateList = new ArrayList<>(); + private ArrayList<String> numList = new ArrayList<>(); + + public ExprIterator(String exprString) { + char[] chs = exprString.toCharArray(); + transToString(chs); + } + + public Integer nextNumString() { + if (hasNextNum()) { + return Integer.parseInt(numList.get(numPos++)); + } + return null; + } + public String nextOperateString() { + if (hasNextOperate()) { + return operateList.get(operPos++); + } + return null; + } + + public boolean hasNextNum() { + return numPos < numList.size(); + } + + public boolean hasNextOperate() { + return operPos < operateList.size(); + } + + private void transToString(char[] chs) { + + StringBuilder stringBuilder = new StringBuilder(); + + for (int i = 0; i < chs.length; i++) { + if (chs[i] == '+' || chs[i] == '-' || chs[i] == '*' + || chs[i] == '/') { + numList.add(stringBuilder.toString()); + operateList.add(String.valueOf(chs[i])); + stringBuilder.delete(0, stringBuilder.length()); + } + else { + stringBuilder.append(chs[i]); + } + + } + numList.add(stringBuilder.toString()); + } + +} diff --git "a/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/expr/InfixExpr.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/expr/InfixExpr.java" new file mode 100644 index 0000000000..46422db77f --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/expr/InfixExpr.java" @@ -0,0 +1,112 @@ +package com.ralf.stack.expr; + +import com.ralf.stack.MyStack; + +public class InfixExpr { + + String expr = null; + private MyStack<String> operateStack = new MyStack<>(); + private MyStack<Integer> numStack = new MyStack<>(); + + public InfixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + + ExprIterator iterator = new ExprIterator(expr); + + while (iterator.hasNextOperate()) { + String operateString = iterator.nextOperateString(); + if (numStack.isEmpty()) { + + numStack.push(iterator.nextNumString()); + numStack.push(iterator.nextNumString()); + operateStack.push(operateString); + + } else if (operateStack.peek().equals("*") + || operateStack.peek().equals("/")) { + + getOperatorAndNum(); + operateStack.push(operateString); + numStack.push(iterator.nextNumString()); + + } else { + if (operateString.equals("+") + || operateString.equals("-")) { + + getOperatorAndNum(); + operateStack.push(operateString); + numStack.push(iterator.nextNumString()); + + } + else { + + numStack.push(iterator.nextNumString()); + operateStack.push(operateString); + + } + } + + } + + return getFinalResult(numStack,operateStack); + } + + private void getOperatorAndNum() { + + String oper = operateStack.pop(); + int secondNum = numStack.pop(); + int firstNum = numStack.pop(); + numStack.push(calculate(firstNum, secondNum, oper)); + } + + private int getFinalResult(MyStack<Integer> numStack, + MyStack<String> operateStack) { + + if (operateStack.isEmpty()) { + return numStack.pop(); + } + + getOperatorAndNum(); + return getFinalResult(numStack, operateStack); + + } + + private int calculate(int firstNum, int secondNum, String oper) { + + int result; + switch (oper) { + case "+": + result = firstNum + secondNum; + break; + + case "-": + result = firstNum - secondNum; + break; + case "*": + result = firstNum * secondNum; + break; + case "/": + result = firstNum / secondNum; + break; + + default: + result = 0; + break; + } + return result; + } + + public void getString() { + + ExprIterator iterator = new ExprIterator(expr); + while (iterator.hasNextNum()) { + System.out.print(iterator.nextNumString()); + } + while (iterator.hasNextOperate()) { + System.out.print(iterator.nextOperateString()); + } + } + +} diff --git "a/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/expr/InfixExprTest.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/expr/InfixExprTest.java" new file mode 100644 index 0000000000..50af62dcea --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/data-struct/com/ralf/stack/expr/InfixExprTest.java" @@ -0,0 +1,49 @@ +package com.ralf.stack.expr; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class InfixExprTest { + + @Before + public void setUp() throws Exception { + } + + @Test + public void testToString() { + InfixExpr expr = new InfixExpr("2+3*4+5"); + + expr.getString(); + } + + @Test + public void testEvaluate(){ + + { + InfixExpr expr = new InfixExpr("2+3*4+5"); + Assert.assertEquals(19.0, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("3*20+12*5-40/2"); + Assert.assertEquals(100.0, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("3*20/2"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("20/2*3"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("10-30+50"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + } + +} diff --git "a/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/attribute/AttributeInfo.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/attribute/AttributeInfo.java" new file mode 100644 index 0000000000..1df3a72c73 --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/attribute/AttributeInfo.java" @@ -0,0 +1,20 @@ +package com.coderising.jvm.attribute; + +public abstract class AttributeInfo { + + public static final String CODE = "Code"; + public static final String CONST_VALUE = "ConstantValue"; + public static final String EXCEPTIONS = "Exceptions"; + public static final String LINE_NUM_TABLE = "LineNumberTable"; + public static final String LOCAL_VAR_TABLE = "LocalVariableTable"; + public static final String STACK_MAP_TABLE = "StackMapTable"; + int attrNameIndex; + int attrLen ; + + public AttributeInfo(int attrNameIndex, int attrLen) { + + this.attrNameIndex = attrNameIndex; + this.attrLen = attrLen; + } + +} diff --git "a/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/attribute/CodeAttr.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/attribute/CodeAttr.java" new file mode 100644 index 0000000000..9a715c5d65 --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/attribute/CodeAttr.java" @@ -0,0 +1,87 @@ +package com.coderising.jvm.attribute; + +import com.coderising.jvm.clasfile.ClassFile; +import com.coderising.jvm.constant.Utf8Info; +import com.coderising.jvm.loader.ByteCodeIterator; + +public class CodeAttr extends AttributeInfo{ + + private int attrLen; + private int maxStack; + private int maxLocals; + private int codeLen; + private String code; + + private LineNumberTable lineNumTable; + private LocalVariableTable localVarTable; + private StackMapTable stackMapTable; + + public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen,String code) { + super(attrNameIndex, attrLen); + this.maxLocals = maxLocals; + this.maxStack = maxStack; + this.code = code; + this.codeLen = codeLen; + } + + public String getCodeString(){ + return this.code; + } + + public static CodeAttr parse(ClassFile classFile, ByteCodeIterator iterator) { + + iterator.back(2); + int attrNameIndex = iterator.next2BytesToInt(); + int attrLen = iterator.next4BytesToInt(); + int maxstack = iterator.next2BytesToInt(); + int maxlocals = iterator.next2BytesToInt(); + int codelen = iterator.next4BytesToInt(); + String code = iterator.nextXBytesToString(codelen); + + CodeAttr codeAttr = new CodeAttr(attrNameIndex, attrLen, maxstack, maxlocals, codelen, code); + + int exceptionCount = iterator.next2BytesToInt(); + if (exceptionCount > 0) { + throw new RuntimeException("Exception is null." + exceptionCount); + } + int childCount = iterator.next2BytesToInt(); + if (childCount > 0) { + for (int i = 0; i < childCount; i++) { + + int childIndex = iterator.next2BytesToInt(); + String attrName = classFile.getPool().getUtf8String(childIndex); + + if (AttributeInfo.LINE_NUM_TABLE.equals(attrName)) { + LineNumberTable lineNumber = LineNumberTable.parse(iterator); + codeAttr.setLineNumTable(lineNumber); + } + else if(AttributeInfo.LOCAL_VAR_TABLE.equals(attrName)){ + LocalVariableTable localVarTable = LocalVariableTable.parse(classFile,iterator); + codeAttr.setLocalVarTable(localVarTable); + } + else if(AttributeInfo.STACK_MAP_TABLE.equals(attrName)){ + StackMapTable stackMapTable = StackMapTable.parse(classFile,iterator); + codeAttr.setStackMapTable(stackMapTable); + } + else { + throw new RuntimeException("This " + attrName +"is not added."); + } + } + } + + return codeAttr; + } + + public void setLineNumTable(LineNumberTable lineNumTable) { + this.lineNumTable = lineNumTable; + } + + public void setLocalVarTable(LocalVariableTable localVarTable) { + this.localVarTable = localVarTable; + } + + public void setStackMapTable(StackMapTable stackMapTable) { + this.stackMapTable = stackMapTable; + } + +} diff --git "a/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/attribute/LineNumberTable.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/attribute/LineNumberTable.java" new file mode 100644 index 0000000000..810111fe33 --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/attribute/LineNumberTable.java" @@ -0,0 +1,62 @@ +package com.coderising.jvm.attribute; + +import java.util.ArrayList; +import java.util.List; + +import com.coderising.jvm.clasfile.ClassFile; +import com.coderising.jvm.loader.ByteCodeIterator; + +public class LineNumberTable extends AttributeInfo{ + + private List<LineNumberItem> lineNumberItems = new ArrayList<>(); + + private static class LineNumberItem{ + + private int startPc; + private int lineNum; + + public int getStartPc() { + return startPc; + } + public void setStartPc(int startPc) { + this.startPc = startPc; + } + public int getLineNum() { + return lineNum; + } + public void setLineNum(int lineNum) { + this.lineNum = lineNum; + } + + } + + public void addLineNumberItem(LineNumberItem lineNumberItem){ + this.lineNumberItems.add(lineNumberItem); + } + + public LineNumberTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + + } + + public static LineNumberTable parse(ByteCodeIterator iterator) { + iterator.back(2); + int attrIndex = iterator.next2BytesToInt(); + int attrlen = iterator.next4BytesToInt(); + LineNumberTable lineNumberTable = new LineNumberTable(attrIndex, attrlen); + int lineNumberCount = iterator.next2BytesToInt(); + + if (lineNumberCount > 0) { + + for (int i = 0; i < lineNumberCount; i++) { + LineNumberItem lItem = new LineNumberItem(); + lItem.setStartPc(iterator.next2BytesToInt()); + lItem.setLineNum(iterator.next2BytesToInt()); + lineNumberTable.addLineNumberItem(lItem); + } + } + + return lineNumberTable; + } + +} diff --git "a/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/attribute/LocalVariableItem.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/attribute/LocalVariableItem.java" new file mode 100644 index 0000000000..2d2b117e68 --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/attribute/LocalVariableItem.java" @@ -0,0 +1,51 @@ +package com.coderising.jvm.attribute; + +public class LocalVariableItem{ + + private int start; + private int lenth; + private int nameIndex; + private int describeIndex; + private int slotIndex; + + public int getStart() { + return start; + } + + public void setStart(int start) { + this.start = start; + } + + public int getLenth() { + return lenth; + } + + public void setLenth(int lenth) { + this.lenth = lenth; + } + + public int getNameIndex() { + return nameIndex; + } + + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + + public int getDescribeIndex() { + return describeIndex; + } + + public void setDescribeIndex(int describeIndex) { + this.describeIndex = describeIndex; + } + + public int getSlotIndex() { + return slotIndex; + } + + public void setSlotIndex(int slotIndex) { + this.slotIndex = slotIndex; + } + +} diff --git "a/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/attribute/LocalVariableTable.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/attribute/LocalVariableTable.java" new file mode 100644 index 0000000000..dbbe83dd07 --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/attribute/LocalVariableTable.java" @@ -0,0 +1,45 @@ +package com.coderising.jvm.attribute; + +import java.util.ArrayList; +import java.util.List; + +import com.coderising.jvm.clasfile.ClassFile; +import com.coderising.jvm.loader.ByteCodeIterator; + +public class LocalVariableTable extends AttributeInfo{ + + private List<LocalVariableItem> localVariableItems = new ArrayList<>(); + + public LocalVariableTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + + } + + public void addLocalVaribleItem(LocalVariableItem lItem){ + this.localVariableItems.add(lItem); + } + + public static LocalVariableTable parse(ClassFile classFile, + ByteCodeIterator iterator) { + iterator.back(2); + int attrIndex = iterator.next2BytesToInt(); + int attrlen = iterator.next4BytesToInt(); + int localVariCount = iterator.next2BytesToInt(); + LocalVariableTable lTable = new LocalVariableTable(attrIndex, attrlen); + + if(localVariCount > 0){ + for (int i = 0; i < localVariCount; i++) { + LocalVariableItem lItem = new LocalVariableItem(); + lItem.setStart(iterator.next2BytesToInt()); + lItem.setLenth(iterator.next2BytesToInt()); + lItem.setNameIndex(iterator.next2BytesToInt()); + lItem.setDescribeIndex(iterator.next2BytesToInt()); + lItem.setSlotIndex(iterator.next2BytesToInt()); + + lTable.addLocalVaribleItem(lItem); + } + } + return lTable; + } + +} diff --git "a/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/attribute/StackMapTable.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/attribute/StackMapTable.java" new file mode 100644 index 0000000000..0559fa60f1 --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/attribute/StackMapTable.java" @@ -0,0 +1,36 @@ +package com.coderising.jvm.attribute; + +import com.coderising.jvm.clasfile.ClassFile; +import com.coderising.jvm.loader.ByteCodeIterator; + +public class StackMapTable extends AttributeInfo{ + + private String originCode; + + public String getOriginCode() { + return originCode; + } + + public void setOriginCode(String originCode) { + this.originCode = originCode; + } + + public StackMapTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static StackMapTable parse(ClassFile classFile, + ByteCodeIterator iterator) { + + iterator.back(2); + int attName_index = iterator.next2BytesToInt(); + int attr_len = iterator.next4BytesToInt(); + StackMapTable stackMapTable = new StackMapTable(attName_index, attr_len); + + String codeString = iterator.nextXBytesToString(attr_len); + stackMapTable.setOriginCode(codeString); + + return stackMapTable; + } + +} diff --git "a/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/clasfile/AccessFlag.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/clasfile/AccessFlag.java" new file mode 100644 index 0000000000..b1d40c20ff --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-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\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/clasfile/ClassFile.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/clasfile/ClassFile.java" new file mode 100644 index 0000000000..708257ddb2 --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/clasfile/ClassFile.java" @@ -0,0 +1,85 @@ +package com.coderising.jvm.clasfile; + +import java.util.ArrayList; +import java.util.List; + +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.field.JField; +import com.coderising.jvm.method.JMethod; + +public class ClassFile { + + private int MinorVersion; + private int MajorVersion; + private String MagicNumer; + private ConstantPool pool; + private ClassIndex classIndex; + private AccessFlag accessFlag; + private List<JField> fields = new ArrayList<>(); + private List<JMethod> jMethods = new ArrayList<>(); + + 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 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; + } + + public List<JField> getJFields() { + return this.fields; + } + + public void addJField(JField jField){ + this.fields.add(jField); + } + + public List<JMethod> getMethods() { + return this.jMethods; + } + + public void addJMethod(JMethod jmethod){ + this.jMethods.add(jmethod); + } + +} diff --git "a/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/clasfile/ClassIndex.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/clasfile/ClassIndex.java" new file mode 100644 index 0000000000..c98eae755f --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-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\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/ClassInfo.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/ClassInfo.java" new file mode 100644 index 0000000000..4f9077cbb6 --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-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\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/ConstantInfo.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/ConstantInfo.java" new file mode 100644 index 0000000000..bc2acc7c6e --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-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\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/ConstantPool.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/ConstantPool.java" new file mode 100644 index 0000000000..9e6016915c --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/ConstantPool.java" @@ -0,0 +1,25 @@ +package com.coderising.jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + 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); + } + + public String getUtf8String(int index){ + return ((Utf8Info)this.constantInfos.get(index)).getValue(); + } +} diff --git "a/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/FieldRefInfo.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/FieldRefInfo.java" new file mode 100644 index 0000000000..22a7b5c5f7 --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-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\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/MethodInfo.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/MethodInfo.java" new file mode 100644 index 0000000000..1a52212645 --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/MethodInfo.java" @@ -0,0 +1,62 @@ +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\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/NameAndTypeInfo.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/NameAndTypeInfo.java" new file mode 100644 index 0000000000..c8731e9216 --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-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\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/NullConstantInfo.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/NullConstantInfo.java" new file mode 100644 index 0000000000..3428c1ea65 --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-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\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/StringInfo.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/StringInfo.java" new file mode 100644 index 0000000000..83339240f5 --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-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\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/Utf8Info.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/Utf8Info.java" new file mode 100644 index 0000000000..da82973e87 --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/constant/Utf8Info.java" @@ -0,0 +1,30 @@ +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\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/field/JField.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/field/JField.java" new file mode 100644 index 0000000000..005dc0da6d --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/field/JField.java" @@ -0,0 +1,44 @@ +package com.coderising.jvm.field; + +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.Utf8Info; +import com.coderising.jvm.loader.ByteCodeIterator; + +public class JField { + + private int access_flags; + private int name_index; + private int descriptor_index; + private ConstantPool pool; + + public JField(int access_flags, int name_index, int descriptor_index, + ConstantPool pool) { + this.access_flags = access_flags; + this.name_index = name_index; + this.descriptor_index = descriptor_index; + this.pool = pool; + + } + + public static JField parse(ConstantPool pool, ByteCodeIterator iterator){ + + int accessflag = iterator.next2BytesToInt(); + int nameindex = iterator.next2BytesToInt(); + int descripindex = iterator.next2BytesToInt(); + + int attribute_count = iterator.next2BytesToInt(); + if (attribute_count > 0) { + throw new RuntimeException("Field attribute_info is not added."); + } + JField field = new JField(accessflag, nameindex, descripindex, pool); + return field; + } + + public String toString(){ + + String name = ((Utf8Info)this.pool.getConstantInfo(name_index)).getValue(); + String descriptor = ((Utf8Info) this.pool.getConstantInfo(descriptor_index)).getValue(); + + return name + ":" + descriptor; + } +} diff --git "a/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/loader/ByteCodeIterator.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/loader/ByteCodeIterator.java" new file mode 100644 index 0000000000..2ae06411ce --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/loader/ByteCodeIterator.java" @@ -0,0 +1,67 @@ +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 int next4BytesToInt(){ + if (pos < this.codes.length) { + return Util.bytesToInt(new byte[]{codes[pos++],codes[pos++],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; + } + public String nextXBytesToString(int len){ + + byte[] temp = new byte[len]; + for (int i = 0; i < temp.length; i++) { + temp[i] = codes[pos++]; + } + + return Util.bytesToHexString(temp).toLowerCase(); + } + + public void back(int n){ + this.pos -= n; + } +} diff --git "a/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/loader/ClassFileLoader.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/loader/ClassFileLoader.java" new file mode 100644 index 0000000000..0c9c290cca --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/loader/ClassFileLoader.java" @@ -0,0 +1,96 @@ +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 com.coderising.jvm.clasfile.ClassFile; + +public class ClassFileLoader { + + private List<String> list = new ArrayList<String>(); + + 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\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/loader/ClassFileParser.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/loader/ClassFileParser.java" new file mode 100644 index 0000000000..07b8f11cbe --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/loader/ClassFileParser.java" @@ -0,0 +1,169 @@ +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; +import com.coderising.jvm.field.JField; +import com.coderising.jvm.method.JMethod; + +public class ClassFileParser { + + public ClassFile parse(byte[] codes) { + + ClassFile clzFile = new ClassFile(); + + ByteCodeIterator iterator = new ByteCodeIterator(codes); + + // Magic Number + String Magic = iterator.next4BytesToString(); + if (!(Magic.equals("cafebabe"))) { + return null; + } + 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)); + + parseInterface(iterator); + parseJFields(clzFile, iterator); + parseJMethods(clzFile, iterator); + + return clzFile; + } + + private void parseJMethods(ClassFile classFile, ByteCodeIterator iterator){ + + int jmethodCount = iterator.next2BytesToInt(); + System.out.println("JMethod Count:" + jmethodCount); + for (int i = 0; i < jmethodCount; i++) { + JMethod jMethod = JMethod.parse(classFile, iterator); + classFile.addJMethod(jMethod); + } + } + private void parseJFields(ClassFile classFile, ByteCodeIterator iterator){ + + int jfieldCount = iterator.next2BytesToInt(); + System.out.println("JField Count :" + jfieldCount); + + for (int i = 0; i < jfieldCount; i++) { + classFile.addJField(JField.parse(classFile.getPool(), iterator)); + } + + } + private void parseInterface(ByteCodeIterator iterator) { + int interfaceCount = iterator.next2BytesToInt(); + System.out.println("InterfaceCount:" + interfaceCount); + } + + 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); + } + else { + throw new RuntimeException("the constant pool tag " + tag + "has been not immplemented yet!"); + } + } + return pool; + + } +} diff --git "a/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/method/JMethod.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/method/JMethod.java" new file mode 100644 index 0000000000..7c33d89e57 --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/method/JMethod.java" @@ -0,0 +1,81 @@ +package com.coderising.jvm.method; + +import com.coderising.jvm.attribute.AttributeInfo; +import com.coderising.jvm.attribute.CodeAttr; +import com.coderising.jvm.clasfile.ClassFile; +import com.coderising.jvm.constant.Utf8Info; +import com.coderising.jvm.loader.ByteCodeIterator; + +public class JMethod { + + private int access_flags; + private int name_index; + private int descriptor_index; + private ClassFile clzFile; + + private CodeAttr codeAttr; + + public int getAccess_flags() { + return access_flags; + } + + public int getName_index() { + return name_index; + } + + public int getDescriptor_index() { + return descriptor_index; + } + + public ClassFile getClzFile() { + return clzFile; + } + + + public CodeAttr getCodeAttr() { + return codeAttr; + } + + public void setCodeAttr(CodeAttr codeAttr) { + this.codeAttr = codeAttr; + } + + public JMethod(ClassFile clzFile, int access_flags, int name_index, int descriptor_index) { + this.access_flags = access_flags; + this.name_index = name_index; + this.descriptor_index = descriptor_index; + } + + public static JMethod parse(ClassFile classFile, ByteCodeIterator iterator) { + + int accessFlag = iterator.next2BytesToInt(); + int nameIndex = iterator.next2BytesToInt(); + int descripIndex = iterator.next2BytesToInt(); + JMethod jMethod = new JMethod(classFile, accessFlag, nameIndex, descripIndex); + + int attribute_count = iterator.next2BytesToInt(); + if (attribute_count > 0) { + for (int i = 0; i < attribute_count; i++) { + + int attrIndex = iterator.next2BytesToInt(); + String attrName = classFile.getPool().getUtf8String(attrIndex); + + if (AttributeInfo.CODE.equals(attrName)) { + CodeAttr codeAttr = CodeAttr.parse(classFile,iterator); + jMethod.setCodeAttr(codeAttr); + } + else { + throw new RuntimeException("Attribute has not been added." + attrName); + } + } + } + + + + + + + return jMethod; + } + +} diff --git "a/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/test/ClassFileLoaderTest.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/test/ClassFileLoaderTest.java" new file mode 100644 index 0000000000..dd7b271663 --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/test/ClassFileLoaderTest.java" @@ -0,0 +1,266 @@ +package com.coderising.jvm.test; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.coderising.jvm.attribute.CodeAttr; +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.field.JField; +import com.coderising.jvm.loader.ClassFileLoader; +import com.coderising.jvm.method.JMethod; + +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 testConstantool() { + + ConstantPool pool = clzFile.getPool(); + + 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("<init>", 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.getPool() + .getConstantInfo(clzIndex.getThisClassIndex()); + ClassInfo superClassInfo = (ClassInfo) clzFile.getPool() + .getConstantInfo(clzIndex.getSuperClassIndex()); + + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, + thisClassInfo.getClassName()); + Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); + } + + /** + * JVMʵֲ + */ + @Test + public void testReadFields() { + + List<JField> jfields = clzFile.getJFields(); + + Assert.assertEquals(2, jfields.size()); + { + JField jfield = jfields.get(0); + Assert.assertEquals("name:Ljava/lang/String;", jfield.toString()); + } + { + JField jfield = jfields.get(1); + Assert.assertEquals("age:I", jfield.toString()); + } + + } + + + @Test + public void testMethod() { + + List<JMethod> jMethods = clzFile.getMethods(); + ConstantPool pool = clzFile.getPool(); + + { + JMethod jMethod = jMethods.get(0); + assertJMethodEquals(pool, jMethod, "<init>", + "(Ljava/lang/String;I)V", "2ab7000c2a2bb5000f2a1cb50011b1"); + } + { + JMethod jMethod = jMethods.get(1); + assertJMethodEquals(pool,jMethod, + "setName", + "(Ljava/lang/String;)V", + "2a2bb5000fb1"); + + } + { + JMethod jMethod = jMethods.get(2); + assertJMethodEquals(pool,jMethod, + "setAge", + "(I)V", + "2a1bb50011b1"); + } + { + JMethod jMethod = jMethods.get(3); + assertJMethodEquals(pool,jMethod, + "sayHello", + "()V", + "b2001c1222b60024b1"); + + } + { + JMethod jMethod = jMethods.get(4); + assertJMethodEquals(pool,jMethod, + "main", + "([Ljava/lang/String;)V", + "bb000159122b101db7002d4c2bb6002fb1"); + } + } + + + private void assertJMethodEquals(ConstantPool pool, JMethod jMethod, + String expectedName, String expectedDescrib, String expectedCode) { + String methodNameString = pool.getUtf8String(jMethod.getName_index()); + String realDescrib = pool.getUtf8String(jMethod.getDescriptor_index()); + String realCode = jMethod.getCodeAttr().getCodeString(); + + Assert.assertEquals(expectedName, methodNameString); + Assert.assertEquals(expectedDescrib, realDescrib); + Assert.assertEquals(expectedCode, realCode); + } + +} diff --git "a/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/test/EmployeeV1.java" "b/group20/925290009/\347\254\254\345\205\255\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\205\255\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(); + } + +} diff --git "a/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/utils/Util.java" "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-jvm/com/coderising/jvm/utils/Util.java" new file mode 100644 index 0000000000..56648f5db9 --- /dev/null +++ "b/group20/925290009/\347\254\254\345\205\255\346\254\241\344\275\234\344\270\232/mini-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 c7fc5d3a8b343fbc906e363701c2db8f2264a1aa Mon Sep 17 00:00:00 2001 From: jy97799 <977996067@qq.com> Date: Sat, 15 Apr 2017 15:13:20 +0800 Subject: [PATCH 257/287] =?UTF-8?q?4.16=E4=BD=9C=E4=B8=9A=20=E4=B8=AD?= =?UTF-8?q?=E5=BA=8F=E9=81=8D=E5=8E=86&JVM=E8=A7=A3=E6=9E=90=E5=AD=97?= =?UTF-8?q?=E6=AE=B5+=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/task6/expr/InfixExpr.java | 80 ++++++++ .../src/task6/expr/InfixExprTest.java | 56 +++++ .../src/task6/jvm/attr/AttributeInfo.java | 19 ++ .../src/task6/jvm/attr/CodeAttr.java | 120 +++++++++++ .../src/task6/jvm/attr/LineNumberTable.java | 72 +++++++ .../src/task6/jvm/attr/LocalVariableItem.java | 39 ++++ .../task6/jvm/attr/LocalVariableTable.java | 57 ++++++ .../src/task6/jvm/attr/StackMapTable.java | 30 +++ .../src/task6/jvm/clz/AccessFlag.java | 25 +++ .../src/task6/jvm/clz/ClassFile.java | 115 +++++++++++ .../src/task6/jvm/clz/ClassIndex.java | 19 ++ .../src/task6/jvm/constant/ClassInfo.java | 24 +++ .../src/task6/jvm/constant/ConstantInfo.java | 29 +++ .../src/task6/jvm/constant/ConstantPool.java | 37 ++++ .../src/task6/jvm/constant/FieldRefInfo.java | 54 +++++ .../src/task6/jvm/constant/MethodRefInfo.java | 55 +++++ .../task6/jvm/constant/NameAndTypeInfo.java | 45 +++++ .../task6/jvm/constant/NullConstantInfo.java | 13 ++ .../src/task6/jvm/constant/StringInfo.java | 26 +++ .../src/task6/jvm/constant/UTF8Info.java | 32 +++ .../src/task6/jvm/field/Field.java | 48 +++++ .../task6/jvm/loader/ByteCodeIterator.java | 56 +++++ .../src/task6/jvm/loader/ClassFileLoader.java | 122 +++++++++++ .../src/task6/jvm/loader/ClassFileParser.java | 112 ++++++++++ .../src/task6/jvm/method/Method.java | 91 +++++++++ .../task6/jvm/test/ClassFileloaderTest.java | 191 ++++++++++++++++++ .../src/task6/jvm/test/EmployeeV1.java | 29 +++ .../src/task6/jvm/util/Util.java | 23 +++ 28 files changed, 1619 insertions(+) create mode 100644 group15/1507_977996067/src/task6/expr/InfixExpr.java create mode 100644 group15/1507_977996067/src/task6/expr/InfixExprTest.java create mode 100644 group15/1507_977996067/src/task6/jvm/attr/AttributeInfo.java create mode 100644 group15/1507_977996067/src/task6/jvm/attr/CodeAttr.java create mode 100644 group15/1507_977996067/src/task6/jvm/attr/LineNumberTable.java create mode 100644 group15/1507_977996067/src/task6/jvm/attr/LocalVariableItem.java create mode 100644 group15/1507_977996067/src/task6/jvm/attr/LocalVariableTable.java create mode 100644 group15/1507_977996067/src/task6/jvm/attr/StackMapTable.java create mode 100644 group15/1507_977996067/src/task6/jvm/clz/AccessFlag.java create mode 100644 group15/1507_977996067/src/task6/jvm/clz/ClassFile.java create mode 100644 group15/1507_977996067/src/task6/jvm/clz/ClassIndex.java create mode 100644 group15/1507_977996067/src/task6/jvm/constant/ClassInfo.java create mode 100644 group15/1507_977996067/src/task6/jvm/constant/ConstantInfo.java create mode 100644 group15/1507_977996067/src/task6/jvm/constant/ConstantPool.java create mode 100644 group15/1507_977996067/src/task6/jvm/constant/FieldRefInfo.java create mode 100644 group15/1507_977996067/src/task6/jvm/constant/MethodRefInfo.java create mode 100644 group15/1507_977996067/src/task6/jvm/constant/NameAndTypeInfo.java create mode 100644 group15/1507_977996067/src/task6/jvm/constant/NullConstantInfo.java create mode 100644 group15/1507_977996067/src/task6/jvm/constant/StringInfo.java create mode 100644 group15/1507_977996067/src/task6/jvm/constant/UTF8Info.java create mode 100644 group15/1507_977996067/src/task6/jvm/field/Field.java create mode 100644 group15/1507_977996067/src/task6/jvm/loader/ByteCodeIterator.java create mode 100644 group15/1507_977996067/src/task6/jvm/loader/ClassFileLoader.java create mode 100644 group15/1507_977996067/src/task6/jvm/loader/ClassFileParser.java create mode 100644 group15/1507_977996067/src/task6/jvm/method/Method.java create mode 100644 group15/1507_977996067/src/task6/jvm/test/ClassFileloaderTest.java create mode 100644 group15/1507_977996067/src/task6/jvm/test/EmployeeV1.java create mode 100644 group15/1507_977996067/src/task6/jvm/util/Util.java diff --git a/group15/1507_977996067/src/task6/expr/InfixExpr.java b/group15/1507_977996067/src/task6/expr/InfixExpr.java new file mode 100644 index 0000000000..ae4dda95ad --- /dev/null +++ b/group15/1507_977996067/src/task6/expr/InfixExpr.java @@ -0,0 +1,80 @@ +package task6.expr; + +import org.junit.Assert; +import task5.stack.Stack; + +import java.util.Arrays; +import java.util.stream.Collectors; + +public class InfixExpr { + + private String expr; + + private Stack<Float> numberStack = new Stack<>(); + + private Stack<Float> resultStack = new Stack<>(); + + public InfixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + + Assert.assertNotNull(expr); + + String[] operators = expr.split("[\\d]+"); + + int length = operators.length; + + Arrays.stream(expr.split("[+\\-*/]+")) + .map(Float::parseFloat) + .forEach(numberStack::push); + + numberStack = reverse(numberStack); + + resultStack.push(numberStack.pop()); + + for (int i = 1; i < length; i++) { + String currentOperator = operators[i]; +// 先做乘除,结果放resultStack里面 + switch (currentOperator) { + case "*": + resultStack.push(resultStack.pop() * numberStack.pop()); + break; + case "/": + resultStack.push(resultStack.pop() / numberStack.pop()); + break; + case "+": + resultStack.push(numberStack.pop()); + break; + case "-": + resultStack.push(numberStack.pop()); + break; + } + } + + resultStack = reverse(resultStack); + +// 做加减 + for (int i = 1; i < length; i++) { + String currentOperator = operators[i]; + if ("+".equals(currentOperator)) { + Float num1 = resultStack.pop(); + Float num2 = resultStack.pop(); + resultStack.push(num1 + num2); + } else if ("-".equals(currentOperator)) { + Float num1 = resultStack.pop(); + Float num2 = resultStack.pop(); + resultStack.push(num1 - num2); + } + } + return resultStack.peek(); + } + + private Stack<Float> reverse(Stack<Float> stackToReverse) { + Stack<Float> temp = new Stack<>(); + while (!stackToReverse.isEmpty()) + temp.push(stackToReverse.pop()); + return temp; + } +} \ No newline at end of file diff --git a/group15/1507_977996067/src/task6/expr/InfixExprTest.java b/group15/1507_977996067/src/task6/expr/InfixExprTest.java new file mode 100644 index 0000000000..487b23a040 --- /dev/null +++ b/group15/1507_977996067/src/task6/expr/InfixExprTest.java @@ -0,0 +1,56 @@ +package task6.expr; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; + +public class InfixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + //InfixExpr expr = new InfixExpr("300*20+12*5-20/4"); + { + InfixExpr expr = new InfixExpr("2+3*4+5"); + Assert.assertEquals(19.0, expr.evaluate(), 0.001f); + } + { + InfixExpr expr = new InfixExpr("3*20+12*5-40/2"); + Assert.assertEquals(100.0, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("3*20/2"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("20/2*3"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("10-30+50"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + } + + @Test + public void testExprSplit() { + String expr = "3*20+12*5-40/2"; + Arrays.stream(expr.split("[+\\-*/]+")).forEach(System.out::println); + Arrays.stream(expr.split("[\\d]+")).forEach(System.out::println); + } + +} \ No newline at end of file diff --git a/group15/1507_977996067/src/task6/jvm/attr/AttributeInfo.java b/group15/1507_977996067/src/task6/jvm/attr/AttributeInfo.java new file mode 100644 index 0000000000..22b7eb0ae0 --- /dev/null +++ b/group15/1507_977996067/src/task6/jvm/attr/AttributeInfo.java @@ -0,0 +1,19 @@ +package task6.jvm.attr; + +public abstract class AttributeInfo { + public static final String CODE = "Code"; + public static final String CONST_VALUE = "ConstantValue"; + public static final String EXCEPTIONS = "Exceptions"; + public static final String LINE_NUM_TABLE = "LineNumberTable"; + public static final String LOCAL_VAR_TABLE = "LocalVariableTable"; + public static final String STACK_MAP_TABLE = "StackMapTable"; + int attrNameIndex; + int attrLen ; + public AttributeInfo(int attrNameIndex, int attrLen) { + + this.attrNameIndex = attrNameIndex; + this.attrLen = attrLen; + } + + +} diff --git a/group15/1507_977996067/src/task6/jvm/attr/CodeAttr.java b/group15/1507_977996067/src/task6/jvm/attr/CodeAttr.java new file mode 100644 index 0000000000..301be0c14d --- /dev/null +++ b/group15/1507_977996067/src/task6/jvm/attr/CodeAttr.java @@ -0,0 +1,120 @@ +package task6.jvm.attr; + + +import task6.jvm.clz.ClassFile; +import task6.jvm.constant.ConstantPool; +import task6.jvm.loader.ByteCodeIterator; + +public class CodeAttr extends AttributeInfo { + private int maxStack ; + private int maxLocals ; + private int codeLen ; + private String code; + public String getCode() { + return code; + } + + //private ByteCodeCommand[] cmds ; + //public ByteCodeCommand[] getCmds() { + // return cmds; + //} + private LineNumberTable lineNumTable; + private LocalVariableTable localVarTable; + private StackMapTable stackMapTable; + + public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen,String code /*ByteCodeCommand[] cmds*/) { + super(attrNameIndex, attrLen); + this.maxStack = maxStack; + this.maxLocals = maxLocals; + this.codeLen = codeLen; + this.code = code; + //this.cmds = cmds; + } + + public void setLineNumberTable(LineNumberTable t) { + this.lineNumTable = t; + } + + public void setLocalVariableTable(LocalVariableTable t) { + this.localVarTable = t; + } + +public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ + + int attrNameIndex = iter.next2Bytes(); + int attrLen = iter.next4Bytes(); + int maxStack = iter.next2Bytes(); + int maxLocals = iter.next2Bytes(); + int codeLen = iter.next4Bytes(); + + String code = iter.nextUxToHexString(codeLen); + + System.out.println(code); + + //ByteCodeCommand[] cmds = ByteCodeCommand.parse(clzFile,code); + + CodeAttr codeAttr = new CodeAttr(attrNameIndex,attrLen, maxStack,maxLocals,codeLen,code); + + int exceptionTableLen = iter.next2Bytes(); + //TODO 处理exception + if(exceptionTableLen>0){ + String exTable = iter.nextUxToHexString(exceptionTableLen); + System.out.println("Encountered exception table , just ignore it :" + exTable); + + } + + + int subAttrCount = iter.next2Bytes(); + + for(int x=1; x<=subAttrCount; x++){ + int subAttrIndex = iter.next2Bytes(); + String subAttrName = clzFile.getConstantPool().getUTF8String(subAttrIndex); + + //已经向前移动了U2, 现在退回去。 + iter.back(2); + //line item table + if(AttributeInfo.LINE_NUM_TABLE.equalsIgnoreCase(subAttrName)){ + + LineNumberTable t = LineNumberTable.parse(iter); + codeAttr.setLineNumberTable(t); + } + else if(AttributeInfo.LOCAL_VAR_TABLE.equalsIgnoreCase(subAttrName)){ + LocalVariableTable t = LocalVariableTable.parse(iter); + codeAttr.setLocalVariableTable(t); + } + else if (AttributeInfo.STACK_MAP_TABLE.equalsIgnoreCase(subAttrName)){ + StackMapTable t = StackMapTable.parse(iter); + codeAttr.setStackMapTable(t); + } + else{ + throw new RuntimeException("Need code to process " + subAttrName); + } + + + } + + return codeAttr; + } + + + public String toString(ConstantPool pool){ + StringBuilder buffer = new StringBuilder(); + buffer.append("Code:").append(code).append("\n"); + /*for(int i=0;i<cmds.length;i++){ + buffer.append(cmds[i].toString(pool)).append("\n"); + }*/ + buffer.append("\n"); + buffer.append(this.lineNumTable.toString()); + buffer.append(this.localVarTable.toString(pool)); + return buffer.toString(); + } + private void setStackMapTable(StackMapTable t) { + this.stackMapTable = t; + + } + + + + + +} diff --git a/group15/1507_977996067/src/task6/jvm/attr/LineNumberTable.java b/group15/1507_977996067/src/task6/jvm/attr/LineNumberTable.java new file mode 100644 index 0000000000..3274411ecc --- /dev/null +++ b/group15/1507_977996067/src/task6/jvm/attr/LineNumberTable.java @@ -0,0 +1,72 @@ +package task6.jvm.attr; + +import task6.jvm.loader.ByteCodeIterator; + +import java.util.ArrayList; +import java.util.List; + +public class LineNumberTable extends AttributeInfo { + List<LineNumberItem> items = new ArrayList<LineNumberItem>(); + + private static class LineNumberItem { + int startPC; + int lineNum; + + public int getStartPC() { + return startPC; + } + + public void setStartPC(int startPC) { + this.startPC = startPC; + } + + public int getLineNum() { + return lineNum; + } + + public void setLineNum(int lineNum) { + this.lineNum = lineNum; + } + } + + public void addLineNumberItem(LineNumberItem item) { + this.items.add(item); + } + + public LineNumberTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + + } + + public static LineNumberTable parse(ByteCodeIterator iter) { + + int index = iter.next2Bytes(); + int len = iter.next4Bytes(); + + LineNumberTable table = new LineNumberTable(index, len); + + int itemLen = iter.next2Bytes(); + + for (int i = 1; i <= itemLen; i++) { + LineNumberItem item = new LineNumberItem(); + item.setStartPC(iter.next2Bytes()); + item.setLineNum(iter.next2Bytes()); + table.addLineNumberItem(item); + } + return table; + } + + public String toString() { + StringBuilder buffer = new StringBuilder(); + buffer.append("Line Number Table:\n"); + for (LineNumberItem item : items) { + buffer.append("startPC:" + item.getStartPC()).append(","); + buffer.append("lineNum:" + item.getLineNum()).append("\n"); + } + buffer.append("\n"); + return buffer.toString(); + + } + + +} diff --git a/group15/1507_977996067/src/task6/jvm/attr/LocalVariableItem.java b/group15/1507_977996067/src/task6/jvm/attr/LocalVariableItem.java new file mode 100644 index 0000000000..78a2ac90b2 --- /dev/null +++ b/group15/1507_977996067/src/task6/jvm/attr/LocalVariableItem.java @@ -0,0 +1,39 @@ +package task6.jvm.attr; + +public class LocalVariableItem { + private int startPC; + private int length; + private int nameIndex; + private int descIndex; + private int index; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getNameIndex() { + return nameIndex; + } + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + public int getDescIndex() { + return descIndex; + } + public void setDescIndex(int descIndex) { + this.descIndex = descIndex; + } + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } +} diff --git a/group15/1507_977996067/src/task6/jvm/attr/LocalVariableTable.java b/group15/1507_977996067/src/task6/jvm/attr/LocalVariableTable.java new file mode 100644 index 0000000000..ec855987e1 --- /dev/null +++ b/group15/1507_977996067/src/task6/jvm/attr/LocalVariableTable.java @@ -0,0 +1,57 @@ +package task6.jvm.attr; + + +import task6.jvm.constant.ConstantPool; +import task6.jvm.loader.ByteCodeIterator; + +import java.util.ArrayList; +import java.util.List; + +public class LocalVariableTable extends AttributeInfo{ + + List<LocalVariableItem> items = new ArrayList<LocalVariableItem>(); + + public LocalVariableTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + + private void addLocalVariableItem(LocalVariableItem item) { + this.items.add(item); + } + + public static LocalVariableTable parse(ByteCodeIterator iter){ + + int index = iter.next2Bytes(); + int len = iter.next4Bytes(); + + LocalVariableTable table = new LocalVariableTable(index,len); + + int itemLen = iter.next2Bytes(); + + for(int i=1; i<=itemLen; i++){ + LocalVariableItem item = new LocalVariableItem(); + item.setStartPC(iter.next2Bytes()); + item.setLength(iter.next2Bytes()); + item.setNameIndex(iter.next2Bytes()); + item.setDescIndex(iter.next2Bytes()); + item.setIndex(iter.next2Bytes()); + table.addLocalVariableItem(item); + } + return table; + } + + + public String toString(ConstantPool pool){ + StringBuilder buffer = new StringBuilder(); + buffer.append("Local Variable Table:\n"); + for(LocalVariableItem item : items){ + buffer.append("startPC:"+item.getStartPC()).append(","); + buffer.append("name:"+pool.getUTF8String(item.getNameIndex())).append(","); + buffer.append("desc:"+pool.getUTF8String(item.getDescIndex())).append(","); + buffer.append("slotIndex:"+ item.getIndex()).append("\n"); + } + buffer.append("\n"); + return buffer.toString(); + } +} diff --git a/group15/1507_977996067/src/task6/jvm/attr/StackMapTable.java b/group15/1507_977996067/src/task6/jvm/attr/StackMapTable.java new file mode 100644 index 0000000000..8206b23797 --- /dev/null +++ b/group15/1507_977996067/src/task6/jvm/attr/StackMapTable.java @@ -0,0 +1,30 @@ +package task6.jvm.attr; + + +import task6.jvm.loader.ByteCodeIterator; + +public class StackMapTable extends AttributeInfo{ + + private String originalCode; + + public StackMapTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static StackMapTable parse(ByteCodeIterator iter){ + int index = iter.next2Bytes(); + int len = iter.next4Bytes(); + StackMapTable t = new StackMapTable(index,len); + + //后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 + String code = iter.nextUxToHexString(len); + t.setOriginalCode(code); + + return t; + } + + private void setOriginalCode(String code) { + this.originalCode = code; + + } +} diff --git a/group15/1507_977996067/src/task6/jvm/clz/AccessFlag.java b/group15/1507_977996067/src/task6/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..5f2b079628 --- /dev/null +++ b/group15/1507_977996067/src/task6/jvm/clz/AccessFlag.java @@ -0,0 +1,25 @@ +package task6.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/task6/jvm/clz/ClassFile.java b/group15/1507_977996067/src/task6/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..f4e2c14bfb --- /dev/null +++ b/group15/1507_977996067/src/task6/jvm/clz/ClassFile.java @@ -0,0 +1,115 @@ +package task6.jvm.clz; + +import task6.jvm.constant.ClassInfo; +import task6.jvm.constant.ConstantPool; +import task6.jvm.field.Field; +import task6.jvm.method.Method; + +import java.util.ArrayList; +import java.util.List; + +public class ClassFile { + + private int minorVersion; + private int majorVersion; + + private AccessFlag accessFlag; + private ClassIndex clzIndex; + private ConstantPool pool; + + private List<Field> fields = new ArrayList<>(); + private List<Method> methods = new ArrayList<>(); + + public void setClzIndex(ClassIndex clzIndex) { + this.clzIndex = clzIndex; + } + + public ConstantPool getPool() { + return pool; + } + + public void setPool(ConstantPool pool) { + this.pool = pool; + } + + public List<Field> getFields() { + return fields; + } + + public void setFields(List<Field> fields) { + this.fields = fields; + } + + public List<Method> getMethods() { + return methods; + } + + public void setMethods(List<Method> methods) { + this.methods = methods; + } + + 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/task6/jvm/clz/ClassIndex.java b/group15/1507_977996067/src/task6/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..3460eacda5 --- /dev/null +++ b/group15/1507_977996067/src/task6/jvm/clz/ClassIndex.java @@ -0,0 +1,19 @@ +package task6.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/task6/jvm/constant/ClassInfo.java b/group15/1507_977996067/src/task6/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..c9fa227420 --- /dev/null +++ b/group15/1507_977996067/src/task6/jvm/constant/ClassInfo.java @@ -0,0 +1,24 @@ +package task6.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/task6/jvm/constant/ConstantInfo.java b/group15/1507_977996067/src/task6/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..5aaa5551e9 --- /dev/null +++ b/group15/1507_977996067/src/task6/jvm/constant/ConstantInfo.java @@ -0,0 +1,29 @@ +package task6.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/task6/jvm/constant/ConstantPool.java b/group15/1507_977996067/src/task6/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..e4f9e4cbc9 --- /dev/null +++ b/group15/1507_977996067/src/task6/jvm/constant/ConstantPool.java @@ -0,0 +1,37 @@ +package task6.jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List<ConstantInfo> 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/task6/jvm/constant/FieldRefInfo.java b/group15/1507_977996067/src/task6/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..19c9cee941 --- /dev/null +++ b/group15/1507_977996067/src/task6/jvm/constant/FieldRefInfo.java @@ -0,0 +1,54 @@ +package task6.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/task6/jvm/constant/MethodRefInfo.java b/group15/1507_977996067/src/task6/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..d39ccb2f1d --- /dev/null +++ b/group15/1507_977996067/src/task6/jvm/constant/MethodRefInfo.java @@ -0,0 +1,55 @@ +package task6.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/task6/jvm/constant/NameAndTypeInfo.java b/group15/1507_977996067/src/task6/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..a4164137db --- /dev/null +++ b/group15/1507_977996067/src/task6/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,45 @@ +package task6.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/task6/jvm/constant/NullConstantInfo.java b/group15/1507_977996067/src/task6/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..fcadb33142 --- /dev/null +++ b/group15/1507_977996067/src/task6/jvm/constant/NullConstantInfo.java @@ -0,0 +1,13 @@ +package task6.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo(){ + + } + @Override + public int getType() { + return -1; + } + +} diff --git a/group15/1507_977996067/src/task6/jvm/constant/StringInfo.java b/group15/1507_977996067/src/task6/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..799f77598a --- /dev/null +++ b/group15/1507_977996067/src/task6/jvm/constant/StringInfo.java @@ -0,0 +1,26 @@ +package task6.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/task6/jvm/constant/UTF8Info.java b/group15/1507_977996067/src/task6/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..2df6a00f77 --- /dev/null +++ b/group15/1507_977996067/src/task6/jvm/constant/UTF8Info.java @@ -0,0 +1,32 @@ +package task6.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/task6/jvm/field/Field.java b/group15/1507_977996067/src/task6/jvm/field/Field.java new file mode 100644 index 0000000000..0c42b23787 --- /dev/null +++ b/group15/1507_977996067/src/task6/jvm/field/Field.java @@ -0,0 +1,48 @@ +package task6.jvm.field; + + +import task6.jvm.constant.ConstantPool; +import task6.jvm.constant.UTF8Info; +import task6.jvm.loader.ByteCodeIterator; + +public class Field { + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private ConstantPool pool; + + public Field(int accessFlag, int nameIndex, int descriptorIndex, ConstantPool pool) { + + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + this.pool = pool; + } + + public String toString() { + String name = ((UTF8Info) pool.getConstantInfo(this.nameIndex)).getValue(); + + String desc = ((UTF8Info) pool.getConstantInfo(this.descriptorIndex)).getValue(); + return name + ":" + desc; + } + + + public static Field parse(ConstantPool pool, ByteCodeIterator iter) { + + int accessFlag = iter.next2Bytes(); + int nameIndex = iter.next2Bytes(); + int descIndex = iter.next2Bytes(); + int attribCount = iter.next2Bytes(); + //System.out.println("field attribute count:"+ attribCount); + + Field f = new Field(accessFlag, nameIndex, descIndex, pool); + + if (attribCount > 0) { + throw new RuntimeException("Field Attribute has not been implemented"); + } + + return f; + } + +} \ No newline at end of file diff --git a/group15/1507_977996067/src/task6/jvm/loader/ByteCodeIterator.java b/group15/1507_977996067/src/task6/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..b1d950b29c --- /dev/null +++ b/group15/1507_977996067/src/task6/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,56 @@ +package task6.jvm.loader; + +import task6.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 next4Bytes() { + return nextBytes(4); + } + + public int nextFlag() { + return nextBytes(1); + } + + public void back(int length) { + position -= length; + } + + public byte[] getBytes(int length) { + byte[] bytes = Arrays.copyOfRange(this.bytes, position, position + length); + position += length; + return bytes; + } + + public String nextUxToHexString(int length) { + return new String(getBytes(length)); + } + + 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/task6/jvm/loader/ClassFileLoader.java b/group15/1507_977996067/src/task6/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..6e09f888b5 --- /dev/null +++ b/group15/1507_977996067/src/task6/jvm/loader/ClassFileLoader.java @@ -0,0 +1,122 @@ +package task6.jvm.loader; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import task6.jvm.clz.ClassFile; + +import java.io.*; +import java.util.ArrayList; +import java.util.List; + +public class ClassFileLoader { + + private List<String> clzPaths = new ArrayList<String>(); + + 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/task6/jvm/loader/ClassFileParser.java b/group15/1507_977996067/src/task6/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..a00f1b342e --- /dev/null +++ b/group15/1507_977996067/src/task6/jvm/loader/ClassFileParser.java @@ -0,0 +1,112 @@ +package task6.jvm.loader; + +import task6.jvm.clz.AccessFlag; +import task6.jvm.clz.ClassFile; +import task6.jvm.clz.ClassIndex; +import task6.jvm.constant.*; +import task6.jvm.field.Field; +import task6.jvm.method.Method; + +import java.util.ArrayList; +import java.util.List; + +public class ClassFileParser { + + private ConstantPool constantPool; + + 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()); + + parseConstantPool(iterator); + classFile.setConstPool(constantPool); + classFile.setAccessFlag(parseAccessFlag(iterator)); + classFile.setClassIndex(parseClassIndex(iterator));//task5 over + + iterator.next2Bytes(); // interface + + classFile.setFields(parseFileds(iterator)); + classFile.setMethods(parseMethods(classFile, iterator));//task6 over + 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 void 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); + } + } + this.constantPool = pool; + } + + private List<Field> parseFileds(ByteCodeIterator iter) { + int fieldCount = iter.next2Bytes(); + + List<Field> fieldList = new ArrayList<>(fieldCount); + + for (int i = 0; i < fieldCount; i++) { + Field f = Field.parse(constantPool, iter); + fieldList.add(f); + } + return fieldList; + } + + private List<Method> parseMethods(ClassFile classFile, ByteCodeIterator iter) { + int methodCount = iter.next2Bytes(); + + List<Method> methodList = new ArrayList<>(methodCount); + + for (int i = 0; i < methodCount; i++) { + Method m = Method.parse(classFile, iter); + methodList.add(m); + } + return methodList; + } +} diff --git a/group15/1507_977996067/src/task6/jvm/method/Method.java b/group15/1507_977996067/src/task6/jvm/method/Method.java new file mode 100644 index 0000000000..3b6bafa893 --- /dev/null +++ b/group15/1507_977996067/src/task6/jvm/method/Method.java @@ -0,0 +1,91 @@ +package task6.jvm.method; + +import task6.jvm.attr.AttributeInfo; +import task6.jvm.attr.CodeAttr; +import task6.jvm.clz.ClassFile; +import task6.jvm.constant.ConstantPool; +import task6.jvm.constant.UTF8Info; +import task6.jvm.loader.ByteCodeIterator; + +public class Method { + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private CodeAttr codeAttr; + + private ClassFile clzFile; + + + public ClassFile getClzFile() { + return clzFile; + } + + public int getNameIndex() { + return nameIndex; + } + + public int getDescriptorIndex() { + return descriptorIndex; + } + + public CodeAttr getCodeAttr() { + return codeAttr; + } + + public void setCodeAttr(CodeAttr code) { + this.codeAttr = code; + } + + public Method(ClassFile clzFile, int accessFlag, int nameIndex, int descriptorIndex) { + this.clzFile = clzFile; + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + } + + + public String toString() { + + ConstantPool pool = this.clzFile.getConstantPool(); + StringBuilder buffer = new StringBuilder(); + + String name = ((UTF8Info) pool.getConstantInfo(this.nameIndex)).getValue(); + + String desc = ((UTF8Info) pool.getConstantInfo(this.descriptorIndex)).getValue(); + + buffer.append(name).append(":").append(desc).append("\n"); + + buffer.append(this.codeAttr.toString(pool)); + + return buffer.toString(); + } + + public static Method parse(ClassFile clzFile, ByteCodeIterator iter) { + int accessFlag = iter.next2Bytes(); + int nameIndex = iter.next2Bytes(); + int descIndex = iter.next2Bytes(); + int attribCount = iter.next2Bytes(); + + + Method m = new Method(clzFile, accessFlag, nameIndex, descIndex); + + for (int j = 1; j <= attribCount; j++) { + + int attrNameIndex = iter.next2Bytes(); + String attrName = clzFile.getConstantPool().getUTF8String(attrNameIndex); + iter.back(2); + + if (AttributeInfo.CODE.equalsIgnoreCase(attrName)) { + CodeAttr codeAttr = CodeAttr.parse(clzFile, iter); + m.setCodeAttr(codeAttr); + } else { + throw new RuntimeException("only CODE attribute is implemented , please implement the " + attrName); + } + + } + + return m; + + } +} diff --git a/group15/1507_977996067/src/task6/jvm/test/ClassFileloaderTest.java b/group15/1507_977996067/src/task6/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..b904b45388 --- /dev/null +++ b/group15/1507_977996067/src/task6/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,191 @@ +package task6.jvm.test; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import task6.jvm.clz.ClassFile; +import task6.jvm.clz.ClassIndex; +import task6.jvm.constant.*; +import task6.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("<init>", 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/task6/jvm/test/EmployeeV1.java b/group15/1507_977996067/src/task6/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..6c894392dd --- /dev/null +++ b/group15/1507_977996067/src/task6/jvm/test/EmployeeV1.java @@ -0,0 +1,29 @@ +package task6.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/task6/jvm/util/Util.java b/group15/1507_977996067/src/task6/jvm/util/Util.java new file mode 100644 index 0000000000..a9e2cebf5c --- /dev/null +++ b/group15/1507_977996067/src/task6/jvm/util/Util.java @@ -0,0 +1,23 @@ +package task6.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<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 8aad5ec570d50aae52a62d0701b2ddaa9c47dfe1 Mon Sep 17 00:00:00 2001 From: "kaitao.li" <kaitao.li@wormpex.com> Date: Sat, 15 Apr 2017 15:26:42 +0800 Subject: [PATCH 258/287] week5 StackUtil --- .../com/coding2017/basic/stack/StackUtil.java | 122 ++++++++++++++++++ .../basic/stack/expr/InfixExpr.java | 18 +++ .../coding2017/basic/stack/StackUtilTest.java | 52 ++++++++ .../basic/stack/expr/InfixExprTest.java | 51 ++++++++ 4 files changed, 243 insertions(+) create mode 100644 group01/280646174/basic/src/main/java/com/coding2017/basic/stack/StackUtil.java create mode 100644 group01/280646174/basic/src/main/java/com/coding2017/basic/stack/expr/InfixExpr.java create mode 100644 group01/280646174/basic/src/test/java/com/coding2017/basic/stack/StackUtilTest.java create mode 100644 group01/280646174/basic/src/test/java/com/coding2017/basic/stack/expr/InfixExprTest.java diff --git a/group01/280646174/basic/src/main/java/com/coding2017/basic/stack/StackUtil.java b/group01/280646174/basic/src/main/java/com/coding2017/basic/stack/StackUtil.java new file mode 100644 index 0000000000..99d9e1cb6d --- /dev/null +++ b/group01/280646174/basic/src/main/java/com/coding2017/basic/stack/StackUtil.java @@ -0,0 +1,122 @@ +package com.coding2017.basic.stack; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +import java.util.Map; +import java.util.Set; +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 == null || s.isEmpty()) { + return; + } + + Stack tempStack = new Stack(); + Integer bottom = null; // 到什么元素为止 + Integer temp; + + while (!reachBottom(s, bottom)) { + temp = (Integer) s.pop(); + while (!reachBottom(s, bottom)) { + tempStack.push(s.pop()); + } + s.push(temp); + while (!tempStack.isEmpty()) { + s.push(tempStack.pop()); + } + bottom = temp; + } + } + + private static boolean reachBottom(Stack stack, Integer bottom) { + return stack.isEmpty() || stack.peek() == bottom; + } + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s, Object o) { + Stack tempStack = new Stack(); + while (!s.isEmpty()) { + if (s.peek().equals(o)) { + s.pop(); + break; + } + tempStack.push(s.pop()); + } + while (!tempStack.isEmpty()) { + s.push(tempStack.pop()); + } + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param len + * @return + */ + public static Object[] getTop(Stack s, int len) { + Object[] result = new Object[len]; + Stack tempStack = new Stack(); + for (int i = 0; i < len; i++) { + if (s.isEmpty()) { + break; + } + result[i] = s.peek(); + tempStack.push(s.pop()); + } + while (!tempStack.isEmpty()) { + s.push(tempStack.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) { + Stack<Character> stack = new Stack<>(); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (isRightBracket(c)) { + if (stack.isEmpty() || !isMatchBracket(stack.pop(), c)) { + return false; + } + } else if (isLeftBracket(c)) { + stack.push(c); + } + } + + return stack.isEmpty(); + } + + private static boolean isLeftBracket(Character character) { + final Set<Character> leftBrackets = ImmutableSet.copyOf(new Character[] { '(', '[', '{' }); + return leftBrackets.contains(character); + } + + private static boolean isRightBracket(Character character) { + final Set<Character> rightBrackets = ImmutableSet.copyOf(new Character[] { ')', ']', '}' }); + return rightBrackets.contains(character); + } + + private static boolean isMatchBracket(Character left, Character right) { + final Map<Character, Character> bracketMap = ImmutableMap.<Character, Character> builder().put(')', '(') + .put(']', '[').put('}', '{').build(); + return left.equals(bracketMap.get(right)); + } + +} diff --git a/group01/280646174/basic/src/main/java/com/coding2017/basic/stack/expr/InfixExpr.java b/group01/280646174/basic/src/main/java/com/coding2017/basic/stack/expr/InfixExpr.java new file mode 100644 index 0000000000..0f95b519dd --- /dev/null +++ b/group01/280646174/basic/src/main/java/com/coding2017/basic/stack/expr/InfixExpr.java @@ -0,0 +1,18 @@ +package com.coding2017.basic.stack.expr; + +public class InfixExpr { + String expr = null; + + public InfixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + + return 0.0f; + } + + + + +} diff --git a/group01/280646174/basic/src/test/java/com/coding2017/basic/stack/StackUtilTest.java b/group01/280646174/basic/src/test/java/com/coding2017/basic/stack/StackUtilTest.java new file mode 100644 index 0000000000..d25e7aee3d --- /dev/null +++ b/group01/280646174/basic/src/test/java/com/coding2017/basic/stack/StackUtilTest.java @@ -0,0 +1,52 @@ +package com.coding2017.basic.stack; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.Stack; + +import static org.junit.Assert.*; + +/** + * Created by kaitao.li on 2017/4/15. + */ +public class StackUtilTest { + + private Stack mockStack() { + Stack s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + return s; + } + + @Test + public void testReverse() { + Stack s = mockStack(); + StackUtil.reverse(s); + Assert.assertArrayEquals(s.toArray(), new Integer[] { 5, 4, 3, 2, 1 }); + } + + @Test + public void testRemove() { + Stack s = mockStack(); + StackUtil.remove(s, 3); + Assert.assertArrayEquals(s.toArray(), new Integer[] {1, 2, 4, 5}); + } + + @Test + public void testGetTop() { + Stack s = mockStack(); + Object[] top = StackUtil.getTop(s, 2); + Assert.assertArrayEquals(s.toArray(), new Integer[]{1, 2, 3, 4, 5}); + Assert.assertArrayEquals(top, new Integer[] {5, 4}); + } + + @Test + public void testIsValidPairs() { + Assert.assertTrue(StackUtil.isValidPairs("([e{d}f])")); + Assert.assertFalse(StackUtil.isValidPairs("([b{x]y})")); + } +} \ No newline at end of file diff --git a/group01/280646174/basic/src/test/java/com/coding2017/basic/stack/expr/InfixExprTest.java b/group01/280646174/basic/src/test/java/com/coding2017/basic/stack/expr/InfixExprTest.java new file mode 100644 index 0000000000..0ded3f2a95 --- /dev/null +++ b/group01/280646174/basic/src/test/java/com/coding2017/basic/stack/expr/InfixExprTest.java @@ -0,0 +1,51 @@ +package com.coding2017.basic.stack.expr; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Created by kaitao.li on 2017/4/15. + */ +public class InfixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + //InfixExpr expr = new InfixExpr("300*20+12*5-20/4"); + { + InfixExpr expr = new InfixExpr("2+3*4+5"); + Assert.assertEquals(19.0, expr.evaluate(), 0.001f); + } + { + InfixExpr expr = new InfixExpr("3*20+12*5-40/2"); + Assert.assertEquals(100.0, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("3*20/2"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("20/2*3"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("10-30+50"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + } +} \ No newline at end of file From 3db42e0525c91caf58f7e6fff81dcdbd67e4d2c9 Mon Sep 17 00:00:00 2001 From: zhanglifeng <284422826@qq.com> Date: Sat, 15 Apr 2017 17:34:49 +0800 Subject: [PATCH 259/287] =?UTF-8?q?1=E3=80=81jvm=E7=AC=AC=E4=BA=8C?= =?UTF-8?q?=E6=AC=A1=E4=BD=9C=E4=B8=9A=202=E3=80=81=E5=B0=86=E5=B7=A5?= =?UTF-8?q?=E7=A8=8B=E4=BF=AE=E6=94=B9=E4=B8=BAmaven=E5=B7=A5=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jvm/loader/ClassFileLoader.java | 46 ---- .../jvm/test/ClassFileloaderTest.java | 74 ------- .../src/com/coderising/litestruts/struts.xml | 11 - .../src/com/coding2017/basic/List.java | 9 - .../coderising/download/DownloadThread.java | 0 .../coderising/download/FileDownloader.java | 0 .../download/FileDownloaderTest.java | 0 .../coderising/download/api/Connection.java | 6 +- .../download/api/ConnectionException.java | 0 .../download/api/ConnectionManager.java | 2 +- .../download/api/DownloadListener.java | 2 +- .../download/impl/ConnectionImpl.java | 0 .../download/impl/ConnectionManagerImpl.java | 0 .../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 | 54 +++++ .../jvm/loader/ClassFileLoader.java | 136 ++++++++++++ .../jvm/loader/ClassFileParser.java | 115 ++++++++++ .../jvm/test/ClassFileloaderTest.java | 198 ++++++++++++++++++ .../com/coderising/jvm/test/EmployeeV1.java | 0 .../java/com/coderising/jvm/util/Util.java | 24 +++ .../coderising/litestruts/LoginAction.java | 0 .../com/coderising/litestruts/Struts.java | 0 .../com/coderising/litestruts/StrutsTest.java | 0 .../java}/com/coderising/litestruts/View.java | 0 .../com/coding2017/basic/BinaryTreeNode.java | 0 .../java}/com/coding2017/basic/Iterator.java | 4 +- .../main/java/com/coding2017/basic/List.java | 9 + .../java}/com/coding2017/basic/Queue.java | 0 .../com/coding2017/basic/array/ArrayList.java | 2 +- .../com/coding2017/basic/array/ArrayUtil.java | 0 .../coding2017/basic/array/ArrayUtilTest.java | 0 .../basic/linklist/LRUPageFrame.java | 0 .../basic/linklist/LRUPageFrameTest.java | 0 .../coding2017/basic/linklist/LinkedList.java | 0 .../com/coding2017/basic/stack}/Stack.java | 0 .../com/coding2017/basic/stack/StackUtil.java | 116 ++++++++++ .../coding2017/basic/stack/StackUtilTest.java | 78 +++++++ 48 files changed, 1164 insertions(+), 148 deletions(-) delete mode 100644 group05/284422826/src/com/coderising/jvm/loader/ClassFileLoader.java delete mode 100644 group05/284422826/src/com/coderising/jvm/test/ClassFileloaderTest.java delete mode 100644 group05/284422826/src/com/coderising/litestruts/struts.xml delete mode 100644 group05/284422826/src/com/coding2017/basic/List.java rename group05/284422826/src/{ => main/java}/com/coderising/download/DownloadThread.java (100%) rename group05/284422826/src/{ => main/java}/com/coderising/download/FileDownloader.java (100%) rename group05/284422826/src/{ => main/java}/com/coderising/download/FileDownloaderTest.java (100%) rename group05/284422826/src/{ => main/java}/com/coderising/download/api/Connection.java (75%) rename group05/284422826/src/{ => main/java}/com/coderising/download/api/ConnectionException.java (100%) rename group05/284422826/src/{ => main/java}/com/coderising/download/api/ConnectionManager.java (70%) rename group05/284422826/src/{ => main/java}/com/coderising/download/api/DownloadListener.java (71%) rename group05/284422826/src/{ => main/java}/com/coderising/download/impl/ConnectionImpl.java (100%) rename group05/284422826/src/{ => main/java}/com/coderising/download/impl/ConnectionManagerImpl.java (100%) create mode 100644 group05/284422826/src/main/java/com/coderising/jvm/clz/AccessFlag.java create mode 100644 group05/284422826/src/main/java/com/coderising/jvm/clz/ClassFile.java create mode 100644 group05/284422826/src/main/java/com/coderising/jvm/clz/ClassIndex.java create mode 100644 group05/284422826/src/main/java/com/coderising/jvm/constant/ClassInfo.java create mode 100644 group05/284422826/src/main/java/com/coderising/jvm/constant/ConstantInfo.java create mode 100644 group05/284422826/src/main/java/com/coderising/jvm/constant/ConstantPool.java create mode 100644 group05/284422826/src/main/java/com/coderising/jvm/constant/FieldRefInfo.java create mode 100644 group05/284422826/src/main/java/com/coderising/jvm/constant/MethodRefInfo.java create mode 100644 group05/284422826/src/main/java/com/coderising/jvm/constant/NameAndTypeInfo.java create mode 100644 group05/284422826/src/main/java/com/coderising/jvm/constant/NullConstantInfo.java create mode 100644 group05/284422826/src/main/java/com/coderising/jvm/constant/StringInfo.java create mode 100644 group05/284422826/src/main/java/com/coderising/jvm/constant/UTF8Info.java create mode 100644 group05/284422826/src/main/java/com/coderising/jvm/loader/ByteCodeIterator.java create mode 100644 group05/284422826/src/main/java/com/coderising/jvm/loader/ClassFileLoader.java create mode 100644 group05/284422826/src/main/java/com/coderising/jvm/loader/ClassFileParser.java create mode 100644 group05/284422826/src/main/java/com/coderising/jvm/test/ClassFileloaderTest.java rename group05/284422826/src/{ => main/java}/com/coderising/jvm/test/EmployeeV1.java (100%) create mode 100644 group05/284422826/src/main/java/com/coderising/jvm/util/Util.java rename group05/284422826/src/{ => main/java}/com/coderising/litestruts/LoginAction.java (100%) rename group05/284422826/src/{ => main/java}/com/coderising/litestruts/Struts.java (100%) rename group05/284422826/src/{ => main/java}/com/coderising/litestruts/StrutsTest.java (100%) rename group05/284422826/src/{ => main/java}/com/coderising/litestruts/View.java (100%) rename group05/284422826/src/{ => main/java}/com/coding2017/basic/BinaryTreeNode.java (100%) rename group05/284422826/src/{ => main/java}/com/coding2017/basic/Iterator.java (55%) create mode 100644 group05/284422826/src/main/java/com/coding2017/basic/List.java rename group05/284422826/src/{ => main/java}/com/coding2017/basic/Queue.java (100%) rename group05/284422826/src/{ => main/java}/com/coding2017/basic/array/ArrayList.java (98%) rename group05/284422826/src/{ => main/java}/com/coding2017/basic/array/ArrayUtil.java (100%) rename group05/284422826/src/{ => main/java}/com/coding2017/basic/array/ArrayUtilTest.java (100%) rename group05/284422826/src/{ => main/java}/com/coding2017/basic/linklist/LRUPageFrame.java (100%) rename group05/284422826/src/{ => main/java}/com/coding2017/basic/linklist/LRUPageFrameTest.java (100%) rename group05/284422826/src/{ => main/java}/com/coding2017/basic/linklist/LinkedList.java (100%) rename group05/284422826/src/{com/coding2017/basic => main/java/com/coding2017/basic/stack}/Stack.java (100%) create mode 100644 group05/284422826/src/main/java/com/coding2017/basic/stack/StackUtil.java create mode 100644 group05/284422826/src/main/java/com/coding2017/basic/stack/StackUtilTest.java diff --git a/group05/284422826/src/com/coderising/jvm/loader/ClassFileLoader.java b/group05/284422826/src/com/coderising/jvm/loader/ClassFileLoader.java deleted file mode 100644 index a15237f0cb..0000000000 --- a/group05/284422826/src/com/coderising/jvm/loader/ClassFileLoader.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.coderising.jvm.loader; - -import java.io.BufferedInputStream; -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<String> clzPaths = new ArrayList<>(); - - public byte[] readBinaryCode(String className) { - String name = this.getClassPath() + File.separatorChar + className.replace('.', File.separatorChar) + ".class"; - File file = new File(name); - byte[] bytes = new byte[(int)file.length()]; - try { - BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); - while (bis.read(bytes) != -1) { - System.out.println(Arrays.toString(bytes)); - } - } catch (IOException e) { - e.printStackTrace(); - } - return bytes; - } - - - public void addClassPath(String path) { - clzPaths.add(path); - } - - - public String getClassPath() { - StringBuilder path = new StringBuilder(); - for (String str : clzPaths) { - path.append(str).append(";"); - } - return path.substring(0, path.length() - 1); - } - - -} diff --git a/group05/284422826/src/com/coderising/jvm/test/ClassFileloaderTest.java b/group05/284422826/src/com/coderising/jvm/test/ClassFileloaderTest.java deleted file mode 100644 index ca669de57a..0000000000 --- a/group05/284422826/src/com/coderising/jvm/test/ClassFileloaderTest.java +++ /dev/null @@ -1,74 +0,0 @@ -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 = "D:\\git\\coding2017\\group05\\284422826\\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 ){ - StringBuilder buffer = new StringBuilder(); - for (byte b : codes) { - 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/group05/284422826/src/com/coderising/litestruts/struts.xml b/group05/284422826/src/com/coderising/litestruts/struts.xml deleted file mode 100644 index a7cb57e188..0000000000 --- a/group05/284422826/src/com/coderising/litestruts/struts.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<struts> - <action name="login" class="com.coderising.litestruts.LoginAction"> - <result name="success">/jsp/homepage.jsp</result> - <result name="fail">/jsp/showLogin.jsp</result> - </action> - <action name="logout" class="com.coderising.action.LogoutAction"> - <result name= "success">/jsp/welcome.jsp</result> - <result name= "error">/jsp/error.jsp</result> - </action> -</struts> \ No newline at end of file diff --git a/group05/284422826/src/com/coding2017/basic/List.java b/group05/284422826/src/com/coding2017/basic/List.java deleted file mode 100644 index 25c197cc18..0000000000 --- a/group05/284422826/src/com/coding2017/basic/List.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.coding2017.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/group05/284422826/src/com/coderising/download/DownloadThread.java b/group05/284422826/src/main/java/com/coderising/download/DownloadThread.java similarity index 100% rename from group05/284422826/src/com/coderising/download/DownloadThread.java rename to group05/284422826/src/main/java/com/coderising/download/DownloadThread.java diff --git a/group05/284422826/src/com/coderising/download/FileDownloader.java b/group05/284422826/src/main/java/com/coderising/download/FileDownloader.java similarity index 100% rename from group05/284422826/src/com/coderising/download/FileDownloader.java rename to group05/284422826/src/main/java/com/coderising/download/FileDownloader.java diff --git a/group05/284422826/src/com/coderising/download/FileDownloaderTest.java b/group05/284422826/src/main/java/com/coderising/download/FileDownloaderTest.java similarity index 100% rename from group05/284422826/src/com/coderising/download/FileDownloaderTest.java rename to group05/284422826/src/main/java/com/coderising/download/FileDownloaderTest.java diff --git a/group05/284422826/src/com/coderising/download/api/Connection.java b/group05/284422826/src/main/java/com/coderising/download/api/Connection.java similarity index 75% rename from group05/284422826/src/com/coderising/download/api/Connection.java rename to group05/284422826/src/main/java/com/coderising/download/api/Connection.java index 0957eaf7f4..622dc26bc6 100644 --- a/group05/284422826/src/com/coderising/download/api/Connection.java +++ b/group05/284422826/src/main/java/com/coderising/download/api/Connection.java @@ -9,15 +9,15 @@ public interface Connection { * @param endPos 结束位置 * @return */ - public byte[] read(int startPos,int endPos) throws IOException; + byte[] read(int startPos, int endPos) throws IOException; /** * 得到数据内容的长度 * @return */ - public int getContentLength(); + int getContentLength(); /** * 关闭连接 */ - public void close(); + void close(); } diff --git a/group05/284422826/src/com/coderising/download/api/ConnectionException.java b/group05/284422826/src/main/java/com/coderising/download/api/ConnectionException.java similarity index 100% rename from group05/284422826/src/com/coderising/download/api/ConnectionException.java rename to group05/284422826/src/main/java/com/coderising/download/api/ConnectionException.java diff --git a/group05/284422826/src/com/coderising/download/api/ConnectionManager.java b/group05/284422826/src/main/java/com/coderising/download/api/ConnectionManager.java similarity index 70% rename from group05/284422826/src/com/coderising/download/api/ConnectionManager.java rename to group05/284422826/src/main/java/com/coderising/download/api/ConnectionManager.java index ce045393b1..a478bd3d2d 100644 --- a/group05/284422826/src/com/coderising/download/api/ConnectionManager.java +++ b/group05/284422826/src/main/java/com/coderising/download/api/ConnectionManager.java @@ -6,5 +6,5 @@ public interface ConnectionManager { * @param url * @return */ - public Connection open(String url) throws ConnectionException; + Connection open(String url) throws ConnectionException; } diff --git a/group05/284422826/src/com/coderising/download/api/DownloadListener.java b/group05/284422826/src/main/java/com/coderising/download/api/DownloadListener.java similarity index 71% rename from group05/284422826/src/com/coderising/download/api/DownloadListener.java rename to group05/284422826/src/main/java/com/coderising/download/api/DownloadListener.java index bf9807b307..de81b7607d 100644 --- a/group05/284422826/src/com/coderising/download/api/DownloadListener.java +++ b/group05/284422826/src/main/java/com/coderising/download/api/DownloadListener.java @@ -1,5 +1,5 @@ package com.coderising.download.api; public interface DownloadListener { - public void notifyFinished(); + void notifyFinished(); } diff --git a/group05/284422826/src/com/coderising/download/impl/ConnectionImpl.java b/group05/284422826/src/main/java/com/coderising/download/impl/ConnectionImpl.java similarity index 100% rename from group05/284422826/src/com/coderising/download/impl/ConnectionImpl.java rename to group05/284422826/src/main/java/com/coderising/download/impl/ConnectionImpl.java diff --git a/group05/284422826/src/com/coderising/download/impl/ConnectionManagerImpl.java b/group05/284422826/src/main/java/com/coderising/download/impl/ConnectionManagerImpl.java similarity index 100% rename from group05/284422826/src/com/coderising/download/impl/ConnectionManagerImpl.java rename to group05/284422826/src/main/java/com/coderising/download/impl/ConnectionManagerImpl.java diff --git a/group05/284422826/src/main/java/com/coderising/jvm/clz/AccessFlag.java b/group05/284422826/src/main/java/com/coderising/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..faae056835 --- /dev/null +++ b/group05/284422826/src/main/java/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/284422826/src/main/java/com/coderising/jvm/clz/ClassFile.java b/group05/284422826/src/main/java/com/coderising/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..650ca8375d --- /dev/null +++ b/group05/284422826/src/main/java/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/284422826/src/main/java/com/coderising/jvm/clz/ClassIndex.java b/group05/284422826/src/main/java/com/coderising/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..e424f284b3 --- /dev/null +++ b/group05/284422826/src/main/java/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/284422826/src/main/java/com/coderising/jvm/constant/ClassInfo.java b/group05/284422826/src/main/java/com/coderising/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..aea9048ea4 --- /dev/null +++ b/group05/284422826/src/main/java/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/284422826/src/main/java/com/coderising/jvm/constant/ConstantInfo.java b/group05/284422826/src/main/java/com/coderising/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..466b072244 --- /dev/null +++ b/group05/284422826/src/main/java/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/284422826/src/main/java/com/coderising/jvm/constant/ConstantPool.java b/group05/284422826/src/main/java/com/coderising/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..86c0445695 --- /dev/null +++ b/group05/284422826/src/main/java/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<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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/284422826/src/main/java/com/coderising/jvm/constant/FieldRefInfo.java b/group05/284422826/src/main/java/com/coderising/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..65475e194c --- /dev/null +++ b/group05/284422826/src/main/java/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/284422826/src/main/java/com/coderising/jvm/constant/MethodRefInfo.java b/group05/284422826/src/main/java/com/coderising/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..7f05870020 --- /dev/null +++ b/group05/284422826/src/main/java/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/284422826/src/main/java/com/coderising/jvm/constant/NameAndTypeInfo.java b/group05/284422826/src/main/java/com/coderising/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..402f9dec86 --- /dev/null +++ b/group05/284422826/src/main/java/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/284422826/src/main/java/com/coderising/jvm/constant/NullConstantInfo.java b/group05/284422826/src/main/java/com/coderising/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..936736016f --- /dev/null +++ b/group05/284422826/src/main/java/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/284422826/src/main/java/com/coderising/jvm/constant/StringInfo.java b/group05/284422826/src/main/java/com/coderising/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..f1f8eb4ed4 --- /dev/null +++ b/group05/284422826/src/main/java/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/284422826/src/main/java/com/coderising/jvm/constant/UTF8Info.java b/group05/284422826/src/main/java/com/coderising/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..5cac9f04f7 --- /dev/null +++ b/group05/284422826/src/main/java/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/284422826/src/main/java/com/coderising/jvm/loader/ByteCodeIterator.java b/group05/284422826/src/main/java/com/coderising/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..d15af81630 --- /dev/null +++ b/group05/284422826/src/main/java/com/coderising/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,54 @@ +package com.coderising.jvm.loader; + +import com.coderising.jvm.util.Util; + +import java.util.Arrays; + + +public class ByteCodeIterator { + byte[] codes; + int pos = 0; + + public ByteCodeIterator(byte[] codes) { + this.codes = codes; + } + + public byte[] getBytes(int len) { + if (pos + len >= codes.length) { + throw new ArrayIndexOutOfBoundsException(); + } + + byte[] data = Arrays.copyOfRange(codes, pos, pos + len); + pos = pos + len; + return data; + } + + 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 nextUxToHexString(int len){ + byte[] temp = new byte[len]; + for (int i = 0; i < len; i++) { + temp[i] = codes[pos++]; + } + return Util.byteToHexString(temp).toLowerCase(); + } + + public void back(int n){ + pos = pos - n; + } + +} diff --git a/group05/284422826/src/main/java/com/coderising/jvm/loader/ClassFileLoader.java b/group05/284422826/src/main/java/com/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..0560d27c8a --- /dev/null +++ b/group05/284422826/src/main/java/com/coderising/jvm/loader/ClassFileLoader.java @@ -0,0 +1,136 @@ +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 com.coderising.jvm.clz.ClassFile; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; + +public class ClassFileLoader { + + private List<String> clzPaths = new ArrayList<String>(); + + 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/group05/284422826/src/main/java/com/coderising/jvm/loader/ClassFileParser.java b/group05/284422826/src/main/java/com/coderising/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..d133cbafb6 --- /dev/null +++ b/group05/284422826/src/main/java/com/coderising/jvm/loader/ClassFileParser.java @@ -0,0 +1,115 @@ +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) { + 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); + + AccessFlag flag = parseAccessFlag(iter); + clzFile.setAccessFlag(flag); + + ClassIndex clzIndex = parseClassInfex(iter); + clzFile.setClassIndex(clzIndex); + + return clzFile; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + AccessFlag accessFlag = new AccessFlag(iter.nextU2toInt()); + + return accessFlag; + } + + private ClassIndex parseClassInfex(ByteCodeIterator iter) { + int thisClassIndex = iter.nextU2toInt(); + int superClassIndex = iter.nextU2toInt(); + ClassIndex clzIndex = new ClassIndex(); + clzIndex.setThisClassIndex(thisClassIndex); + clzIndex.setSuperClassIndex(superClassIndex); + return clzIndex; + + } + + private ConstantPool parseConstantPool(ByteCodeIterator iter) { + int constantPoolCount = iter.nextU2toInt();//常量池中常量的个数 + ConstantPool pool = new ConstantPool(); + pool.addConstantInfo(new NullConstantInfo()); + + for (int i = 1; i < constantPoolCount - 1; i++) { //常量池 + int tag = iter.nextU1toInt(); + + if(7 == tag){ //ClassInfo + int utf8Index = iter.nextU2toInt(); //name_index + ClassInfo clzInfo = new ClassInfo(pool); + clzInfo.setUtf8Index(utf8Index); + + pool.addConstantInfo(clzInfo); + }else if(1 == tag){ //UTF8 String + int len = iter.nextU2toInt(); + byte[] data = iter.getBytes(len); + String value = null; + try { + value = new String(data, "UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + UTF8Info utf8Info = new UTF8Info(pool); + utf8Info.setLength(len); + utf8Info.setValue(value); + pool.addConstantInfo(utf8Info); + }else if(8 == tag){ + StringInfo strInfo = new StringInfo(pool); + strInfo.setIndex(iter.nextU2toInt()); + pool.addConstantInfo(strInfo); + }else if(9 == tag){ + FieldRefInfo fieldRefInfo = new FieldRefInfo(pool); + fieldRefInfo.setClassInfoIndex(iter.nextU2toInt()); + fieldRefInfo.setNameAndTypeIndex(iter.nextU2toInt()); + pool.addConstantInfo(fieldRefInfo); + }else if(10 == tag){ + MethodRefInfo methodRefInfo = new MethodRefInfo(pool); + methodRefInfo.setClassInfoIndex(iter.nextU2toInt()); + methodRefInfo.setNameAndTypeIndex(iter.nextU2toInt()); + pool.addConstantInfo(methodRefInfo); + }else if(12 == tag){ + NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(pool); + nameAndTypeInfo.setIndex1(iter.nextU2toInt()); + nameAndTypeInfo.setIndex2(iter.nextU2toInt()); + pool.addConstantInfo(nameAndTypeInfo); + }else { + throw new RuntimeException("the constant pool tag " + tag + " has not been implemented yet."); + } + } + + return pool; + } + + +} diff --git a/group05/284422826/src/main/java/com/coderising/jvm/test/ClassFileloaderTest.java b/group05/284422826/src/main/java/com/coderising/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..6aa29cc87b --- /dev/null +++ b/group05/284422826/src/main/java/com/coderising/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,198 @@ +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.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; + +public class ClassFileloaderTest { + + + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + + static String path1 = "D:\\git\\coding2017\\group05\\284422826\\target\\classes\\"; + 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 { + } + + @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(); + } + + /** + * ---------------------------------------------------------------------- + */ + + + @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("<init>", 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/284422826/src/com/coderising/jvm/test/EmployeeV1.java b/group05/284422826/src/main/java/com/coderising/jvm/test/EmployeeV1.java similarity index 100% rename from group05/284422826/src/com/coderising/jvm/test/EmployeeV1.java rename to group05/284422826/src/main/java/com/coderising/jvm/test/EmployeeV1.java diff --git a/group05/284422826/src/main/java/com/coderising/jvm/util/Util.java b/group05/284422826/src/main/java/com/coderising/jvm/util/Util.java new file mode 100644 index 0000000000..0c4cc8c57c --- /dev/null +++ b/group05/284422826/src/main/java/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<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/group05/284422826/src/com/coderising/litestruts/LoginAction.java b/group05/284422826/src/main/java/com/coderising/litestruts/LoginAction.java similarity index 100% rename from group05/284422826/src/com/coderising/litestruts/LoginAction.java rename to group05/284422826/src/main/java/com/coderising/litestruts/LoginAction.java diff --git a/group05/284422826/src/com/coderising/litestruts/Struts.java b/group05/284422826/src/main/java/com/coderising/litestruts/Struts.java similarity index 100% rename from group05/284422826/src/com/coderising/litestruts/Struts.java rename to group05/284422826/src/main/java/com/coderising/litestruts/Struts.java diff --git a/group05/284422826/src/com/coderising/litestruts/StrutsTest.java b/group05/284422826/src/main/java/com/coderising/litestruts/StrutsTest.java similarity index 100% rename from group05/284422826/src/com/coderising/litestruts/StrutsTest.java rename to group05/284422826/src/main/java/com/coderising/litestruts/StrutsTest.java diff --git a/group05/284422826/src/com/coderising/litestruts/View.java b/group05/284422826/src/main/java/com/coderising/litestruts/View.java similarity index 100% rename from group05/284422826/src/com/coderising/litestruts/View.java rename to group05/284422826/src/main/java/com/coderising/litestruts/View.java diff --git a/group05/284422826/src/com/coding2017/basic/BinaryTreeNode.java b/group05/284422826/src/main/java/com/coding2017/basic/BinaryTreeNode.java similarity index 100% rename from group05/284422826/src/com/coding2017/basic/BinaryTreeNode.java rename to group05/284422826/src/main/java/com/coding2017/basic/BinaryTreeNode.java diff --git a/group05/284422826/src/com/coding2017/basic/Iterator.java b/group05/284422826/src/main/java/com/coding2017/basic/Iterator.java similarity index 55% rename from group05/284422826/src/com/coding2017/basic/Iterator.java rename to group05/284422826/src/main/java/com/coding2017/basic/Iterator.java index 19e214cfbb..939c382551 100644 --- a/group05/284422826/src/com/coding2017/basic/Iterator.java +++ b/group05/284422826/src/main/java/com/coding2017/basic/Iterator.java @@ -1,7 +1,7 @@ package com.coding2017.basic; public interface Iterator { - public boolean hasNext(); - public Object next(); + boolean hasNext(); + Object next(); } diff --git a/group05/284422826/src/main/java/com/coding2017/basic/List.java b/group05/284422826/src/main/java/com/coding2017/basic/List.java new file mode 100644 index 0000000000..0b6a48e7e4 --- /dev/null +++ b/group05/284422826/src/main/java/com/coding2017/basic/List.java @@ -0,0 +1,9 @@ +package com.coding2017.basic; + +public interface List { + void add(Object o); + void add(int index, Object o); + Object get(int index); + Object remove(int index); + int size(); +} diff --git a/group05/284422826/src/com/coding2017/basic/Queue.java b/group05/284422826/src/main/java/com/coding2017/basic/Queue.java similarity index 100% rename from group05/284422826/src/com/coding2017/basic/Queue.java rename to group05/284422826/src/main/java/com/coding2017/basic/Queue.java diff --git a/group05/284422826/src/com/coding2017/basic/array/ArrayList.java b/group05/284422826/src/main/java/com/coding2017/basic/array/ArrayList.java similarity index 98% rename from group05/284422826/src/com/coding2017/basic/array/ArrayList.java rename to group05/284422826/src/main/java/com/coding2017/basic/array/ArrayList.java index 3baaf4e597..236b3006ac 100644 --- a/group05/284422826/src/com/coding2017/basic/array/ArrayList.java +++ b/group05/284422826/src/main/java/com/coding2017/basic/array/ArrayList.java @@ -86,7 +86,7 @@ private ArrayListIterator(ArrayList arrayList) { @Override public boolean hasNext() { current++; - return current > arrayList.size() ? false : true; + return current <= arrayList.size(); } @Override diff --git a/group05/284422826/src/com/coding2017/basic/array/ArrayUtil.java b/group05/284422826/src/main/java/com/coding2017/basic/array/ArrayUtil.java similarity index 100% rename from group05/284422826/src/com/coding2017/basic/array/ArrayUtil.java rename to group05/284422826/src/main/java/com/coding2017/basic/array/ArrayUtil.java diff --git a/group05/284422826/src/com/coding2017/basic/array/ArrayUtilTest.java b/group05/284422826/src/main/java/com/coding2017/basic/array/ArrayUtilTest.java similarity index 100% rename from group05/284422826/src/com/coding2017/basic/array/ArrayUtilTest.java rename to group05/284422826/src/main/java/com/coding2017/basic/array/ArrayUtilTest.java diff --git a/group05/284422826/src/com/coding2017/basic/linklist/LRUPageFrame.java b/group05/284422826/src/main/java/com/coding2017/basic/linklist/LRUPageFrame.java similarity index 100% rename from group05/284422826/src/com/coding2017/basic/linklist/LRUPageFrame.java rename to group05/284422826/src/main/java/com/coding2017/basic/linklist/LRUPageFrame.java diff --git a/group05/284422826/src/com/coding2017/basic/linklist/LRUPageFrameTest.java b/group05/284422826/src/main/java/com/coding2017/basic/linklist/LRUPageFrameTest.java similarity index 100% rename from group05/284422826/src/com/coding2017/basic/linklist/LRUPageFrameTest.java rename to group05/284422826/src/main/java/com/coding2017/basic/linklist/LRUPageFrameTest.java diff --git a/group05/284422826/src/com/coding2017/basic/linklist/LinkedList.java b/group05/284422826/src/main/java/com/coding2017/basic/linklist/LinkedList.java similarity index 100% rename from group05/284422826/src/com/coding2017/basic/linklist/LinkedList.java rename to group05/284422826/src/main/java/com/coding2017/basic/linklist/LinkedList.java diff --git a/group05/284422826/src/com/coding2017/basic/Stack.java b/group05/284422826/src/main/java/com/coding2017/basic/stack/Stack.java similarity index 100% rename from group05/284422826/src/com/coding2017/basic/Stack.java rename to group05/284422826/src/main/java/com/coding2017/basic/stack/Stack.java diff --git a/group05/284422826/src/main/java/com/coding2017/basic/stack/StackUtil.java b/group05/284422826/src/main/java/com/coding2017/basic/stack/StackUtil.java new file mode 100644 index 0000000000..c14ddd9039 --- /dev/null +++ b/group05/284422826/src/main/java/com/coding2017/basic/stack/StackUtil.java @@ -0,0 +1,116 @@ +package com.coding2017.basic.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<Integer> s) { + if (s == null || s.isEmpty()) { + return; + } + + Integer top = s.pop(); + reverse(s); + addToBottom(s, top); + } + + public static void addToBottom(Stack<Integer> s, Integer value) { + if(s.isEmpty()){ + s.push(value); + }else { + Integer top = s.pop(); + addToBottom(s, value); + s.push(top); + } + } + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s, Object o) { + if(s == null || s.isEmpty()){ + return; + } + Stack tempStack = new Stack(); + while(!s.isEmpty()){ + Object value = s.pop(); + if (!value.equals(o)) { + tempStack.push(value); + } + } + + while(!tempStack.isEmpty()){ + s.push(tempStack.pop()); + } + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param len + * @return + */ + public static Object[] getTop(Stack s, int len) { + if(s == null || s.isEmpty() || s.size() < len || len <= 0){ + return null; + } + + Object[] result = new Object[len]; + int i = 0; + while(!s.isEmpty()){ + Object value = s.pop(); + result[i++] = value; + if(i == len){ + break; + } + } + + 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<Character> stack = new Stack(); + + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if(c == '(' || c == '{' || c == '['){ + stack.push(c); + }else if(c == ')'){ + char topChar = stack.pop(); + if(topChar != '('){ + return false; + } + }else if(c == ']'){ + char topChar = stack.pop(); + if(topChar != '['){ + return false; + } + }else if(c == '}'){ + char topChar = stack.pop(); + if(topChar != '{'){ + return false; + } + } + } + return stack.size() == 0; + } + + +} diff --git a/group05/284422826/src/main/java/com/coding2017/basic/stack/StackUtilTest.java b/group05/284422826/src/main/java/com/coding2017/basic/stack/StackUtilTest.java new file mode 100644 index 0000000000..96179918cb --- /dev/null +++ b/group05/284422826/src/main/java/com/coding2017/basic/stack/StackUtilTest.java @@ -0,0 +1,78 @@ +package com.coding2017.basic.stack; + +import static org.junit.Assert.fail; + +import java.util.Stack; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +public class StackUtilTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testAddToBottom() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + + StackUtil.addToBottom(s, 0); + + Assert.assertEquals("[0, 1, 2, 3]", s.toString()); + + } + @Test + public void testReverse() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + Assert.assertEquals("[1, 2, 3, 4, 5]", s.toString()); + StackUtil.reverse(s); + Assert.assertEquals("[5, 4, 3, 2, 1]", s.toString()); + } + + @Test + public void testRemove() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + StackUtil.remove(s, 2); + Assert.assertEquals("[1, 3]", s.toString()); + } + + @Test + public void testGetTop() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + { + Object[] values = StackUtil.getTop(s, 3); + Assert.assertEquals(5, values[0]); + Assert.assertEquals(4, values[1]); + Assert.assertEquals(3, values[2]); + } + } + + @Test + public void testIsValidPairs() { + Assert.assertTrue(StackUtil.isValidPairs("([e{d}f])")); + Assert.assertFalse(StackUtil.isValidPairs("([b{x]y})")); + } + +} From 0d12fae46beaf9f97c1cf6eefe1c53ab6cd89284 Mon Sep 17 00:00:00 2001 From: Pan <gqp201210@gmail.com> Date: Sat, 15 Apr 2017 18:31:27 +0800 Subject: [PATCH 260/287] jvm third field and method, dataStructure not fish --- .../main/java/com/pan/jvm/attr/CodeAttr.java | 45 +++++- .../com/pan/jvm/attr/LineNumberTable.java | 15 +- .../com/pan/jvm/attr/LocalVariableTable.java | 20 ++- .../main/java/com/pan/jvm/field/Field.java | 28 +++- .../com/pan/jvm/loader/ClassFileParser.java | 30 ++++ .../main/java/com/pan/jvm/method/Method.java | 26 +++- .../java/com/pan/jvm/ClassFileLoaderTest.java | 144 +++++++++--------- 7 files changed, 219 insertions(+), 89 deletions(-) diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/CodeAttr.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/CodeAttr.java index 08bfa18f85..5b913a36c2 100644 --- a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/CodeAttr.java +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/CodeAttr.java @@ -40,9 +40,48 @@ public void setLocalVariableTable(LocalVariableTable t) { } public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ - - - return null; + int attrNameIndex = iter.nextU2ToInt(); + int attrLen = iter.nextU4ToInt(); + int maxStack = iter.nextU2ToInt(); + int maxLocals = iter.nextU2ToInt(); + int codeLen = iter.nextU4ToInt(); + + String code = iter.nextUxToHexString(codeLen); + + System.out.println("CODE-code: "+code); + + CodeAttr codeAttr = new CodeAttr(attrNameIndex, attrLen, maxStack, maxLocals, codeLen, code); + + int exceptionTableLen = iter.nextU2ToInt(); + + if (exceptionTableLen > 0){ + String exTable = iter.nextUxToHexString(exceptionTableLen); + System.out.println("Encountered exception table, just ignore!"); + } + + // 处理子属性 + int subAttrCount = iter.nextU2ToInt(); + for (int i = 1; i <= subAttrCount; i++) { + int suAttrIndex = iter.nextU2ToInt(); + String subAttrName = clzFile.getConstantPool().getUTF8String(suAttrIndex); + + iter.back(2);// 便于在子属性中获取 attrNameIndex + + if (AttributeInfo.LINE_NUM_TABLE.equalsIgnoreCase(subAttrName)){ + LineNumberTable lineNumberTable = LineNumberTable.parse(iter); + codeAttr.setLineNumberTable(lineNumberTable); + }else if (AttributeInfo.LOCAL_VAR_TABLE.equalsIgnoreCase(subAttrName)){ + LocalVariableTable localVariableTable = LocalVariableTable.parse(iter); + codeAttr.setLocalVariableTable(localVariableTable); + }else if (AttributeInfo.STACK_MAP_TABLE.equalsIgnoreCase(subAttrName)){ + StackMapTable stackMapTable = StackMapTable.parse(iter); + codeAttr.setStackMapTable(stackMapTable); + }else { + throw new RuntimeException("Need code to process :" + subAttrName); + } + + } + return codeAttr; } private void setStackMapTable(StackMapTable t) { this.stackMapTable = t; diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/LineNumberTable.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/LineNumberTable.java index 31d2ab3d7e..563e8b19d5 100644 --- a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/LineNumberTable.java +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/LineNumberTable.java @@ -33,8 +33,19 @@ public LineNumberTable(int attrNameIndex, int attrLen) { } public static LineNumberTable parse(ByteCodeIterator iter){ - - return null; + int attrNameIndex = iter.nextU2ToInt(); + int attrLen = iter.nextU4ToInt(); + LineNumberTable lineNumberTable = new LineNumberTable(attrNameIndex, attrLen); + + int attrItemSize = iter.nextU2ToInt(); + for (int i = 1; i <= attrItemSize; i++) { + LineNumberItem lineNumberItem = new LineNumberItem(); + lineNumberItem.setStartPC(iter.nextU2ToInt()); + lineNumberItem.setLineNum(iter.nextU2ToInt()); + + lineNumberTable.addLineNumberItem(lineNumberItem); + } + return lineNumberTable; } diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/LocalVariableTable.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/LocalVariableTable.java index 745f1e77d2..6291f9a605 100644 --- a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/LocalVariableTable.java +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/LocalVariableTable.java @@ -17,8 +17,24 @@ public LocalVariableTable(int attrNameIndex, int attrLen) { } public static LocalVariableTable parse(ByteCodeIterator iter){ - - return null; + + int attrNameIndex = iter.nextU2ToInt(); + int attrLen = iter.nextU4ToInt(); + + LocalVariableTable localVariableTable = new LocalVariableTable(attrNameIndex, attrLen); + + int attrItemSize = iter.nextU2ToInt(); + for (int i = 1; i <= attrItemSize; i++) { + LocalVariableItem localVariableItem = new LocalVariableItem(); + localVariableItem.setStartPC(iter.nextU2ToInt()); + localVariableItem.setLength(iter.nextU2ToInt()); + localVariableItem.setNameIndex(iter.nextU2ToInt()); + localVariableItem.setDescIndex(iter.nextU2ToInt()); + localVariableItem.setIndex(iter.nextU2ToInt()); + localVariableTable.addLocalVariableItem(localVariableItem); + } + + return localVariableTable; } private void addLocalVariableItem(LocalVariableItem item) { this.items.add(item); diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/field/Field.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/field/Field.java index 3fc8da4cdf..e427618564 100644 --- a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/field/Field.java +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/field/Field.java @@ -1,7 +1,9 @@ package com.pan.jvm.field; +import com.pan.jvm.constant.ConstantInfo; import com.pan.jvm.constant.ConstantPool; +import com.pan.jvm.constant.UTF8Info; import com.pan.jvm.loader.ByteCodeIterator; public class Field { @@ -21,12 +23,26 @@ public Field( int accessFlag, int nameIndex, int descriptorIndex,ConstantPool po this.pool = pool; } - - - - public static Field parse(ConstantPool pool,ByteCodeIterator iter){ - - return null; + @Override + public String toString() { + String name = ((UTF8Info) pool.getConstantInfo(this.nameIndex)).getValue(); + String desc = ((UTF8Info) pool.getConstantInfo(this.descriptorIndex)).getValue(); + + return name + ":" + desc; + } + + public static Field parse(ConstantPool pool, ByteCodeIterator iter){ + + int accessFlags = iter.nextU2ToInt(); + int nameIndex = iter.nextU2ToInt(); + int descriptorIndex = iter.nextU2ToInt(); + int attrCount = iter.nextU2ToInt(); + System.out.println("Field Attributes Count: " + attrCount); + Field field = new Field(accessFlags, nameIndex, descriptorIndex, pool); + if (attrCount > 0){ + throw new RuntimeException("Attributes Count &gt 0"); + } + return field; } } diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileParser.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileParser.java index 7ab096b4f5..b2bddb85c2 100644 --- a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileParser.java +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileParser.java @@ -4,6 +4,8 @@ import com.pan.jvm.clz.ClassFile; import com.pan.jvm.clz.ClassIndex; import com.pan.jvm.constant.*; +import com.pan.jvm.field.Field; +import com.pan.jvm.method.Method; import java.io.UnsupportedEncodingException; @@ -30,10 +32,38 @@ public ClassFile parse(byte[] codes) { ClassIndex clzIndex = parseClassIndex(iterator); classFile.setClassIndex(clzIndex); + // interface parseInterfaces(iterator); + + // field + parseFields(classFile, iterator); + + // method + parseMethods(classFile, iterator); + return classFile; } + private void parseMethods(ClassFile classFile, ByteCodeIterator iterator) { + int methodsCount = iterator.nextU2ToInt(); + System.out.println("Methods Count: " + methodsCount); + + for (int i = 1; i <= methodsCount; i++) { + Method method = Method.parse(classFile, iterator); + classFile.addMethod(method); + } + } + + + private void parseFields(ClassFile clzFile, ByteCodeIterator iterator) { + int fieldsCount = iterator.nextU2ToInt(); + System.out.println("Field count:" + fieldsCount); + for (int i = 1; i <= fieldsCount; i++) {// 从第一个开始,因为不包含本身 + Field field = Field.parse(clzFile.getConstantPool(), iterator); + clzFile.addField(field); + } + } + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { AccessFlag accessFlag = new AccessFlag(iter.nextU2ToInt()); return accessFlag; diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/method/Method.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/method/Method.java index ec3561a566..0fbb0f0946 100644 --- a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/method/Method.java +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/method/Method.java @@ -1,6 +1,7 @@ package com.pan.jvm.method; +import com.pan.jvm.attr.AttributeInfo; import com.pan.jvm.attr.CodeAttr; import com.pan.jvm.clz.ClassFile; import com.pan.jvm.loader.ByteCodeIterator; @@ -43,11 +44,28 @@ public Method(ClassFile clzFile,int accessFlag, int nameIndex, int descriptorInd } - - - public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ - return null; + int accessFlags = iter.nextU2ToInt(); + int nameIndex = iter.nextU2ToInt(); + int descriptorIndex = iter.nextU2ToInt(); + int attrCount = iter.nextU2ToInt(); + + System.out.println("Method Attributes Count: " + attrCount); + Method method = new Method(clzFile, accessFlags, nameIndex, descriptorIndex); + if (attrCount > 0){ + for (int i = 1; i <= attrCount; i++) { + int attrNameIndex = iter.nextU2ToInt(); + String attrName = clzFile.getConstantPool().getUTF8String(attrNameIndex); + iter.back(2); // 回退两个,便于Code 中读取属性 + if (AttributeInfo.CODE.equalsIgnoreCase(attrName)){ + CodeAttr codeAttr = CodeAttr.parse(clzFile, iter); + method.setCodeAttr(codeAttr); + }else { + throw new RuntimeException("Current Has CODE. Not Support Other"); + } + } + } + return method; } } diff --git a/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/ClassFileLoaderTest.java b/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/ClassFileLoaderTest.java index 2aed2e5e44..b0a61b242a 100644 --- a/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/ClassFileLoaderTest.java +++ b/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/ClassFileLoaderTest.java @@ -181,78 +181,78 @@ public void testClassIndex(){ Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); } -// -// /** -// * 下面是第三次JVM课应实现的测试用例 -// */ -// @Test -// public void testReadFields(){ -// -// List<Field> fields = clzFile.getFields(); -// Assert.assertEquals(2, fields.size()); -// { -// Field f = fields.get(0); -// Assert.assertEquals("name:Ljava/lang/String;", f.toString()); -// } -// { -// Field f = fields.get(1); -// Assert.assertEquals("age:I", f.toString()); -// } -// } -// @Test -// public void testMethods(){ -// -// List<Method> methods = clzFile.getMethods(); -// ConstantPool pool = clzFile.getConstantPool(); -// -// { -// Method m = methods.get(0); -// assertMethodEquals(pool,m, -// "<init>", -// "(Ljava/lang/String;I)V", -// "2ab7000c2a2bb5000f2a1cb50011b1"); -// -// } -// { -// Method m = methods.get(1); -// assertMethodEquals(pool,m, -// "setName", -// "(Ljava/lang/String;)V", -// "2a2bb5000fb1"); -// -// } -// { -// Method m = methods.get(2); -// assertMethodEquals(pool,m, -// "setAge", -// "(I)V", -// "2a1bb50011b1"); -// } -// { -// Method m = methods.get(3); -// assertMethodEquals(pool,m, -// "sayHello", -// "()V", -// "b2001c1222b60024b1"); -// -// } -// { -// Method m = methods.get(4); -// assertMethodEquals(pool,m, -// "main", -// "([Ljava/lang/String;)V", -// "bb000159122b101db7002d4c2bb6002fb1"); -// } -// } -// -// private void assertMethodEquals(ConstantPool pool,Method m , String expectedName, String expectedDesc,String expectedCode){ -// String methodName = pool.getUTF8String(m.getNameIndex()); -// String methodDesc = pool.getUTF8String(m.getDescriptorIndex()); -// String code = m.getCodeAttr().getCode(); -// Assert.assertEquals(expectedName, methodName); -// Assert.assertEquals(expectedDesc, methodDesc); -// Assert.assertEquals(expectedCode, code); -// } + + /** + * 下面是第三次JVM课应实现的测试用例 + */ + @Test + public void testReadFields(){ + + List<Field> fields = clzFile.getFields(); + Assert.assertEquals(2, fields.size()); + { + Field f = fields.get(0); + Assert.assertEquals("name:Ljava/lang/String;", f.toString()); + } + { + Field f = fields.get(1); + Assert.assertEquals("age:I", f.toString()); + } + } + @Test + public void testMethods(){ + + List<Method> methods = clzFile.getMethods(); + ConstantPool pool = clzFile.getConstantPool(); + + { + Method m = methods.get(0); + assertMethodEquals(pool,m, + "<init>", + "(Ljava/lang/String;I)V", + "2ab700012a2bb500022a1cb50003b1"); + + } + { + Method m = methods.get(1); + assertMethodEquals(pool,m, + "setName", + "(Ljava/lang/String;)V", + "2a2bb50002b1"); + + } + { + Method m = methods.get(2); + assertMethodEquals(pool,m, + "setAge", + "(I)V", + "2a1bb50003b1"); + } + { + Method m = methods.get(3); + assertMethodEquals(pool,m, + "sayHello", + "()V", + "b200041205b60006b1"); + + } + { + Method m = methods.get(4); + assertMethodEquals(pool,m, + "main", + "([Ljava/lang/String;)V", + "bb0007591208101db700094c2bb6000ab1"); + } + } + + private void assertMethodEquals(ConstantPool pool,Method m , String expectedName, String expectedDesc,String expectedCode){ + String methodName = pool.getUTF8String(m.getNameIndex()); + String methodDesc = pool.getUTF8String(m.getDescriptorIndex()); + String code = m.getCodeAttr().getCode(); + Assert.assertEquals(expectedName, methodName); + Assert.assertEquals(expectedDesc, methodDesc); + Assert.assertEquals(expectedCode, code); + } } From 9560f3b746f1513cf2f067e700700a2563e73d72 Mon Sep 17 00:00:00 2001 From: lzb <lzbferrari@gmail.com> Date: Sat, 15 Apr 2017 18:57:21 +0800 Subject: [PATCH 261/287] =?UTF-8?q?jvm=E7=AC=AC=E4=BA=8C=E5=91=A8=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/me/lzb/common/utils/ByteUtils.java | 26 ++ .../java/me/lzb/common}/utils/FileUtils.java | 12 +- .../me/lzb/common}/utils/StringUtils.java | 3 +- .../learning2017/learning-basic/pom.xml | 5 + .../java/me/lzb/datastructure/StackUtil.java | 56 ++++ .../me/lzb/datastructure/StackUtilTest.java | 77 +++++ .../main/java/me/lzb/jvm/clz/AccessFlag.java | 29 ++ .../main/java/me/lzb/jvm/clz/ClassFile.java | 96 +++++++ .../main/java/me/lzb/jvm/clz/ClassIndex.java | 25 ++ .../java/me/lzb/jvm/constant/ClassInfo.java | 33 +++ .../me/lzb/jvm/constant/ConstantInfo.java | 28 ++ .../me/lzb/jvm/constant/ConstantPool.java | 28 ++ .../me/lzb/jvm/constant/FieldRefInfo.java | 35 +++ .../java/me/lzb/jvm/constant/JvmConstant.java | 23 ++ .../me/lzb/jvm/constant/MethodRefInfo.java | 36 +++ .../me/lzb/jvm/constant/NameAndTypeInfo.java | 36 +++ .../me/lzb/jvm/constant/NullConstantInfo.java | 12 + .../java/me/lzb/jvm/constant/StringInfo.java | 26 ++ .../java/me/lzb/jvm/constant/UTF8Info.java | 38 +++ .../jvm/exception/NotClassFileException.java | 14 + .../me/lzb/jvm/loader/ClassFileLoader.java | 62 ++++ .../me/lzb/jvm/loader/ClassFileParser.java | 177 ++++++++++++ .../java/me/lzb/loader/ClassFileLoader.java | 57 ---- .../java/me/lzb/jvm/ClassFileloaderTest.java | 268 ++++++++++++++++++ .../me/lzb/{loader => jvm}/EmployeeV1.java | 2 +- .../me/lzb/loader/ClassFileloaderTest.java | 103 ------- group24/1148285693/learning2017/pom.xml | 8 +- 27 files changed, 1150 insertions(+), 165 deletions(-) create mode 100644 group24/1148285693/learning2017/common/src/main/java/me/lzb/common/utils/ByteUtils.java rename group24/1148285693/learning2017/{mini-jvm/src/main/java/me/lzb => common/src/main/java/me/lzb/common}/utils/FileUtils.java (83%) rename group24/1148285693/learning2017/{mini-jvm/src/main/java/me/lzb => common/src/main/java/me/lzb/common}/utils/StringUtils.java (79%) create mode 100644 group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/StackUtil.java create mode 100644 group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/datastructure/StackUtilTest.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/clz/AccessFlag.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/clz/ClassFile.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/clz/ClassIndex.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/ClassInfo.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/ConstantInfo.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/ConstantPool.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/FieldRefInfo.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/JvmConstant.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/MethodRefInfo.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/NameAndTypeInfo.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/NullConstantInfo.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/StringInfo.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/UTF8Info.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/exception/NotClassFileException.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/loader/ClassFileLoader.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/loader/ClassFileParser.java delete mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/loader/ClassFileLoader.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/test/java/me/lzb/jvm/ClassFileloaderTest.java rename group24/1148285693/learning2017/mini-jvm/src/test/java/me/lzb/{loader => jvm}/EmployeeV1.java (95%) delete mode 100644 group24/1148285693/learning2017/mini-jvm/src/test/java/me/lzb/loader/ClassFileloaderTest.java diff --git a/group24/1148285693/learning2017/common/src/main/java/me/lzb/common/utils/ByteUtils.java b/group24/1148285693/learning2017/common/src/main/java/me/lzb/common/utils/ByteUtils.java new file mode 100644 index 0000000000..f6586ce761 --- /dev/null +++ b/group24/1148285693/learning2017/common/src/main/java/me/lzb/common/utils/ByteUtils.java @@ -0,0 +1,26 @@ +package me.lzb.common.utils; + +/** + * Created by LZB on 2017/4/14. + */ +public class ByteUtils { + + 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(); + } + + public static int byteToInt(byte[] codes){ + String s1 = byteToHexString(codes); + return Integer.valueOf(s1, 16).intValue(); + } +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/utils/FileUtils.java b/group24/1148285693/learning2017/common/src/main/java/me/lzb/common/utils/FileUtils.java similarity index 83% rename from group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/utils/FileUtils.java rename to group24/1148285693/learning2017/common/src/main/java/me/lzb/common/utils/FileUtils.java index b0947d4326..6d622acfbb 100644 --- a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/utils/FileUtils.java +++ b/group24/1148285693/learning2017/common/src/main/java/me/lzb/common/utils/FileUtils.java @@ -1,4 +1,4 @@ -package me.lzb.utils; +package me.lzb.common.utils; import java.io.*; @@ -15,10 +15,15 @@ public class FileUtils { * @return true false */ public static boolean isFileExist(String path, String name) { - File file = new File(path + "\\" + name); + return isFileExist(path + File.separator + name); + } + + public static boolean isFileExist(String f) { + File file = new File(f); return file.exists(); } + /** * 读取文件为二进制数组 * @param clzFileName 文件路径 @@ -26,6 +31,9 @@ public static boolean isFileExist(String path, String name) { * @throws IOException */ public static byte[] readByteCodes(String clzFileName) throws IOException { + if(!isFileExist(clzFileName)){ + return null; + } File f = new File(clzFileName); diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/utils/StringUtils.java b/group24/1148285693/learning2017/common/src/main/java/me/lzb/common/utils/StringUtils.java similarity index 79% rename from group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/utils/StringUtils.java rename to group24/1148285693/learning2017/common/src/main/java/me/lzb/common/utils/StringUtils.java index b4ec543d49..66f70d49f7 100644 --- a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/utils/StringUtils.java +++ b/group24/1148285693/learning2017/common/src/main/java/me/lzb/common/utils/StringUtils.java @@ -1,7 +1,8 @@ -package me.lzb.utils; +package me.lzb.common.utils; /** * Created by LZB on 2017/4/4. */ public class StringUtils extends org.apache.commons.lang3.StringUtils { + } diff --git a/group24/1148285693/learning2017/learning-basic/pom.xml b/group24/1148285693/learning2017/learning-basic/pom.xml index 7cb5cfb3f0..2e3728be0f 100644 --- a/group24/1148285693/learning2017/learning-basic/pom.xml +++ b/group24/1148285693/learning2017/learning-basic/pom.xml @@ -18,5 +18,10 @@ <dependencies> + <dependency> + <groupId>me.lzb</groupId> + <artifactId>common</artifactId> + <version>1.0</version> + </dependency> </dependencies> </project> diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/StackUtil.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/StackUtil.java new file mode 100644 index 0000000000..c854ec7052 --- /dev/null +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/StackUtil.java @@ -0,0 +1,56 @@ +package me.lzb.datastructure; +import java.util.Stack; + +public class StackUtil { + + public static void bad_reverse(Stack<Integer> s) { + + + } + + /** + * 假设栈中的元素是Integer, 从栈顶到栈底是 : 5,4,3,2,1 调用该方法后, 元素次序变为: 1,2,3,4,5 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + */ + public static void reverse(Stack<Integer> s) { + + + + } + public static void addToBottom(Stack<Integer> s, Integer value){ + + + } + /** + * 删除栈中的某个元素 注意:只能使用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; + } + + +} diff --git a/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/datastructure/StackUtilTest.java b/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/datastructure/StackUtilTest.java new file mode 100644 index 0000000000..929d365f69 --- /dev/null +++ b/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/datastructure/StackUtilTest.java @@ -0,0 +1,77 @@ +package me.lzb.datastructure; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.Stack; + +public class StackUtilTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testAddToBottom() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + + StackUtil.addToBottom(s, 0); + + Assert.assertEquals("[0, 1, 2, 3]", s.toString()); + + } + @Test + public void testReverse() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + Assert.assertEquals("[1, 2, 3, 4, 5]", s.toString()); + StackUtil.reverse(s); + Assert.assertEquals("[5, 4, 3, 2, 1]", s.toString()); + } + + @Test + public void testRemove() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + StackUtil.remove(s, 2); + Assert.assertEquals("[1, 3]", s.toString()); + } + + @Test + public void testGetTop() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + { + Object[] values = StackUtil.getTop(s, 3); + Assert.assertEquals(5, values[0]); + Assert.assertEquals(4, values[1]); + Assert.assertEquals(3, values[2]); + } + } + + @Test + public void testIsValidPairs() { + Assert.assertTrue(StackUtil.isValidPairs("([e{d}f])")); + Assert.assertFalse(StackUtil.isValidPairs("([b{x]y})")); + } + +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/clz/AccessFlag.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..224714a010 --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/clz/AccessFlag.java @@ -0,0 +1,29 @@ +package me.lzb.jvm.clz; + +/** + * Created by LZB on 2017/4/14. + */ +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/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/clz/ClassFile.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..380bf7c016 --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/clz/ClassFile.java @@ -0,0 +1,96 @@ +package me.lzb.jvm.clz; + +import me.lzb.jvm.constant.ConstantPool; + +/** + * Created by LZB on 2017/4/14. + */ +public class ClassFile { + + private String magicNumber; + + private int minorVersion; + + private int majorVersion; + + private AccessFlag accessFlag; + + private ClassIndex clzIndex; + + private int constantPoolCount; + + private ConstantPool constantPool; + + + public String getMagicNumber() { + return magicNumber; + } + + public void setMagicNumber(String magicNumber) { + this.magicNumber = magicNumber; + } + + 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 AccessFlag getAccessFlag() { + return accessFlag; + } + + public void setAccessFlag(AccessFlag accessFlag) { + this.accessFlag = accessFlag; + } + + public ConstantPool getConstantPool() { + return constantPool; + } + + public void setConstantPool(ConstantPool constantPool) { + this.constantPool = constantPool; + } + + + public int getConstantPoolCount() { + return constantPoolCount; + } + + public void setConstantPoolCount(int constantPoolCount) { + this.constantPoolCount = constantPoolCount; + } + + + public ClassIndex getClzIndex() { + return clzIndex; + } + + public void setClzIndex(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()); + + } + +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/clz/ClassIndex.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..8916290057 --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/clz/ClassIndex.java @@ -0,0 +1,25 @@ +package me.lzb.jvm.clz; + +/** + * Created by LZB on 2017/4/14. + */ +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/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/ClassInfo.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..1cfdc94ed7 --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/ClassInfo.java @@ -0,0 +1,33 @@ +package me.lzb.jvm.constant; + +/** + * Created by LZB on 2017/4/14. + */ +public class ClassInfo extends ConstantInfo{ + private int type = JvmConstant.Class_info; + private int utf8Index; + + public ClassInfo(ConstantPool pool) { + super(pool); + } + + @Override + public int getType() { + return type; + } + + public int getUtf8Index() { + return utf8Index; + } + + public void setUtf8Index(int utf8Index) { + this.utf8Index = utf8Index; + } + + + public String getClassName() { + int index = getUtf8Index(); + UTF8Info utf8Info = (UTF8Info)constantPool.getConstantInfo(index); + return utf8Info.getValue(); + } +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/ConstantInfo.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..df65a833c2 --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/ConstantInfo.java @@ -0,0 +1,28 @@ +package me.lzb.jvm.constant; + +/** + * Created by LZB on 2017/4/14. + */ +public abstract class ConstantInfo { + + protected ConstantPool constantPool; + + + public ConstantInfo(){ + + } + + public ConstantInfo(ConstantPool pool) { + this.constantPool = pool; + } + + public ConstantPool getConstantPool() { + return constantPool; + } + public ConstantInfo getConstantInfo(int index){ + return this.constantPool.getConstantInfo(index); + } + + + public abstract int getType(); +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/ConstantPool.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..4e787eed62 --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/ConstantPool.java @@ -0,0 +1,28 @@ +package me.lzb.jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by LZB on 2017/4/14. + */ +public class ConstantPool { + + private List<ConstantInfo> constantInfoList = new ArrayList<>(); + + + + public void addConstantInfo(ConstantInfo constantInfo){ + constantInfoList.add(constantInfo); + } + + + public int getSize(){ + return constantInfoList.size() > 1 ? constantInfoList.size() - 1 : 0; + } + + public ConstantInfo getConstantInfo(int index){ + return constantInfoList.get(index); + } + +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/FieldRefInfo.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..907db2c4f8 --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/FieldRefInfo.java @@ -0,0 +1,35 @@ +package me.lzb.jvm.constant; + +/** + * Created by LZB on 2017/4/15. + */ +public class FieldRefInfo extends ConstantInfo{ + private int type = JvmConstant.Fieldref_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; + } +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/JvmConstant.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/JvmConstant.java new file mode 100644 index 0000000000..1707dc72c0 --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/JvmConstant.java @@ -0,0 +1,23 @@ +package me.lzb.jvm.constant; + +/** + * Jvm常量 + * Created by LZB on 2017/4/14. + */ +public class JvmConstant { + + public static final String MAGIC_NUMBER = "cafebabe"; + + public static final int Class_info = 7; + + public static final int Fieldref_info = 9; + + public static final int Methodref_info = 10; + + public static final int String_info = 8; + + public static final int NameAndType_info = 12; + + public static final int Utf8_info = 1; + +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/MethodRefInfo.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..b7ae059e1f --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/MethodRefInfo.java @@ -0,0 +1,36 @@ +package me.lzb.jvm.constant; + +/** + * Created by LZB on 2017/4/15. + */ +public class MethodRefInfo extends ConstantInfo { + private int type = JvmConstant.Methodref_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; + } +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/NameAndTypeInfo.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..3ffdfd8927 --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,36 @@ +package me.lzb.jvm.constant; + +/** + * Created by LZB on 2017/4/15. + */ +public class NameAndTypeInfo extends ConstantInfo { + private int type = JvmConstant.NameAndType_info; + + private int index1; + private int index2; + + public NameAndTypeInfo(ConstantPool pool) { + super(pool); + } + + @Override + public int getType() { + return type; + } + + 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; + } +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/NullConstantInfo.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..7f9debba3b --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/NullConstantInfo.java @@ -0,0 +1,12 @@ +package me.lzb.jvm.constant; + +/** + * Created by LZB on 2017/4/14. + */ +public class NullConstantInfo extends ConstantInfo{ + + @Override + public int getType() { + return -1; + } +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/StringInfo.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..00b80d64ef --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/StringInfo.java @@ -0,0 +1,26 @@ +package me.lzb.jvm.constant; + +/** + * Created by LZB on 2017/4/15. + */ +public class StringInfo extends ConstantInfo { + private int type = JvmConstant.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; + } +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/UTF8Info.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..e6389fb397 --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/UTF8Info.java @@ -0,0 +1,38 @@ +package me.lzb.jvm.constant; + +/** + * Created by LZB on 2017/4/15. + */ +public class UTF8Info extends ConstantInfo { + private int type = JvmConstant.Class_info; + + private String value; + + private int length; + + public UTF8Info(ConstantPool pool) { + super(pool); + } + + + @Override + public int getType() { + return type; + } + + 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; + } +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/exception/NotClassFileException.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/exception/NotClassFileException.java new file mode 100644 index 0000000000..d3952ead6d --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/exception/NotClassFileException.java @@ -0,0 +1,14 @@ +package me.lzb.jvm.exception; + +/** + * Created by LZB on 2017/4/14. + */ +public class NotClassFileException extends Exception{ + public NotClassFileException(String message, Exception cause) { + super(message, cause); + } + + public NotClassFileException(String message) { + super(message); + } +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/loader/ClassFileLoader.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..0dab6a3407 --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/loader/ClassFileLoader.java @@ -0,0 +1,62 @@ +package me.lzb.jvm.loader; + + +import me.lzb.common.utils.FileUtils; +import me.lzb.jvm.clz.ClassFile; +import me.lzb.jvm.exception.NotClassFileException; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + + + +public class ClassFileLoader { + + private List<String> clzPaths = new ArrayList<>(); + + public byte[] readBinaryCode(String className) throws IOException { +// String fileName = className.replaceAll(".*\\.", "") + ".class"; +// String pkg = className.replaceAll("\\.[^\\.]+$", ""); +// String packagePath = pkg.replaceAll("\\.", "\\\\"); + + className = className.replace('.', File.separatorChar) +".class"; + for (String s : clzPaths) { + byte[] data = FileUtils.readByteCodes(s + className); + if(data != null){ + return data; + } + } + + throw new IOException(className + "is not exist"); + } + + + public void addClassPath(String path) { + clzPaths.add(path); + } + + + public String getClassPath(){ + StringBuilder buffer = new StringBuilder(); + for (Iterator<String> iterator = clzPaths.iterator(); iterator.hasNext();) { + buffer.append(iterator.next() + (iterator.hasNext() ? ";" : "")); + } + return buffer.toString(); + } + + + public ClassFile loadClass(String className) throws IOException, NotClassFileException { + byte[] codes = this.readBinaryCode(className); + ClassFileParser parser = new ClassFileParser(codes); + return parser.parse(); + } + + + + + + +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/loader/ClassFileParser.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..2b99969f75 --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/loader/ClassFileParser.java @@ -0,0 +1,177 @@ +package me.lzb.jvm.loader; + +import me.lzb.common.utils.ByteUtils; +import me.lzb.common.utils.StringUtils; +import me.lzb.jvm.clz.AccessFlag; +import me.lzb.jvm.clz.ClassFile; +import me.lzb.jvm.clz.ClassIndex; +import me.lzb.jvm.constant.*; +import me.lzb.jvm.exception.NotClassFileException; + +import java.io.UnsupportedEncodingException; + +/** + * 处理字class文件字节流 + * Created by LZB on 2017/4/14. + */ +public class ClassFileParser { + + + private final byte[] data; + + private int index; + + public ClassFileParser(byte[] data) { + this.data = data; + } + + + + public ClassFile parse() throws NotClassFileException{ + ClassFile classFile = new ClassFile(); + magicNumber(classFile); + + if(!StringUtils.equals(classFile.getMagicNumber(), JvmConstant.MAGIC_NUMBER)){ + throw new NotClassFileException("It is not a java class file."); + } + + version(classFile); + + constantPool(classFile); + + accessFlag(classFile); + + classIndex(classFile); + + return classFile; + } + + + + private byte[] nextBytes(int nextLength){ + byte[] target = new byte[nextLength]; + System.arraycopy(data, index, target, 0, nextLength); + index = index + nextLength; + return target; + } + + private int nextBytesToInt(int nextLength){ + return ByteUtils.byteToInt(nextBytes(nextLength)); + } + + private String nextBytesToString(int nextLength){ + return ByteUtils.byteToHexString(nextBytes(nextLength)); + } + + + private void magicNumber(ClassFile classFile){ + this.index = 0; + classFile.setMagicNumber(nextBytesToString(4)); + } + + private void version(ClassFile classFile){ + classFile.setMinorVersion(nextBytesToInt(2)); + classFile.setMajorVersion(nextBytesToInt(2)); + } + + private void constantPool(ClassFile classFile){ + int count = nextBytesToInt(2); + classFile.setConstantPoolCount(count); + + ConstantPool pool = new ConstantPool(); + pool.addConstantInfo(new NullConstantInfo()); + + for (int i = 1; i < count; i++) { + + int tag = nextBytesToInt(1); + + if(tag == JvmConstant.Class_info){ + ClassInfo classInfo = new ClassInfo(pool); + classInfo.setUtf8Index(nextBytesToInt(2)); + + pool.addConstantInfo(classInfo); + continue; + } + + if(tag == JvmConstant.Fieldref_info){ + FieldRefInfo fieldRefInfo = new FieldRefInfo(pool); + fieldRefInfo.setClassInfoIndex(nextBytesToInt(2)); + fieldRefInfo.setNameAndTypeIndex(nextBytesToInt(2)); + + pool.addConstantInfo(fieldRefInfo); + continue; + } + + if(tag == JvmConstant.Methodref_info){ + MethodRefInfo methodRefInfo = new MethodRefInfo(pool); + methodRefInfo.setClassInfoIndex(nextBytesToInt(2)); + methodRefInfo.setNameAndTypeIndex(nextBytesToInt(2)); + + pool.addConstantInfo(methodRefInfo); + continue; + } + + if(tag == JvmConstant.NameAndType_info){ + NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(pool); + nameAndTypeInfo.setIndex1(nextBytesToInt(2)); + nameAndTypeInfo.setIndex2(nextBytesToInt(2)); + + pool.addConstantInfo(nameAndTypeInfo); + continue; + } + + if(tag == JvmConstant.String_info){ + StringInfo stringInfo = new StringInfo(pool); + stringInfo.setIndex(nextBytesToInt(2)); + + pool.addConstantInfo(stringInfo); + continue; + } + + if(tag == JvmConstant.Utf8_info){ + UTF8Info utf8Info = new UTF8Info(pool); + int len = nextBytesToInt(2); + byte[] data = nextBytes(len); + String value = null; + try { + value = new String(data, "UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + utf8Info.setLength(len); + utf8Info.setValue(value); + + pool.addConstantInfo(utf8Info); + continue; + } + + + throw new RuntimeException("the constant pool tag " + tag + " has not been implemented yet." + i); + } + + + + classFile.setConstantPool(pool); + } + + + + private void accessFlag(ClassFile classFile){ + AccessFlag flag = new AccessFlag(nextBytesToInt(2)); + classFile.setAccessFlag(flag); + } + + + private void classIndex(ClassFile classFile){ + ClassIndex clzIndex = new ClassIndex(); + + int thisClassIndex = nextBytesToInt(2); + int superClassIndex = nextBytesToInt(2); + clzIndex.setThisClassIndex(thisClassIndex); + clzIndex.setSuperClassIndex(superClassIndex); + + classFile.setClzIndex(clzIndex); + } + + +} 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 deleted file mode 100644 index 86f017cebf..0000000000 --- a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/loader/ClassFileLoader.java +++ /dev/null @@ -1,57 +0,0 @@ -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<String> 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<String> iterator = clzPaths.iterator(); iterator.hasNext();) { - buffer.append(iterator.next() + (iterator.hasNext() ? ";" : "")); - } - return buffer.toString(); - } - - - - -} diff --git a/group24/1148285693/learning2017/mini-jvm/src/test/java/me/lzb/jvm/ClassFileloaderTest.java b/group24/1148285693/learning2017/mini-jvm/src/test/java/me/lzb/jvm/ClassFileloaderTest.java new file mode 100644 index 0000000000..570462ef74 --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/test/java/me/lzb/jvm/ClassFileloaderTest.java @@ -0,0 +1,268 @@ +package me.lzb.jvm; + +import me.lzb.common.utils.ByteUtils; +import me.lzb.jvm.clz.ClassFile; +import me.lzb.jvm.clz.ClassIndex; +import me.lzb.jvm.constant.*; +import me.lzb.jvm.exception.NotClassFileException; +import me.lzb.jvm.loader.ClassFileLoader; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; + + +public class ClassFileloaderTest { + + + static String path1 = EmployeeV1.class.getResource("/").getPath(); +// static String path1 = "D:\\code\\learning\\coding2017\\group24\\1148285693\\learning2017\\mini-jvm\\target\\test-classes\\"; + static String path2 = "C:\\temp"; + + static String className = "me.lzb.jvm.EmployeeV1"; + + private static final String FULL_QUALIFIED_CLASS_NAME = "me/lzb/jvm/EmployeeV1"; +// private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + + + @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); + + + byte[] byteCodes = loader.readBinaryCode(className); + + Assert.assertEquals(1030, byteCodes.length); + + } + + + @Test + public void testMagicNumber() throws Exception { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + byte[] byteCodes = loader.readBinaryCode(className); + byte[] codes = new byte[]{byteCodes[0], byteCodes[1], byteCodes[2], byteCodes[3]}; + + String acctualValue = ByteUtils.byteToHexString(codes); + + Assert.assertEquals("cafebabe", acctualValue); + } + + + static ClassFile clzFile = null; + static { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + + try { + clzFile = loader.loadClass(className); + } catch (IOException e) { + e.printStackTrace(); + } catch (NotClassFileException e){ + e.printStackTrace(); + } + clzFile.print(); + } + + + + + @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("<init>", 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(10); + Assert.assertEquals(7, methodRef.getClassInfoIndex()); + Assert.assertEquals(47, 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()); + } + + /** + * 下面是第三次JVM课应实现的测试用例 + */ + @Test + public void testReadFields(){ + + List<Field> fields = clzFile.getFields(); + Assert.assertEquals(2, fields.size()); + { + Field f = fields.get(0); + Assert.assertEquals("name:Ljava/lang/String;", f.toString()); + } + { + Field f = fields.get(1); + Assert.assertEquals("age:I", f.toString()); + } + } + @Test + public void testMethods(){ + + List<Method> methods = clzFile.getMethods(); + ConstantPool pool = clzFile.getConstantPool(); + + { + Method m = methods.get(0); + assertMethodEquals(pool,m, + "<init>", + "(Ljava/lang/String;I)V", + "2ab7000c2a2bb5000f2a1cb50011b1"); + + } + { + Method m = methods.get(1); + assertMethodEquals(pool,m, + "setName", + "(Ljava/lang/String;)V", + "2a2bb5000fb1"); + + } + { + Method m = methods.get(2); + assertMethodEquals(pool,m, + "setAge", + "(I)V", + "2a1bb50011b1"); + } + { + Method m = methods.get(3); + assertMethodEquals(pool,m, + "sayHello", + "()V", + "b2001c1222b60024b1"); + + } + { + Method m = methods.get(4); + assertMethodEquals(pool,m, + "main", + "([Ljava/lang/String;)V", + "bb000159122b101db7002d4c2bb6002fb1"); + } + } + + private void assertMethodEquals(ConstantPool pool,Method m , String expectedName, String expectedDesc,String expectedCode){ + String methodName = pool.getUTF8String(m.getNameIndex()); + String methodDesc = pool.getUTF8String(m.getDescriptorIndex()); + String code = m.getCodeAttr().getCode(); + Assert.assertEquals(expectedName, methodName); + Assert.assertEquals(expectedDesc, methodDesc); + Assert.assertEquals(expectedCode, code); + } + +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/test/java/me/lzb/loader/EmployeeV1.java b/group24/1148285693/learning2017/mini-jvm/src/test/java/me/lzb/jvm/EmployeeV1.java similarity index 95% rename from group24/1148285693/learning2017/mini-jvm/src/test/java/me/lzb/loader/EmployeeV1.java rename to group24/1148285693/learning2017/mini-jvm/src/test/java/me/lzb/jvm/EmployeeV1.java index ab035ac403..3fa9b0fc85 100644 --- a/group24/1148285693/learning2017/mini-jvm/src/test/java/me/lzb/loader/EmployeeV1.java +++ b/group24/1148285693/learning2017/mini-jvm/src/test/java/me/lzb/jvm/EmployeeV1.java @@ -1,4 +1,4 @@ -package me.lzb.loader; +package me.lzb.jvm; public class EmployeeV1 { 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 deleted file mode 100644 index b544e7ddc4..0000000000 --- a/group24/1148285693/learning2017/mini-jvm/src/test/java/me/lzb/loader/ClassFileloaderTest.java +++ /dev/null @@ -1,103 +0,0 @@ -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<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/group24/1148285693/learning2017/pom.xml b/group24/1148285693/learning2017/pom.xml index 9b8d948ff9..8dc41781ba 100644 --- a/group24/1148285693/learning2017/pom.xml +++ b/group24/1148285693/learning2017/pom.xml @@ -22,9 +22,10 @@ </developers> <modules> + <module>common</module> <module>learning-basic</module> <module>mini-jvm</module> - <!--<module>example</module>--> + <module>other</module> </modules> <properties> @@ -103,6 +104,11 @@ <artifactId>commons-codec</artifactId> <version>1.10</version> </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-collections4</artifactId> + <version>4.1</version> + </dependency> <!--http client--> <dependency> From d6f9c2439115520edef09bb8d18431838bfc4d17 Mon Sep 17 00:00:00 2001 From: DonaldY <448641125@qq.com> Date: Sat, 15 Apr 2017 21:21:28 +0800 Subject: [PATCH 262/287] sixth homework finished --- .../com/donaldy/jvm/attr/AttributeInfo.java | 19 ++++ .../src/com/donaldy/jvm/attr/CodeAttr.java | 56 ++++++++++++ .../com/donaldy/jvm/attr/LineNumberTable.java | 57 ++++++++++++ .../donaldy/jvm/attr/LocalVariableItem.java | 39 ++++++++ .../donaldy/jvm/attr/LocalVariableTable.java | 45 ++++++++++ .../com/donaldy/jvm/attr/StackMapTable.java | 30 +++++++ .../src/com/donaldy/jvm/clz/ClassFile.java | 55 ++++++++---- .../src/com/donaldy/jvm/field/Field.java | 46 ++++++++++ .../donaldy/jvm/loader/ByteCodeIterator.java | 57 +++++++++++- .../donaldy/jvm/loader/ClassFileParser.java | 39 ++++++++ .../src/com/donaldy/jvm/method/Method.java | 89 +++++++++++++++++++ .../donaldy/jvm/test/ClassFileloaderTest.java | 86 +++++++++++++++++- 12 files changed, 595 insertions(+), 23 deletions(-) create mode 100644 group24/448641125/src/com/donaldy/jvm/attr/AttributeInfo.java create mode 100644 group24/448641125/src/com/donaldy/jvm/attr/CodeAttr.java create mode 100644 group24/448641125/src/com/donaldy/jvm/attr/LineNumberTable.java create mode 100644 group24/448641125/src/com/donaldy/jvm/attr/LocalVariableItem.java create mode 100644 group24/448641125/src/com/donaldy/jvm/attr/LocalVariableTable.java create mode 100644 group24/448641125/src/com/donaldy/jvm/attr/StackMapTable.java create mode 100644 group24/448641125/src/com/donaldy/jvm/field/Field.java create mode 100644 group24/448641125/src/com/donaldy/jvm/method/Method.java diff --git a/group24/448641125/src/com/donaldy/jvm/attr/AttributeInfo.java b/group24/448641125/src/com/donaldy/jvm/attr/AttributeInfo.java new file mode 100644 index 0000000000..db2cdc8f97 --- /dev/null +++ b/group24/448641125/src/com/donaldy/jvm/attr/AttributeInfo.java @@ -0,0 +1,19 @@ +package com.donaldy.jvm.attr; + +public abstract class AttributeInfo { + public static final String CODE = "Code"; + public static final String CONST_VALUE = "ConstantValue"; + public static final String EXCEPTIONS = "Exceptions"; + public static final String LINE_NUM_TABLE = "LineNumberTable"; + public static final String LOCAL_VAR_TABLE = "LocalVariableTable"; + public static final String STACK_MAP_TABLE = "StackMapTable"; + int attrNameIndex; + int attrLen ; + public AttributeInfo(int attrNameIndex, int attrLen) { + + this.attrNameIndex = attrNameIndex; + this.attrLen = attrLen; + } + + +} diff --git a/group24/448641125/src/com/donaldy/jvm/attr/CodeAttr.java b/group24/448641125/src/com/donaldy/jvm/attr/CodeAttr.java new file mode 100644 index 0000000000..6b699e6991 --- /dev/null +++ b/group24/448641125/src/com/donaldy/jvm/attr/CodeAttr.java @@ -0,0 +1,56 @@ +package com.donaldy.jvm.attr; + +import com.donaldy.jvm.clz.ClassFile; +import com.donaldy.jvm.constant.ConstantPool; +import com.donaldy.jvm.loader.ByteCodeIterator; + + +public class CodeAttr extends AttributeInfo { + private int maxStack ; + private int maxLocals ; + private int codeLen ; + private String code; + public String getCode() { + return code; + } + + //private ByteCodeCommand[] cmds ; + //public ByteCodeCommand[] getCmds() { + // return cmds; + //} + private LineNumberTable lineNumTable; + private LocalVariableTable localVarTable; + private StackMapTable stackMapTable; + + public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen,String code /*ByteCodeCommand[] cmds*/) { + super(attrNameIndex, attrLen); + this.maxStack = maxStack; + this.maxLocals = maxLocals; + this.codeLen = codeLen; + this.code = code; + //this.cmds = cmds; + } + + public void setLineNumberTable(LineNumberTable t) { + this.lineNumTable = t; + } + + public void setLocalVariableTable(LocalVariableTable t) { + this.localVarTable = t; + } + + public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ + + + return null; + } + private void setStackMapTable(StackMapTable t) { + this.stackMapTable = t; + + } + + + + + +} diff --git a/group24/448641125/src/com/donaldy/jvm/attr/LineNumberTable.java b/group24/448641125/src/com/donaldy/jvm/attr/LineNumberTable.java new file mode 100644 index 0000000000..9dc9ab1dc9 --- /dev/null +++ b/group24/448641125/src/com/donaldy/jvm/attr/LineNumberTable.java @@ -0,0 +1,57 @@ +package com.donaldy.jvm.attr; + +import java.util.ArrayList; +import java.util.List; + +import com.donaldy.jvm.loader.ByteCodeIterator; + +public class LineNumberTable extends AttributeInfo { + List<LineNumberItem> items = new ArrayList<LineNumberItem>(); + + private static class LineNumberItem{ + int startPC; + int lineNum; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLineNum() { + return lineNum; + } + public void setLineNum(int lineNum) { + this.lineNum = lineNum; + } + } + public void addLineNumberItem(LineNumberItem item){ + this.items.add(item); + } + public LineNumberTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + + } + + public static LineNumberTable parse(ByteCodeIterator iter){ + int attrNameIndex = iter.nextU2ToInt(); + int attributeLen = iter.nextU4ToInt(); + int lnTableLen = iter.nextU2ToInt(); + LineNumberTable lnTable = new LineNumberTable(attrNameIndex, attributeLen); + + System.out.println("LineNumberTable.lnTableLen : " + lnTableLen); + + for (int i = 0; i < lnTableLen; ++i) { + LineNumberItem lnItem = new LineNumberItem(); + + lnItem.setStartPC(iter.nextU2ToInt()); + lnItem.setLineNum(iter.nextU2ToInt()); + + lnTable.addLineNumberItem(lnItem); + } + + return lnTable; + } + + + +} diff --git a/group24/448641125/src/com/donaldy/jvm/attr/LocalVariableItem.java b/group24/448641125/src/com/donaldy/jvm/attr/LocalVariableItem.java new file mode 100644 index 0000000000..7f04ebbc22 --- /dev/null +++ b/group24/448641125/src/com/donaldy/jvm/attr/LocalVariableItem.java @@ -0,0 +1,39 @@ +package com.donaldy.jvm.attr; + +public class LocalVariableItem { + private int startPC; + private int length; + private int nameIndex; + private int descIndex; + private int index; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getNameIndex() { + return nameIndex; + } + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + public int getDescIndex() { + return descIndex; + } + public void setDescIndex(int descIndex) { + this.descIndex = descIndex; + } + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } +} diff --git a/group24/448641125/src/com/donaldy/jvm/attr/LocalVariableTable.java b/group24/448641125/src/com/donaldy/jvm/attr/LocalVariableTable.java new file mode 100644 index 0000000000..c207540570 --- /dev/null +++ b/group24/448641125/src/com/donaldy/jvm/attr/LocalVariableTable.java @@ -0,0 +1,45 @@ +package com.donaldy.jvm.attr; + + +import java.util.ArrayList; +import java.util.List; + +import com.donaldy.jvm.constant.ConstantPool; + +import com.donaldy.jvm.loader.ByteCodeIterator; + +public class LocalVariableTable extends AttributeInfo{ + + List<LocalVariableItem> items = new ArrayList<LocalVariableItem>(); + + public LocalVariableTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static LocalVariableTable parse(ByteCodeIterator iter){ + int attrNameIndex = iter.nextU2ToInt(); + int attrLen = iter.nextU4ToInt(); + int localVariableTableLen = iter.nextU2ToInt(); + + LocalVariableTable lvTable = new LocalVariableTable(attrNameIndex, attrLen); + + for (int i = 0 ; i < localVariableTableLen; ++i) { + LocalVariableItem lvItem = new LocalVariableItem(); + lvItem.setStartPC(iter.nextU2ToInt()); + lvItem.setLength(iter.nextU2ToInt()); + lvItem.setNameIndex(iter.nextU2ToInt()); + lvItem.setDescIndex(iter.nextU2ToInt()); + lvItem.setIndex(iter.nextU2ToInt()); + + lvTable.addLocalVariableItem(lvItem); + } + + + return lvTable; + } + private void addLocalVariableItem(LocalVariableItem item) { + this.items.add(item); + } + + +} diff --git a/group24/448641125/src/com/donaldy/jvm/attr/StackMapTable.java b/group24/448641125/src/com/donaldy/jvm/attr/StackMapTable.java new file mode 100644 index 0000000000..41365dc049 --- /dev/null +++ b/group24/448641125/src/com/donaldy/jvm/attr/StackMapTable.java @@ -0,0 +1,30 @@ +package com.donaldy.jvm.attr; + + +import com.donaldy.jvm.loader.ByteCodeIterator; + +public class StackMapTable extends AttributeInfo{ + + private String originalCode; + + public StackMapTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static StackMapTable parse(ByteCodeIterator iter){ + int index = iter.nextU2ToInt(); + int len = iter.nextU4ToInt(); + StackMapTable t = new StackMapTable(index,len); + + //后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 + String code = iter.nextUxToHexString(len); + t.setOriginalCode(code); + + return t; + } + + private void setOriginalCode(String code) { + this.originalCode = code; + + } +} diff --git a/group24/448641125/src/com/donaldy/jvm/clz/ClassFile.java b/group24/448641125/src/com/donaldy/jvm/clz/ClassFile.java index e37a77e5ad..c36e1940b1 100644 --- a/group24/448641125/src/com/donaldy/jvm/clz/ClassFile.java +++ b/group24/448641125/src/com/donaldy/jvm/clz/ClassFile.java @@ -2,17 +2,23 @@ import com.donaldy.jvm.constant.ClassInfo; import com.donaldy.jvm.constant.ConstantPool; +import com.donaldy.jvm.field.Field; +import com.donaldy.jvm.method.Method; + +import java.util.ArrayList; +import java.util.List; public class ClassFile { - + private int minorVersion; private int majorVersion; - + private AccessFlag accessFlag; private ClassIndex clzIndex; private ConstantPool pool; - - + private List<Field> fields = new ArrayList<Field>(); + private List<Method> methods = new ArrayList<Method>(); + public ClassIndex getClzIndex() { return clzIndex; } @@ -22,10 +28,10 @@ public AccessFlag getAccessFlag() { public void setAccessFlag(AccessFlag accessFlag) { this.accessFlag = accessFlag; } - - - - public ConstantPool getConstantPool() { + + + + public ConstantPool getConstantPool() { return pool; } public int getMinorVersion() { @@ -42,27 +48,38 @@ public void setMajorVersion(int majorVersion) { } public void setConstPool(ConstantPool pool) { this.pool = pool; - + } public void setClassIndex(ClassIndex clzIndex) { - this.clzIndex = clzIndex; + this.clzIndex = clzIndex; + } + + public void addField(Field f){ + this.fields.add(f); } - - - - + public List<Field> getFields(){ + return this.fields; + } + public void addMethod(Method m){ + this.methods.add(m); + } + public List<Method> getMethods() { + return methods; + } + + 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); diff --git a/group24/448641125/src/com/donaldy/jvm/field/Field.java b/group24/448641125/src/com/donaldy/jvm/field/Field.java new file mode 100644 index 0000000000..18cad5669a --- /dev/null +++ b/group24/448641125/src/com/donaldy/jvm/field/Field.java @@ -0,0 +1,46 @@ +package com.donaldy.jvm.field; + +import com.donaldy.jvm.constant.ConstantPool; +import com.donaldy.jvm.constant.UTF8Info; +import com.donaldy.jvm.loader.ByteCodeIterator; + + +public class Field { + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + private ConstantPool pool; + + + public Field( int accessFlag, int nameIndex, int descriptorIndex,ConstantPool pool) { + + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + this.pool = pool; + } + + + + + public static Field parse(ConstantPool pool,ByteCodeIterator iter){ + + int accessFlag = iter.nextU2ToInt(); + int nameIndex = iter.nextU2ToInt(); + int descriptorIndex = iter.nextU2ToInt(); + + //TODO : 因无static类型变量,所以这无 + int attributesCount = iter.nextU2ToInt(); + + Field file = new Field(accessFlag, nameIndex, descriptorIndex, pool); + + return file; + } + + public String toString() { + //System.out.println("name : " + this.nameIndex + ", desc : " + descriptorIndex); + String description = this.pool.getUTF8String(this.descriptorIndex); + String name = this.pool.getUTF8String(this.nameIndex); + return name + ":"+ description; + } +} diff --git a/group24/448641125/src/com/donaldy/jvm/loader/ByteCodeIterator.java b/group24/448641125/src/com/donaldy/jvm/loader/ByteCodeIterator.java index 052bbe1034..82eae449b9 100644 --- a/group24/448641125/src/com/donaldy/jvm/loader/ByteCodeIterator.java +++ b/group24/448641125/src/com/donaldy/jvm/loader/ByteCodeIterator.java @@ -2,9 +2,62 @@ import com.donaldy.jvm.util.Util; +import java.util.Arrays; + public class ByteCodeIterator { - private byte[] codes; + byte[] codes; + int pos = 0; + + ByteCodeIterator(byte[] codes) { + this.codes = codes; + } + + + + 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; + } + + 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 nextUxToHexString(int len) { + byte[] tmp = new byte[len]; + + for (int i = 0; i < len; i++) { + tmp[i] = codes[pos++]; + } + return Util.byteToHexString(tmp).toLowerCase(); + + } + + public void back(int n) { + this.pos -= n; + } + + ///////////////////////Backup////////////////// + /*private byte[] codes; private int pointer = 0; @@ -47,5 +100,5 @@ private byte[] nextLenByte(int len) { } return byteCodes; - } + }*/ } diff --git a/group24/448641125/src/com/donaldy/jvm/loader/ClassFileParser.java b/group24/448641125/src/com/donaldy/jvm/loader/ClassFileParser.java index dffafe3834..b0229c7435 100644 --- a/group24/448641125/src/com/donaldy/jvm/loader/ClassFileParser.java +++ b/group24/448641125/src/com/donaldy/jvm/loader/ClassFileParser.java @@ -4,6 +4,8 @@ import com.donaldy.jvm.clz.ClassFile; import com.donaldy.jvm.clz.ClassIndex; import com.donaldy.jvm.constant.*; +import com.donaldy.jvm.field.Field; +import com.donaldy.jvm.method.Method; import java.io.UnsupportedEncodingException; @@ -33,6 +35,13 @@ public ClassFile parse(byte[] codes) { ClassIndex clzIndex = parseClassIndex(iter); clzFile.setClassIndex(clzIndex); + ////////////Third times JVM homework//////////// + parseInterfaces(iter); //本次作业无interface + + parseFileds(clzFile, iter); + + parseMethods(clzFile, iter); + return clzFile; } @@ -123,5 +132,35 @@ private ConstantPool parseConstantPool(ByteCodeIterator iter) { return pool; } + private void parseInterfaces(ByteCodeIterator iter) { + int interfaceCount = iter.nextU2ToInt(); + + System.out.println("interfaceCount:" + interfaceCount); + + // TODO : 如果实现了interface, 这里需要解析 + } + + private void parseFileds(ClassFile clzFile, ByteCodeIterator iter) { + int fieldCount = iter.nextU2ToInt(); + + //System.out.println("fileCount : " + fieldCount); + + for (int i = 1; i <= fieldCount; i++) { + Field f = Field.parse(clzFile.getConstantPool(), iter); + clzFile.addField(f); + } + + } + + private void parseMethods(ClassFile clzFile, ByteCodeIterator iter) { + + int methodCount = iter.nextU2ToInt(); + + for (int i = 1; i <= methodCount; i++) { + Method m = Method.parse(clzFile, iter); + clzFile.addMethod(m); + } + + } } diff --git a/group24/448641125/src/com/donaldy/jvm/method/Method.java b/group24/448641125/src/com/donaldy/jvm/method/Method.java new file mode 100644 index 0000000000..a69ff696b8 --- /dev/null +++ b/group24/448641125/src/com/donaldy/jvm/method/Method.java @@ -0,0 +1,89 @@ +package com.donaldy.jvm.method; + +import com.donaldy.jvm.attr.*; +import com.donaldy.jvm.clz.ClassFile; +import com.donaldy.jvm.constant.ConstantPool; +import com.donaldy.jvm.constant.UTF8Info; +import com.donaldy.jvm.loader.ByteCodeIterator; + + + +public class Method { + + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private CodeAttr codeAttr; + + private ClassFile clzFile; + + + public ClassFile getClzFile() { + return clzFile; + } + + public int getNameIndex() { + return nameIndex; + } + public int getDescriptorIndex() { + return descriptorIndex; + } + + public CodeAttr getCodeAttr() { + return codeAttr; + } + + public void setCodeAttr(CodeAttr code) { + this.codeAttr = code; + } + + public Method(ClassFile clzFile,int accessFlag, int nameIndex, int descriptorIndex) { + this.clzFile = clzFile; + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + } + + + public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ + + int accessFlag = iter.nextU2ToInt(); + int nameIndex = iter.nextU2ToInt(); + int descriptorIndex = iter.nextU2ToInt(); + + int attributeCount = iter.nextU2ToInt(); + System.out.println("attributeCount : " + attributeCount); + + int attrNameIndex = iter.nextU2ToInt(); + if (!"Code".equals(clzFile.getConstantPool().getUTF8String(attrNameIndex))) + throw new RuntimeException("attributeInfo : " + attrNameIndex); + + int attrLen = iter.nextU4ToInt(); + int maxStack = iter.nextU2ToInt(); + int maxLocals = iter.nextU2ToInt(); + int codeLen = iter.nextU4ToInt(); + String code = iter.nextUxToHexString(codeLen); + + CodeAttr codeAttr = new CodeAttr(attrNameIndex, attrLen, maxStack, maxLocals, codeLen, code); + + int exceptionLen = iter.nextU2ToInt(); + System.out.println("execptionLen : " + exceptionLen); + + int attributesCount = iter.nextU2ToInt(); + System.out.println("attributeCount : " + attributesCount); + + LineNumberTable lnTable = LineNumberTable.parse(iter); + codeAttr.setLineNumberTable(lnTable); + + LocalVariableTable lvTable = LocalVariableTable.parse(iter); + codeAttr.setLocalVariableTable(lvTable); + + + Method method = new Method(clzFile, accessFlag, nameIndex, descriptorIndex); + + method.setCodeAttr(codeAttr); + return method; + + } +} diff --git a/group24/448641125/src/com/donaldy/jvm/test/ClassFileloaderTest.java b/group24/448641125/src/com/donaldy/jvm/test/ClassFileloaderTest.java index 387990b9b7..8610fda4c9 100644 --- a/group24/448641125/src/com/donaldy/jvm/test/ClassFileloaderTest.java +++ b/group24/448641125/src/com/donaldy/jvm/test/ClassFileloaderTest.java @@ -3,6 +3,8 @@ import com.donaldy.jvm.clz.ClassFile; import com.donaldy.jvm.clz.ClassIndex; import com.donaldy.jvm.constant.*; +import com.donaldy.jvm.field.Field; +import com.donaldy.jvm.method.Method; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -10,8 +12,7 @@ import com.donaldy.jvm.loader.ClassFileLoader; - - +import java.util.List; public class ClassFileloaderTest { @@ -194,4 +195,85 @@ public void testClassIndex(){ Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); } + /** + * 下面是第三次JVM课应实现的测试用例 + */ + @Test + public void testReadFields(){ + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(this.path1); + clzFile = loader.loadClass("com.donaldy.jvm.test.EmployeeV1"); + + List<Field> fields = clzFile.getFields(); + Assert.assertEquals(2, fields.size()); + { + Field f = fields.get(0); + Assert.assertEquals("name:Ljava/lang/String;", f.toString()); + } + { + Field f = fields.get(1); + Assert.assertEquals("age:I", f.toString()); + } + } + @Test + public void testMethods(){ + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(this.path1); + clzFile = loader.loadClass("com.donaldy.jvm.test.EmployeeV1"); + + + List<Method> methods = clzFile.getMethods(); + ConstantPool pool = clzFile.getConstantPool(); + + { + Method m = methods.get(0); + assertMethodEquals(pool,m, + "<init>", + "(Ljava/lang/String;I)V", + "2ab7000c2a2bb5000f2a1cb50011b1"); + + } + { + Method m = methods.get(1); + assertMethodEquals(pool,m, + "setName", + "(Ljava/lang/String;)V", + "2a2bb5000fb1"); + + } + { + Method m = methods.get(2); + assertMethodEquals(pool,m, + "setAge", + "(I)V", + "2a1bb50011b1"); + } + { + Method m = methods.get(3); + assertMethodEquals(pool,m, + "sayHello", + "()V", + "b2001c1222b60024b1"); + + } + { + Method m = methods.get(4); + assertMethodEquals(pool,m, + "main", + "([Ljava/lang/String;)V", + "bb000159122b101db7002d4c2bb6002fb1"); + } + } + + private void assertMethodEquals(ConstantPool pool,Method m , String expectedName, String expectedDesc,String expectedCode){ + String methodName = pool.getUTF8String(m.getNameIndex()); + String methodDesc = pool.getUTF8String(m.getDescriptorIndex()); + String code = m.getCodeAttr().getCode(); + Assert.assertEquals(expectedName, methodName); + Assert.assertEquals(expectedDesc, methodDesc); + Assert.assertEquals(expectedCode, code); + } + } From 2c40a6f0a102324ca8fd00734155514c372fc90e Mon Sep 17 00:00:00 2001 From: Pan <gqp201210@gmail.com> Date: Sat, 15 Apr 2017 22:48:59 +0800 Subject: [PATCH 263/287] fix warring --- .../src/test/java/com/pan/alg/StackUtilTest.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/group11/252308879/mini-jvm/src/test/java/com/pan/alg/StackUtilTest.java b/group11/252308879/mini-jvm/src/test/java/com/pan/alg/StackUtilTest.java index f94a01b2d7..71671c9b47 100644 --- a/group11/252308879/mini-jvm/src/test/java/com/pan/alg/StackUtilTest.java +++ b/group11/252308879/mini-jvm/src/test/java/com/pan/alg/StackUtilTest.java @@ -1,7 +1,5 @@ package com.pan.alg; -import static org.junit.Assert.fail; - import java.util.Stack; import org.junit.After; @@ -20,7 +18,7 @@ public void tearDown() throws Exception { @Test public void testAddToBottom() { - Stack<Integer> s = new Stack(); + Stack<Integer> s = new Stack<>(); s.push(1); s.push(2); s.push(3); @@ -32,7 +30,7 @@ public void testAddToBottom() { } @Test public void testReverse() { - Stack<Integer> s = new Stack(); + Stack<Integer> s = new Stack<>(); s.push(1); s.push(2); s.push(3); @@ -45,7 +43,7 @@ public void testReverse() { @Test public void testRemove() { - Stack<Integer> s = new Stack(); + Stack<Integer> s = new Stack<>(); s.push(1); s.push(2); s.push(3); @@ -55,7 +53,7 @@ public void testRemove() { @Test public void testGetTop() { - Stack<Integer> s = new Stack(); + Stack<Integer> s = new Stack<>(); s.push(1); s.push(2); s.push(3); From f1e39f3b65075a999ef8833f5b59610ad38a2b25 Mon Sep 17 00:00:00 2001 From: Pan <gqp201210@gmail.com> Date: Sat, 15 Apr 2017 23:21:19 +0800 Subject: [PATCH 264/287] Test user eclipe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 使用Eclipe试一下生成的字节码首个常量为class_info文件问题 --- .../main/java/com/pan/stack/StackUtil.java | 4 +-- .../src/main/java/com/pan/alg/StackUtil.java | 4 +-- .../main/java/com/pan/jvm/attr/CodeAttr.java | 1 - .../com/pan/jvm/attr/LocalVariableTable.java | 2 -- .../main/java/com/pan/jvm/field/Field.java | 1 - .../com/pan/jvm/loader/ClassFileLoader.java | 2 +- .../src/test/java/com/pan/jvm/EmployeeV1.java | 31 ------------------- 7 files changed, 5 insertions(+), 40 deletions(-) delete mode 100644 group11/252308879/mini-jvm/src/test/java/com/pan/jvm/EmployeeV1.java diff --git a/group11/252308879/data-structure/src/main/java/com/pan/stack/StackUtil.java b/group11/252308879/data-structure/src/main/java/com/pan/stack/StackUtil.java index b4056e830a..74918b1e37 100644 --- a/group11/252308879/data-structure/src/main/java/com/pan/stack/StackUtil.java +++ b/group11/252308879/data-structure/src/main/java/com/pan/stack/StackUtil.java @@ -12,7 +12,7 @@ public static void bad_reverse(Stack<Integer> s) { if(s == null || s.isEmpty()){ return; } - Stack<Integer> tmpStack = new Stack(); + Stack<Integer> tmpStack = new Stack<>(); while(!s.isEmpty()){ tmpStack.push(s.pop()); } @@ -104,7 +104,7 @@ public static Object[] getTop(Stack s,int len) { */ public static boolean isValidPairs(String s){ - Stack<Character> stack = new Stack(); + Stack<Character> stack = new Stack<>(); for(int i=0;i<s.length();i++){ char c = s.charAt(i); diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/alg/StackUtil.java b/group11/252308879/mini-jvm/src/main/java/com/pan/alg/StackUtil.java index 1c7e0a5d0e..01a7f2da52 100644 --- a/group11/252308879/mini-jvm/src/main/java/com/pan/alg/StackUtil.java +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/alg/StackUtil.java @@ -12,7 +12,7 @@ public static void bad_reverse(Stack<Integer> s) { if(s == null || s.isEmpty()){ return; } - Stack<Integer> tmpStack = new Stack(); + Stack<Integer> tmpStack = new Stack<>(); while(!s.isEmpty()){ tmpStack.push(s.pop()); } @@ -104,7 +104,7 @@ public static Object[] getTop(Stack s,int len) { */ public static boolean isValidPairs(String s){ - Stack<Character> stack = new Stack(); + Stack<Character> stack = new Stack<>(); for(int i=0;i<s.length();i++){ char c = s.charAt(i); diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/CodeAttr.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/CodeAttr.java index 5b913a36c2..80a05a9ac0 100644 --- a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/CodeAttr.java +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/CodeAttr.java @@ -1,7 +1,6 @@ package com.pan.jvm.attr; import com.pan.jvm.clz.ClassFile; -import com.pan.jvm.constant.ConstantPool; import com.pan.jvm.loader.ByteCodeIterator; diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/LocalVariableTable.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/LocalVariableTable.java index 6291f9a605..74c73baac6 100644 --- a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/LocalVariableTable.java +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/attr/LocalVariableTable.java @@ -4,8 +4,6 @@ import java.util.ArrayList; import java.util.List; -import com.pan.jvm.constant.ConstantPool; - import com.pan.jvm.loader.ByteCodeIterator; public class LocalVariableTable extends AttributeInfo{ diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/field/Field.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/field/Field.java index e427618564..22775d0de7 100644 --- a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/field/Field.java +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/field/Field.java @@ -1,7 +1,6 @@ package com.pan.jvm.field; -import com.pan.jvm.constant.ConstantInfo; import com.pan.jvm.constant.ConstantPool; import com.pan.jvm.constant.UTF8Info; import com.pan.jvm.loader.ByteCodeIterator; diff --git a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileLoader.java b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileLoader.java index c1d0553522..fa25990691 100644 --- a/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileLoader.java +++ b/group11/252308879/mini-jvm/src/main/java/com/pan/jvm/loader/ClassFileLoader.java @@ -15,7 +15,7 @@ public class ClassFileLoader { - private List<String> clzPaths = new ArrayList(); + private List<String> clzPaths = new ArrayList<>(); public byte[] readBinaryCode(String className) { className = className.replace('.', File.separatorChar) + ".class"; diff --git a/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/EmployeeV1.java b/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/EmployeeV1.java deleted file mode 100644 index 92b5b403ca..0000000000 --- a/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/EmployeeV1.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.pan.jvm; - -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 3f3b383ac239cf88f7e28fce1eb22e6cdb60a563 Mon Sep 17 00:00:00 2001 From: Pan <gqp201210@gmail.com> Date: Sat, 15 Apr 2017 23:39:33 +0800 Subject: [PATCH 265/287] modify dir struct --- group11/252308879/data-structure/pom.xml | 1 - group11/252308879/mini-jvm/pom.xml | 1 - .../java/com/pan/jvm/ClassFileLoaderTest.java | 30 +++++++++---------- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/group11/252308879/data-structure/pom.xml b/group11/252308879/data-structure/pom.xml index 445ba45741..42eb53c993 100644 --- a/group11/252308879/data-structure/pom.xml +++ b/group11/252308879/data-structure/pom.xml @@ -8,7 +8,6 @@ <version>1.0.0-SNAPSHOT</version> </parent> - <groupId>com.pan</groupId> <artifactId>data-structure</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>jar</packaging> diff --git a/group11/252308879/mini-jvm/pom.xml b/group11/252308879/mini-jvm/pom.xml index a1421f550e..b1f01e4594 100644 --- a/group11/252308879/mini-jvm/pom.xml +++ b/group11/252308879/mini-jvm/pom.xml @@ -8,7 +8,6 @@ <version>1.0.0-SNAPSHOT</version> </parent> - <groupId>com.pan</groupId> <artifactId>mini-jvm</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>jar</packaging> diff --git a/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/ClassFileLoaderTest.java b/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/ClassFileLoaderTest.java index b0a61b242a..d341553c70 100644 --- a/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/ClassFileLoaderTest.java +++ b/group11/252308879/mini-jvm/src/test/java/com/pan/jvm/ClassFileLoaderTest.java @@ -201,47 +201,47 @@ public void testReadFields(){ } @Test public void testMethods(){ - + List<Method> methods = clzFile.getMethods(); ConstantPool pool = clzFile.getConstantPool(); - + { - Method m = methods.get(0); + Method m = methods.get(0); assertMethodEquals(pool,m, "<init>", "(Ljava/lang/String;I)V", - "2ab700012a2bb500022a1cb50003b1"); - + "2ab7000c2a2bb5000f2a1cb50011b1"); + } { - Method m = methods.get(1); + Method m = methods.get(1); assertMethodEquals(pool,m, "setName", "(Ljava/lang/String;)V", - "2a2bb50002b1"); - + "2a2bb5000fb1"); + } { - Method m = methods.get(2); + Method m = methods.get(2); assertMethodEquals(pool,m, "setAge", "(I)V", - "2a1bb50003b1"); + "2a1bb50011b1"); } { - Method m = methods.get(3); + Method m = methods.get(3); assertMethodEquals(pool,m, "sayHello", "()V", - "b200041205b60006b1"); - + "b2001c1222b60024b1"); + } { - Method m = methods.get(4); + Method m = methods.get(4); assertMethodEquals(pool,m, "main", "([Ljava/lang/String;)V", - "bb0007591208101db700094c2bb6000ab1"); + "bb000159122b101db7002d4c2bb6002fb1"); } } From 84062570ac4323cc1c89c6afa2c321992de28be2 Mon Sep 17 00:00:00 2001 From: lzb <lzbferrari@gmail.com> Date: Sun, 16 Apr 2017 03:25:23 +0800 Subject: [PATCH 266/287] =?UTF-8?q?jvm=E7=AC=AC=E4=B8=89=E6=AC=A1=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{datastructure => basic}/ArrayList.java | 2 +- .../{datastructure => basic}/ArrayUtil.java | 2 +- .../BinaryTreeNode.java | 2 +- .../src/main/java/me/lzb/basic/InfixExpr.java | 19 + .../{datastructure => basic}/Iterator.java | 2 +- .../{algorithm => basic}/LRUPageFrame.java | 2 +- .../{datastructure => basic}/LinkedList.java | 2 +- .../me/lzb/{datastructure => basic}/List.java | 2 +- .../lzb/{datastructure => basic}/Queue.java | 2 +- .../lzb/{datastructure => basic}/Stack.java | 2 +- .../{datastructure => basic}/StackUtil.java | 2 +- .../ArrayListTest.java | 6 +- .../test/java/me/lzb/basic/InfixExprTest.java | 48 +++ .../LRUPageFrameTest.java | 3 +- .../LinkedListTest.java | 6 +- .../StackUtilTest.java | 2 +- .../java/me/lzb/jvm/attr/AttributeInfo.java | 22 ++ .../main/java/me/lzb/jvm/attr/CodeAttr.java | 52 +++ .../java/me/lzb/jvm/attr/LineNumberItem.java | 31 ++ .../java/me/lzb/jvm/attr/LineNumberTable.java | 23 ++ .../me/lzb/jvm/attr/LocalVariableItem.java | 62 +++ .../me/lzb/jvm/attr/LocalVariableTable.java | 20 + .../java/me/lzb/jvm/attr/StackMapTable.java | 15 + .../main/java/me/lzb/jvm/clz/ClassFile.java | 45 ++- .../java/me/lzb/jvm/constant/ClassInfo.java | 2 +- .../me/lzb/jvm/constant/ConstantInfo.java | 16 + .../me/lzb/jvm/constant/ConstantPool.java | 4 + .../me/lzb/jvm/constant/FieldRefInfo.java | 2 +- .../java/me/lzb/jvm/constant/JvmConstant.java | 23 -- .../me/lzb/jvm/constant/MethodRefInfo.java | 2 +- .../me/lzb/jvm/constant/NameAndTypeInfo.java | 2 +- .../java/me/lzb/jvm/constant/StringInfo.java | 2 +- .../java/me/lzb/jvm/constant/UTF8Info.java | 2 +- .../jvm/exception/NotClassFileException.java | 14 - .../src/main/java/me/lzb/jvm/field/Field.java | 30 ++ .../me/lzb/jvm/loader/ClassFileLoader.java | 28 +- .../me/lzb/jvm/loader/ClassFileParser.java | 210 ++++++++-- .../main/java/me/lzb/jvm/method/Method.java | 65 ++++ .../java/me/lzb/jvm/ClassFileloaderTest.java | 51 +-- .../main/java/me/lzb/other/graph/Graph.java | 366 ++++++++++++++++++ .../me/lzb/other/lock/ReentrantTest1.java | 27 ++ .../me/lzb/other/lock/ReentrantTest2.java | 35 ++ .../lzb/other/proxy/MyInvocationHandler.java | 52 +++ .../java/me/lzb/other/proxy/UserService.java | 11 + .../me/lzb/other/proxy/UserServiceImpl.java | 11 + .../java/me/lzb/other/proxy/ProxyTest.java | 25 ++ 46 files changed, 1218 insertions(+), 136 deletions(-) rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{datastructure => basic}/ArrayList.java (98%) rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{datastructure => basic}/ArrayUtil.java (99%) rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{datastructure => basic}/BinaryTreeNode.java (97%) create mode 100644 group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/InfixExpr.java rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{datastructure => basic}/Iterator.java (80%) rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{algorithm => basic}/LRUPageFrame.java (99%) rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{datastructure => basic}/LinkedList.java (99%) rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{datastructure => basic}/List.java (86%) rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{datastructure => basic}/Queue.java (94%) rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{datastructure => basic}/Stack.java (97%) rename group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/{datastructure => basic}/StackUtil.java (97%) rename group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/{datastructure => basic}/ArrayListTest.java (96%) create mode 100644 group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/basic/InfixExprTest.java rename group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/{algorithm => basic}/LRUPageFrameTest.java (95%) rename group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/{datastructure => basic}/LinkedListTest.java (98%) rename group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/{datastructure => basic}/StackUtilTest.java (97%) create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/AttributeInfo.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/CodeAttr.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/LineNumberItem.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/LineNumberTable.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/LocalVariableItem.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/LocalVariableTable.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/StackMapTable.java delete mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/JvmConstant.java delete mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/exception/NotClassFileException.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/field/Field.java create mode 100644 group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/method/Method.java create mode 100644 group24/1148285693/learning2017/other/src/main/java/me/lzb/other/graph/Graph.java create mode 100644 group24/1148285693/learning2017/other/src/main/java/me/lzb/other/lock/ReentrantTest1.java create mode 100644 group24/1148285693/learning2017/other/src/main/java/me/lzb/other/lock/ReentrantTest2.java create mode 100644 group24/1148285693/learning2017/other/src/main/java/me/lzb/other/proxy/MyInvocationHandler.java create mode 100644 group24/1148285693/learning2017/other/src/main/java/me/lzb/other/proxy/UserService.java create mode 100644 group24/1148285693/learning2017/other/src/main/java/me/lzb/other/proxy/UserServiceImpl.java create mode 100644 group24/1148285693/learning2017/other/src/test/java/me/lzb/other/proxy/ProxyTest.java diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/ArrayList.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/ArrayList.java similarity index 98% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/ArrayList.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/ArrayList.java index 080aa4f724..af897cd58f 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/ArrayList.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/ArrayList.java @@ -1,4 +1,4 @@ -package me.lzb.datastructure; +package me.lzb.basic; /** * 简易ArrayList diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/ArrayUtil.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/ArrayUtil.java similarity index 99% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/ArrayUtil.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/ArrayUtil.java index de101845aa..eab32c80cc 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/ArrayUtil.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/ArrayUtil.java @@ -1,4 +1,4 @@ -package me.lzb.datastructure; +package me.lzb.basic; public class ArrayUtil { diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/BinaryTreeNode.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/BinaryTreeNode.java similarity index 97% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/BinaryTreeNode.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/BinaryTreeNode.java index dfcaa60300..88395e3010 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/BinaryTreeNode.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/BinaryTreeNode.java @@ -1,4 +1,4 @@ -package me.lzb.datastructure; +package me.lzb.basic; /** * 左边比父节点小,右边比父节点大 diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/InfixExpr.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/InfixExpr.java new file mode 100644 index 0000000000..cd682a65c2 --- /dev/null +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/InfixExpr.java @@ -0,0 +1,19 @@ +package me.lzb.basic; + +/** + * Created by LZB on 2017/4/15. + */ +public class InfixExpr { + + private String expr; + + public InfixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + + return 0.0f; + } + +} diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/Iterator.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/Iterator.java similarity index 80% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/Iterator.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/Iterator.java index b65f73b2e3..86e8cae942 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/Iterator.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/Iterator.java @@ -1,4 +1,4 @@ -package me.lzb.datastructure; +package me.lzb.basic; /** * Created by LZB on 2017/3/11. 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/basic/LRUPageFrame.java similarity index 99% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/algorithm/LRUPageFrame.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/LRUPageFrame.java index 1f1d0a36b7..6e0e570ce6 100644 --- 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/basic/LRUPageFrame.java @@ -1,4 +1,4 @@ -package me.lzb.algorithm; +package me.lzb.basic; /** * 用双向链表实现LRU算法 diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/LinkedList.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/LinkedList.java similarity index 99% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/LinkedList.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/LinkedList.java index f79b7eaf18..268b69bf50 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/LinkedList.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/LinkedList.java @@ -1,4 +1,4 @@ -package me.lzb.datastructure; +package me.lzb.basic; /** diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/List.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/List.java similarity index 86% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/List.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/List.java index 8f6478c49e..df7f30812b 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/List.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/List.java @@ -1,4 +1,4 @@ -package me.lzb.datastructure; +package me.lzb.basic; /** * list接口 diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/Queue.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/Queue.java similarity index 94% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/Queue.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/Queue.java index 35dc95f688..08303d3fb5 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/Queue.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/Queue.java @@ -1,4 +1,4 @@ -package me.lzb.datastructure; +package me.lzb.basic; /** * 先进先出 diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/Stack.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/Stack.java similarity index 97% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/Stack.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/Stack.java index 367b7210e6..60785110eb 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/Stack.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/Stack.java @@ -1,4 +1,4 @@ -package me.lzb.datastructure; +package me.lzb.basic; /** * 先进后出 diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/StackUtil.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/StackUtil.java similarity index 97% rename from group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/StackUtil.java rename to group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/StackUtil.java index c854ec7052..8fd3e94d19 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/datastructure/StackUtil.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/StackUtil.java @@ -1,4 +1,4 @@ -package me.lzb.datastructure; +package me.lzb.basic; import java.util.Stack; public class StackUtil { diff --git a/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/datastructure/ArrayListTest.java b/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/basic/ArrayListTest.java similarity index 96% rename from group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/datastructure/ArrayListTest.java rename to group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/basic/ArrayListTest.java index dcb879a948..efcfdbae1d 100644 --- a/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/datastructure/ArrayListTest.java +++ b/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/basic/ArrayListTest.java @@ -1,7 +1,7 @@ -package me.lzb.datastructure; +package me.lzb.basic; -import me.lzb.datastructure.ArrayList; -import me.lzb.datastructure.Iterator; +import me.lzb.basic.ArrayList; +import me.lzb.basic.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/basic/InfixExprTest.java b/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/basic/InfixExprTest.java new file mode 100644 index 0000000000..5ca7621354 --- /dev/null +++ b/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/basic/InfixExprTest.java @@ -0,0 +1,48 @@ +package me.lzb.basic; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class InfixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + //InfixExpr expr = new InfixExpr("300*20+12*5-20/4"); + { + InfixExpr expr = new InfixExpr("2+3*4+5"); + Assert.assertEquals(19.0, expr.evaluate(), 0.001f); + } + { + InfixExpr expr = new InfixExpr("3*20+12*5-40/2"); + Assert.assertEquals(100.0, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("3*20/2"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("20/2*3"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("10-30+50"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + } + +} 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/basic/LRUPageFrameTest.java similarity index 95% rename from group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/algorithm/LRUPageFrameTest.java rename to group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/basic/LRUPageFrameTest.java index 66bfd42119..828eab0881 100644 --- 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/basic/LRUPageFrameTest.java @@ -1,5 +1,6 @@ -package me.lzb.algorithm; +package me.lzb.basic; +import me.lzb.basic.LRUPageFrame; import org.junit.Assert; import org.junit.Test; diff --git a/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/datastructure/LinkedListTest.java b/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/basic/LinkedListTest.java similarity index 98% rename from group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/datastructure/LinkedListTest.java rename to group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/basic/LinkedListTest.java index 1914195aa5..6f02328060 100644 --- a/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/datastructure/LinkedListTest.java +++ b/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/basic/LinkedListTest.java @@ -1,7 +1,7 @@ -package me.lzb.datastructure; +package me.lzb.basic; -import me.lzb.datastructure.Iterator; -import me.lzb.datastructure.LinkedList; +import me.lzb.basic.Iterator; +import me.lzb.basic.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/datastructure/StackUtilTest.java b/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/basic/StackUtilTest.java similarity index 97% rename from group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/datastructure/StackUtilTest.java rename to group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/basic/StackUtilTest.java index 929d365f69..1fa9396c0a 100644 --- a/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/datastructure/StackUtilTest.java +++ b/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/basic/StackUtilTest.java @@ -1,4 +1,4 @@ -package me.lzb.datastructure; +package me.lzb.basic; import org.junit.After; import org.junit.Assert; diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/AttributeInfo.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/AttributeInfo.java new file mode 100644 index 0000000000..fd000bdcb3 --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/AttributeInfo.java @@ -0,0 +1,22 @@ +package me.lzb.jvm.attr; + +/** + * Created by LZB on 2017/4/15. + */ +public abstract class AttributeInfo { + + public static final String CODE = "Code"; + public static final String CONST_VALUE = "ConstantValue"; + public static final String EXCEPTIONS = "Exceptions"; + public static final String LINE_NUM_TABLE = "LineNumberTable"; + public static final String LOCAL_VAR_TABLE = "LocalVariableTable"; + public static final String STACK_MAP_TABLE = "StackMapTable"; + + int attrNameIndex; + int attrLen; + + public AttributeInfo(int attrNameIndex, int attrLen) { + this.attrNameIndex = attrNameIndex; + this.attrLen = attrLen; + } +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/CodeAttr.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/CodeAttr.java new file mode 100644 index 0000000000..2addebeb39 --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/CodeAttr.java @@ -0,0 +1,52 @@ +package me.lzb.jvm.attr; + +/** + * Created by LZB on 2017/4/15. + */ +public class CodeAttr extends AttributeInfo { + private int maxStack; + private int maxLocals; + private int codeLen; + private String code; + private LineNumberTable lineNumTable; + private LocalVariableTable localVarTable; + private StackMapTable stackMapTable; + + public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen, String code /*ByteCodeCommand[] cmds*/) { + super(attrNameIndex, attrLen); + this.maxStack = maxStack; + this.maxLocals = maxLocals; + this.codeLen = codeLen; + this.code = code; + //this.cmds = cmds; + } + + + public String getCode() { + return code; + } + + public LineNumberTable getLineNumTable() { + return lineNumTable; + } + + public void setLineNumTable(LineNumberTable lineNumTable) { + this.lineNumTable = lineNumTable; + } + + public LocalVariableTable getLocalVarTable() { + return localVarTable; + } + + public void setLocalVarTable(LocalVariableTable localVarTable) { + this.localVarTable = localVarTable; + } + + public StackMapTable getStackMapTable() { + return stackMapTable; + } + + public void setStackMapTable(StackMapTable stackMapTable) { + this.stackMapTable = stackMapTable; + } +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/LineNumberItem.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/LineNumberItem.java new file mode 100644 index 0000000000..e621cf925a --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/LineNumberItem.java @@ -0,0 +1,31 @@ +package me.lzb.jvm.attr; + +/** + * Created by LZB on 2017/4/16. + */ +public class LineNumberItem { + int startPC; + int lineNum; + + + public LineNumberItem(int startPC, int lineNum) { + this.startPC = startPC; + this.lineNum = lineNum; + } + + public int getStartPC() { + return startPC; + } + + // public void setStartPC(int startPC) { +// this.startPC = startPC; +// } + + public int getLineNum() { + return lineNum; + } + +// public void setLineNum(int lineNum) { +// this.lineNum = lineNum; +// } +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/LineNumberTable.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/LineNumberTable.java new file mode 100644 index 0000000000..5bf7b4759b --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/LineNumberTable.java @@ -0,0 +1,23 @@ +package me.lzb.jvm.attr; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by LZB on 2017/4/15. + */ +public class LineNumberTable extends AttributeInfo { + List<LineNumberItem> items = new ArrayList<>(); + + + public void addLineNumberItem(LineNumberItem item) { + this.items.add(item); + } + + public LineNumberTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + + } + + +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/LocalVariableItem.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/LocalVariableItem.java new file mode 100644 index 0000000000..decef772a3 --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/LocalVariableItem.java @@ -0,0 +1,62 @@ +package me.lzb.jvm.attr; + +/** + * Created by LZB on 2017/4/15. + */ +public class LocalVariableItem { + private int startPC; + private int length; + private int nameIndex; + private int descIndex; + private int index; + + + public LocalVariableItem(int startPC, int length, int nameIndex, int descIndex, int index){ + this.startPC = startPC; + this.length = length; + this.nameIndex = nameIndex; + this.descIndex = descIndex; + this.index = index; + } + + + public int getStartPC() { + return startPC; + } + + public void setStartPC(int startPC) { + this.startPC = startPC; + } + + public int getLength() { + return length; + } + + public void setLength(int length) { + this.length = length; + } + + public int getNameIndex() { + return nameIndex; + } + + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + + public int getDescIndex() { + return descIndex; + } + + public void setDescIndex(int descIndex) { + this.descIndex = descIndex; + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/LocalVariableTable.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/LocalVariableTable.java new file mode 100644 index 0000000000..9dca129d71 --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/LocalVariableTable.java @@ -0,0 +1,20 @@ +package me.lzb.jvm.attr; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by LZB on 2017/4/15. + */ +public class LocalVariableTable extends AttributeInfo { + List<LocalVariableItem> items = new ArrayList<>(); + + public LocalVariableTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public void addLocalVariableItem(LocalVariableItem item) { + this.items.add(item); + } + +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/StackMapTable.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/StackMapTable.java new file mode 100644 index 0000000000..0b8947bdf8 --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/attr/StackMapTable.java @@ -0,0 +1,15 @@ +package me.lzb.jvm.attr; + +/** + * Created by LZB on 2017/4/15. + */ +public class StackMapTable extends AttributeInfo { + private String originalCode; + + public StackMapTable(int attrNameIndex, int attrLen, String code) { + super(attrNameIndex, attrLen); + this.originalCode = code; + } + + +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/clz/ClassFile.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/clz/ClassFile.java index 380bf7c016..c5de9be5ce 100644 --- a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/clz/ClassFile.java +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/clz/ClassFile.java @@ -1,6 +1,11 @@ package me.lzb.jvm.clz; import me.lzb.jvm.constant.ConstantPool; +import me.lzb.jvm.field.Field; +import me.lzb.jvm.method.Method; + +import java.util.ArrayList; +import java.util.List; /** * Created by LZB on 2017/4/14. @@ -17,10 +22,13 @@ public class ClassFile { private ClassIndex clzIndex; - private int constantPoolCount; private ConstantPool constantPool; + private List<Field> fields = new ArrayList<>(); + + private List<Method> methods = new ArrayList<>(); + public String getMagicNumber() { return magicNumber; @@ -64,14 +72,26 @@ public void setConstantPool(ConstantPool constantPool) { } - public int getConstantPoolCount() { - return constantPoolCount; + + public List<Field> getFields() { + return fields; } - public void setConstantPoolCount(int constantPoolCount) { - this.constantPoolCount = constantPoolCount; + public void setFields(List<Field> fields) { + this.fields = fields; } + public List<Method> getMethods() { + return methods; + } + + public void setMethods(List<Method> methods) { + this.methods = methods; + } + + + + public ClassIndex getClzIndex() { return clzIndex; @@ -93,4 +113,19 @@ public void print(){ } + + + + public int getConstantPoolCount() { + return constantPool.getSize(); + } + + public void addField(Field f){ + this.fields.add(f); + } + + public void addMethod(Method m){ + this.methods.add(m); + } + } diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/ClassInfo.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/ClassInfo.java index 1cfdc94ed7..200e59834a 100644 --- a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/ClassInfo.java +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/ClassInfo.java @@ -4,7 +4,7 @@ * Created by LZB on 2017/4/14. */ public class ClassInfo extends ConstantInfo{ - private int type = JvmConstant.Class_info; + private int type = ConstantInfo.Class_info; private int utf8Index; public ClassInfo(ConstantPool pool) { diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/ConstantInfo.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/ConstantInfo.java index df65a833c2..3bbabf2180 100644 --- a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/ConstantInfo.java +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/ConstantInfo.java @@ -5,6 +5,22 @@ */ public abstract class ConstantInfo { + public static final String MAGIC_NUMBER = "cafebabe"; + + public static final int Class_info = 7; + + public static final int Fieldref_info = 9; + + public static final int Methodref_info = 10; + + public static final int String_info = 8; + + public static final int NameAndType_info = 12; + + public static final int Utf8_info = 1; + + + protected ConstantPool constantPool; diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/ConstantPool.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/ConstantPool.java index 4e787eed62..d78f0a71f4 100644 --- a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/ConstantPool.java +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/ConstantPool.java @@ -25,4 +25,8 @@ public ConstantInfo getConstantInfo(int index){ return constantInfoList.get(index); } + public String getUTF8String(int index){ + return ((UTF8Info)this.constantInfoList.get(index)).getValue(); + } + } diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/FieldRefInfo.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/FieldRefInfo.java index 907db2c4f8..0ebab33b39 100644 --- a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/FieldRefInfo.java +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/FieldRefInfo.java @@ -4,7 +4,7 @@ * Created by LZB on 2017/4/15. */ public class FieldRefInfo extends ConstantInfo{ - private int type = JvmConstant.Fieldref_info; + private int type = ConstantInfo.Fieldref_info; private int classInfoIndex; private int nameAndTypeIndex; diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/JvmConstant.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/JvmConstant.java deleted file mode 100644 index 1707dc72c0..0000000000 --- a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/JvmConstant.java +++ /dev/null @@ -1,23 +0,0 @@ -package me.lzb.jvm.constant; - -/** - * Jvm常量 - * Created by LZB on 2017/4/14. - */ -public class JvmConstant { - - public static final String MAGIC_NUMBER = "cafebabe"; - - public static final int Class_info = 7; - - public static final int Fieldref_info = 9; - - public static final int Methodref_info = 10; - - public static final int String_info = 8; - - public static final int NameAndType_info = 12; - - public static final int Utf8_info = 1; - -} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/MethodRefInfo.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/MethodRefInfo.java index b7ae059e1f..263c185af5 100644 --- a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/MethodRefInfo.java +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/MethodRefInfo.java @@ -4,7 +4,7 @@ * Created by LZB on 2017/4/15. */ public class MethodRefInfo extends ConstantInfo { - private int type = JvmConstant.Methodref_info; + private int type = ConstantInfo.Methodref_info; private int classInfoIndex; private int nameAndTypeIndex; diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/NameAndTypeInfo.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/NameAndTypeInfo.java index 3ffdfd8927..bdf158ec37 100644 --- a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/NameAndTypeInfo.java +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/NameAndTypeInfo.java @@ -4,7 +4,7 @@ * Created by LZB on 2017/4/15. */ public class NameAndTypeInfo extends ConstantInfo { - private int type = JvmConstant.NameAndType_info; + private int type = ConstantInfo.NameAndType_info; private int index1; private int index2; diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/StringInfo.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/StringInfo.java index 00b80d64ef..8ba36d8cfc 100644 --- a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/StringInfo.java +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/StringInfo.java @@ -4,7 +4,7 @@ * Created by LZB on 2017/4/15. */ public class StringInfo extends ConstantInfo { - private int type = JvmConstant.String_info; + private int type = ConstantInfo.String_info; private int index; diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/UTF8Info.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/UTF8Info.java index e6389fb397..d3f35c2fd7 100644 --- a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/UTF8Info.java +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/constant/UTF8Info.java @@ -4,7 +4,7 @@ * Created by LZB on 2017/4/15. */ public class UTF8Info extends ConstantInfo { - private int type = JvmConstant.Class_info; + private int type = ConstantInfo.Class_info; private String value; diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/exception/NotClassFileException.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/exception/NotClassFileException.java deleted file mode 100644 index d3952ead6d..0000000000 --- a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/exception/NotClassFileException.java +++ /dev/null @@ -1,14 +0,0 @@ -package me.lzb.jvm.exception; - -/** - * Created by LZB on 2017/4/14. - */ -public class NotClassFileException extends Exception{ - public NotClassFileException(String message, Exception cause) { - super(message, cause); - } - - public NotClassFileException(String message) { - super(message); - } -} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/field/Field.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/field/Field.java new file mode 100644 index 0000000000..f388fd01bf --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/field/Field.java @@ -0,0 +1,30 @@ +package me.lzb.jvm.field; + +import me.lzb.jvm.constant.ConstantPool; + +/** + * Created by LZB on 2017/4/15. + */ +public class Field { + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private ConstantPool pool; + + public Field(int accessFlag, int nameIndex, int descriptorIndex ,ConstantPool pool) { + + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + this.pool = pool; + } + + + @Override + public String toString() { + String key = pool.getUTF8String(nameIndex); + String value = pool.getUTF8String(descriptorIndex); + return key + ":" + value; + } +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/loader/ClassFileLoader.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/loader/ClassFileLoader.java index 0dab6a3407..593694066d 100644 --- a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/loader/ClassFileLoader.java +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/loader/ClassFileLoader.java @@ -3,7 +3,6 @@ import me.lzb.common.utils.FileUtils; import me.lzb.jvm.clz.ClassFile; -import me.lzb.jvm.exception.NotClassFileException; import java.io.File; import java.io.IOException; @@ -12,51 +11,46 @@ import java.util.List; - public class ClassFileLoader { - private List<String> clzPaths = new ArrayList<>(); + private List<String> clzPaths = new ArrayList<>(); - public byte[] readBinaryCode(String className) throws IOException { + public byte[] readBinaryCode(String className) throws IOException { // String fileName = className.replaceAll(".*\\.", "") + ".class"; // String pkg = className.replaceAll("\\.[^\\.]+$", ""); // String packagePath = pkg.replaceAll("\\.", "\\\\"); - className = className.replace('.', File.separatorChar) +".class"; + className = className.replace('.', File.separatorChar) + ".class"; for (String s : clzPaths) { byte[] data = FileUtils.readByteCodes(s + className); - if(data != null){ + if (data != null) { return data; } } throw new IOException(className + "is not exist"); - } + } - public void addClassPath(String path) { + public void addClassPath(String path) { clzPaths.add(path); - } + } - public String getClassPath(){ + public String getClassPath() { StringBuilder buffer = new StringBuilder(); - for (Iterator<String> iterator = clzPaths.iterator(); iterator.hasNext();) { + for (Iterator<String> iterator = clzPaths.iterator(); iterator.hasNext(); ) { buffer.append(iterator.next() + (iterator.hasNext() ? ";" : "")); } return buffer.toString(); - } + } - public ClassFile loadClass(String className) throws IOException, NotClassFileException { + public ClassFile loadClass(String className) throws IOException { byte[] codes = this.readBinaryCode(className); ClassFileParser parser = new ClassFileParser(codes); return parser.parse(); } - - - - } diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/loader/ClassFileParser.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/loader/ClassFileParser.java index 2b99969f75..bfd3cbc2c0 100644 --- a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/loader/ClassFileParser.java +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/loader/ClassFileParser.java @@ -2,11 +2,13 @@ import me.lzb.common.utils.ByteUtils; import me.lzb.common.utils.StringUtils; +import me.lzb.jvm.attr.*; import me.lzb.jvm.clz.AccessFlag; import me.lzb.jvm.clz.ClassFile; import me.lzb.jvm.clz.ClassIndex; import me.lzb.jvm.constant.*; -import me.lzb.jvm.exception.NotClassFileException; +import me.lzb.jvm.field.Field; +import me.lzb.jvm.method.Method; import java.io.UnsupportedEncodingException; @@ -26,57 +28,60 @@ public ClassFileParser(byte[] data) { } - - public ClassFile parse() throws NotClassFileException{ + public ClassFile parse() { ClassFile classFile = new ClassFile(); - magicNumber(classFile); + parserMagicNumber(classFile); - if(!StringUtils.equals(classFile.getMagicNumber(), JvmConstant.MAGIC_NUMBER)){ - throw new NotClassFileException("It is not a java class file."); + if (!StringUtils.equals(classFile.getMagicNumber(), ConstantInfo.MAGIC_NUMBER)) { + throw new RuntimeException("It is not a java class file."); } - version(classFile); + parserVersion(classFile); + + parserConstantPool(classFile); + + parserAccessFlag(classFile); - constantPool(classFile); + parserClassIndex(classFile); - accessFlag(classFile); + parserInterface(classFile); - classIndex(classFile); + parserField(classFile); + + parserMethod(classFile); return classFile; } - - private byte[] nextBytes(int nextLength){ + private byte[] nextBytes(int nextLength) { byte[] target = new byte[nextLength]; System.arraycopy(data, index, target, 0, nextLength); index = index + nextLength; return target; } - private int nextBytesToInt(int nextLength){ + private int nextBytesToInt(int nextLength) { return ByteUtils.byteToInt(nextBytes(nextLength)); } - private String nextBytesToString(int nextLength){ + private String nextBytesToString(int nextLength) { return ByteUtils.byteToHexString(nextBytes(nextLength)); } - private void magicNumber(ClassFile classFile){ + private void parserMagicNumber(ClassFile classFile) { this.index = 0; classFile.setMagicNumber(nextBytesToString(4)); } - private void version(ClassFile classFile){ + private void parserVersion(ClassFile classFile) { classFile.setMinorVersion(nextBytesToInt(2)); classFile.setMajorVersion(nextBytesToInt(2)); } - private void constantPool(ClassFile classFile){ + private void parserConstantPool(ClassFile classFile) { int count = nextBytesToInt(2); - classFile.setConstantPoolCount(count); ConstantPool pool = new ConstantPool(); pool.addConstantInfo(new NullConstantInfo()); @@ -85,7 +90,7 @@ private void constantPool(ClassFile classFile){ int tag = nextBytesToInt(1); - if(tag == JvmConstant.Class_info){ + if (tag == ConstantInfo.Class_info) { ClassInfo classInfo = new ClassInfo(pool); classInfo.setUtf8Index(nextBytesToInt(2)); @@ -93,7 +98,7 @@ private void constantPool(ClassFile classFile){ continue; } - if(tag == JvmConstant.Fieldref_info){ + if (tag == ConstantInfo.Fieldref_info) { FieldRefInfo fieldRefInfo = new FieldRefInfo(pool); fieldRefInfo.setClassInfoIndex(nextBytesToInt(2)); fieldRefInfo.setNameAndTypeIndex(nextBytesToInt(2)); @@ -102,7 +107,7 @@ private void constantPool(ClassFile classFile){ continue; } - if(tag == JvmConstant.Methodref_info){ + if (tag == ConstantInfo.Methodref_info) { MethodRefInfo methodRefInfo = new MethodRefInfo(pool); methodRefInfo.setClassInfoIndex(nextBytesToInt(2)); methodRefInfo.setNameAndTypeIndex(nextBytesToInt(2)); @@ -111,7 +116,7 @@ private void constantPool(ClassFile classFile){ continue; } - if(tag == JvmConstant.NameAndType_info){ + if (tag == ConstantInfo.NameAndType_info) { NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(pool); nameAndTypeInfo.setIndex1(nextBytesToInt(2)); nameAndTypeInfo.setIndex2(nextBytesToInt(2)); @@ -120,7 +125,7 @@ private void constantPool(ClassFile classFile){ continue; } - if(tag == JvmConstant.String_info){ + if (tag == ConstantInfo.String_info) { StringInfo stringInfo = new StringInfo(pool); stringInfo.setIndex(nextBytesToInt(2)); @@ -128,7 +133,7 @@ private void constantPool(ClassFile classFile){ continue; } - if(tag == JvmConstant.Utf8_info){ + if (tag == ConstantInfo.Utf8_info) { UTF8Info utf8Info = new UTF8Info(pool); int len = nextBytesToInt(2); byte[] data = nextBytes(len); @@ -150,19 +155,17 @@ private void constantPool(ClassFile classFile){ } - classFile.setConstantPool(pool); } - - private void accessFlag(ClassFile classFile){ + private void parserAccessFlag(ClassFile classFile) { AccessFlag flag = new AccessFlag(nextBytesToInt(2)); classFile.setAccessFlag(flag); } - private void classIndex(ClassFile classFile){ + private void parserClassIndex(ClassFile classFile) { ClassIndex clzIndex = new ClassIndex(); int thisClassIndex = nextBytesToInt(2); @@ -173,5 +176,156 @@ private void classIndex(ClassFile classFile){ classFile.setClzIndex(clzIndex); } + private void parserInterface(ClassFile classFile) { + int count = nextBytesToInt(2); + //TODO 实现interface + } + + + private void parserField(ClassFile classFile) { + int count = nextBytesToInt(2); + for (int i = 1; i <= count; i++) { + int accessFlags = nextBytesToInt(2); + int nameIndex = nextBytesToInt(2); + int descriptorIndex = nextBytesToInt(2); + int attributesCount = nextBytesToInt(2); + + if (attributesCount > 0) { + throw new RuntimeException("Field Attribute has not been implement"); + } + + Field field = new Field(accessFlags, nameIndex, descriptorIndex, classFile.getConstantPool()); + classFile.addField(field); + } + } + + private void parserMethod(ClassFile classFile) { + int count = nextBytesToInt(2); + for (int i = 1; i <= count; i++) { + int accessFlags = nextBytesToInt(2); + int nameIndex = nextBytesToInt(2); + int descriptorIndex = nextBytesToInt(2); + int attributesCount = nextBytesToInt(2); + + + Method method = new Method(accessFlags, nameIndex, descriptorIndex); + + + for (int j = 1; j <= attributesCount; j++) { + + int attributeNameIndex = nextBytesToInt(2); + + String attributeName = classFile.getConstantPool().getUTF8String(attributeNameIndex); + + if (StringUtils.equalsIgnoreCase(attributeName, AttributeInfo.CODE)) { + parserCodeAttr(attributeNameIndex, method, classFile); + continue; + } + + + throw new RuntimeException("only CODE attribute is implemented."); + } + + classFile.addMethod(method); + + } + } + + + private void parserCodeAttr(int attributeNameIndex, Method method, ClassFile classFile) { + int attributeLength = nextBytesToInt(4); + int maxStack = nextBytesToInt(2); + int maxLocals = nextBytesToInt(2); + int codeLength = nextBytesToInt(4); + + String code = nextBytesToString(codeLength); + CodeAttr codeAttr = new CodeAttr(attributeNameIndex, attributeLength, maxStack, maxLocals, codeLength, code); + + int exceptionTableLength = nextBytesToInt(2); + if (exceptionTableLength > 0) { + String exceptionTable = nextBytesToString(exceptionTableLength); + //TODO 异常 + } + + + int subAttrCount = nextBytesToInt(2); + for (int k = 1; k <= subAttrCount; k++) { + int subAttrIndex = nextBytesToInt(2); + + String subAttrName = classFile.getConstantPool().getUTF8String(subAttrIndex); + + if (StringUtils.equalsIgnoreCase(subAttrName, AttributeInfo.LINE_NUM_TABLE)) { + + parserLineNumberTable(codeAttr, subAttrIndex); + continue; + } + + if (StringUtils.equalsIgnoreCase(subAttrName, AttributeInfo.LOCAL_VAR_TABLE)) { + parserLocalVariableTable(codeAttr, subAttrIndex); + continue; + } + + if (StringUtils.equalsIgnoreCase(subAttrName, AttributeInfo.STACK_MAP_TABLE)) { + parserStackMapTable(codeAttr, subAttrIndex); + continue; + } + + + throw new RuntimeException("Need code to process" + subAttrName); + } + + + method.setCodeAttr(codeAttr); + } + + + private void parserLineNumberTable(CodeAttr codeAttr, int attributeNameIndex) { +// int attributeNameIndex = nextBytesToInt(2); + int attributeLength = nextBytesToInt(4); + + int lineNumberTableLength = nextBytesToInt(2); + + LineNumberTable table = new LineNumberTable(attributeNameIndex, attributeLength); + + for (int l = 1; l <= lineNumberTableLength; l++) { + int startPc = nextBytesToInt(2); + int lineNumber = nextBytesToInt(2); + LineNumberItem item = new LineNumberItem(startPc, lineNumber); + table.addLineNumberItem(item); + } + + codeAttr.setLineNumTable(table); + } + + + private void parserLocalVariableTable(CodeAttr codeAttr, int attributeNameIndex) { +// int attributeNameIndex = nextBytesToInt(2); + int attributeLength = nextBytesToInt(4); + + int localVariableTableLength = nextBytesToInt(2); + + LocalVariableTable table = new LocalVariableTable(attributeNameIndex, attributeLength); + + for (int l = 1; l <= localVariableTableLength; l++) { + int startPc = nextBytesToInt(2); + int lineNumber = nextBytesToInt(2); + int nameIndex = nextBytesToInt(2); + int descriptorIndex = nextBytesToInt(2); + int index = nextBytesToInt(2); + LocalVariableItem item = new LocalVariableItem(startPc, lineNumber, nameIndex, descriptorIndex, index); + table.addLocalVariableItem(item); + } + + codeAttr.setLocalVarTable(table); + } + + private void parserStackMapTable(CodeAttr codeAttr, int attributeNameIndex) { +// int attributeNameIndex = nextBytesToInt(2); + int attributeLength = nextBytesToInt(4); + String code = nextBytesToString(attributeLength); + StackMapTable table = new StackMapTable(attributeNameIndex, attributeLength, code); + //后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 + codeAttr.setStackMapTable(table); + } } diff --git a/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/method/Method.java b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/method/Method.java new file mode 100644 index 0000000000..9c3e9ad984 --- /dev/null +++ b/group24/1148285693/learning2017/mini-jvm/src/main/java/me/lzb/jvm/method/Method.java @@ -0,0 +1,65 @@ +package me.lzb.jvm.method; + +import me.lzb.jvm.attr.CodeAttr; + +/** + * Created by LZB on 2017/4/15. + */ +public class Method { + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private CodeAttr codeAttr; + +// private ClassFile clzFile; + + + public Method(/*ClassFile clzFile,*/ int accessFlag, int nameIndex, int descriptorIndex) { +// this.clzFile = clzFile; + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + } + + + public int getAccessFlag() { + return accessFlag; + } + + public void setAccessFlag(int accessFlag) { + this.accessFlag = accessFlag; + } + + 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; + } + + public CodeAttr getCodeAttr() { + return codeAttr; + } + + public void setCodeAttr(CodeAttr codeAttr) { + this.codeAttr = codeAttr; + } + +// public ClassFile getClzFile() { +// return clzFile; +// } +// +// public void setClzFile(ClassFile clzFile) { +// this.clzFile = clzFile; +// } +} diff --git a/group24/1148285693/learning2017/mini-jvm/src/test/java/me/lzb/jvm/ClassFileloaderTest.java b/group24/1148285693/learning2017/mini-jvm/src/test/java/me/lzb/jvm/ClassFileloaderTest.java index 570462ef74..f41b313c97 100644 --- a/group24/1148285693/learning2017/mini-jvm/src/test/java/me/lzb/jvm/ClassFileloaderTest.java +++ b/group24/1148285693/learning2017/mini-jvm/src/test/java/me/lzb/jvm/ClassFileloaderTest.java @@ -4,14 +4,16 @@ import me.lzb.jvm.clz.ClassFile; import me.lzb.jvm.clz.ClassIndex; import me.lzb.jvm.constant.*; -import me.lzb.jvm.exception.NotClassFileException; +import me.lzb.jvm.field.Field; import me.lzb.jvm.loader.ClassFileLoader; +import me.lzb.jvm.method.Method; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import java.io.IOException; +import java.util.List; public class ClassFileloaderTest { @@ -88,6 +90,7 @@ public void testMagicNumber() throws Exception { static ClassFile clzFile = null; + static { ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); @@ -96,17 +99,13 @@ public void testMagicNumber() throws Exception { clzFile = loader.loadClass(className); } catch (IOException e) { e.printStackTrace(); - } catch (NotClassFileException e){ - e.printStackTrace(); } clzFile.print(); } - - @Test - public void testVersion(){ + public void testVersion() { Assert.assertEquals(0, clzFile.getMinorVersion()); Assert.assertEquals(52, clzFile.getMajorVersion()); @@ -114,7 +113,7 @@ public void testVersion(){ } @Test - public void testConstantPool(){ + public void testConstantPool() { ConstantPool pool = clzFile.getConstantPool(); @@ -159,7 +158,7 @@ public void testConstantPool(){ } { - MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(1); + MethodRefInfo methodRef = (MethodRefInfo) pool.getConstantInfo(1); Assert.assertEquals(11, methodRef.getClassInfoIndex()); Assert.assertEquals(36, methodRef.getNameAndTypeIndex()); } @@ -171,7 +170,7 @@ public void testConstantPool(){ } //抽查几个吧 { - MethodRefInfo methodRef = (MethodRefInfo)pool.getConstantInfo(10); + MethodRefInfo methodRef = (MethodRefInfo) pool.getConstantInfo(10); Assert.assertEquals(7, methodRef.getClassInfoIndex()); Assert.assertEquals(47, methodRef.getNameAndTypeIndex()); } @@ -181,12 +180,13 @@ public void testConstantPool(){ Assert.assertEquals("EmployeeV1.java", utf8Info.getValue()); } } + @Test - public void testClassIndex(){ + public void testClassIndex() { ClassIndex clzIndex = clzFile.getClzIndex(); - ClassInfo thisClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getThisClassIndex()); - ClassInfo superClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getSuperClassIndex()); + ClassInfo thisClassInfo = (ClassInfo) clzFile.getConstantPool().getConstantInfo(clzIndex.getThisClassIndex()); + ClassInfo superClassInfo = (ClassInfo) clzFile.getConstantPool().getConstantInfo(clzIndex.getSuperClassIndex()); Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); @@ -197,7 +197,7 @@ public void testClassIndex(){ * 下面是第三次JVM课应实现的测试用例 */ @Test - public void testReadFields(){ + public void testReadFields() { List<Field> fields = clzFile.getFields(); Assert.assertEquals(2, fields.size()); @@ -210,53 +210,54 @@ public void testReadFields(){ Assert.assertEquals("age:I", f.toString()); } } + @Test - public void testMethods(){ + public void testMethods() { List<Method> methods = clzFile.getMethods(); ConstantPool pool = clzFile.getConstantPool(); { Method m = methods.get(0); - assertMethodEquals(pool,m, + assertMethodEquals(pool, m, "<init>", "(Ljava/lang/String;I)V", - "2ab7000c2a2bb5000f2a1cb50011b1"); + "2ab700012a2bb500022a1cb50003b1"); } { Method m = methods.get(1); - assertMethodEquals(pool,m, + assertMethodEquals(pool, m, "setName", "(Ljava/lang/String;)V", - "2a2bb5000fb1"); + "2a2bb50002b1"); } { Method m = methods.get(2); - assertMethodEquals(pool,m, + assertMethodEquals(pool, m, "setAge", "(I)V", - "2a1bb50011b1"); + "2a1bb50003b1"); } { Method m = methods.get(3); - assertMethodEquals(pool,m, + assertMethodEquals(pool, m, "sayHello", "()V", - "b2001c1222b60024b1"); + "b200041205b60006b1"); } { Method m = methods.get(4); - assertMethodEquals(pool,m, + assertMethodEquals(pool, m, "main", "([Ljava/lang/String;)V", - "bb000159122b101db7002d4c2bb6002fb1"); + "bb0007591208101db700094c2bb6000ab1"); } } - private void assertMethodEquals(ConstantPool pool,Method m , String expectedName, String expectedDesc,String expectedCode){ + private void assertMethodEquals(ConstantPool pool, Method m, String expectedName, String expectedDesc, String expectedCode) { String methodName = pool.getUTF8String(m.getNameIndex()); String methodDesc = pool.getUTF8String(m.getDescriptorIndex()); String code = m.getCodeAttr().getCode(); diff --git a/group24/1148285693/learning2017/other/src/main/java/me/lzb/other/graph/Graph.java b/group24/1148285693/learning2017/other/src/main/java/me/lzb/other/graph/Graph.java new file mode 100644 index 0000000000..5ef6aba81a --- /dev/null +++ b/group24/1148285693/learning2017/other/src/main/java/me/lzb/other/graph/Graph.java @@ -0,0 +1,366 @@ +package me.lzb.other.graph; + +import java.util.*; + +/** + * 遍历无向图的所有最长一笔画 + * 深度优先,达到最深时,后退,继续搜索另一条路径 + * Created by LZB on 2017/4/8. + */ +public class Graph { + /** + * 换行符 + */ + private static final String NEWLINE = System.getProperty("line.separator"); + /** + * 路径分割符号 + */ + private static final String PATH_SEPARATOR = "->"; + + /** + * 顶点数目 + */ + private int vertexCount; + + /** + * 边的数目 + */ + private int edgeCount; + + /** + * 出现过路径的最长变数 + * 如果等于总边数,说明存在欧拉路径 + */ + int maxEdge = 0; + + /** + * 顶点数组,每个list是与顶点关联的所有边 + */ + private LinkedList<Edge>[] edgeList; + + /** + * 边 + */ + private class Edge { + /** + * 边的id + */ + int id; + + /** + * 是否被正向搜索 + */ + boolean isSearched; + + /** + * 顶点v + */ + int v; + + /** + * 顶点b + */ + int w; + + /** + * 保存回滚操作中,被回滚的的路径方向,以及,前提路径 + * 因为在不同级别的回滚中,可能会有多条临时路径,所以用list存放 + * 顶点->顶点:路径id->路径id->路径id + * 1->2:0->1->2 + */ + ArrayList<String> to = new ArrayList<>(); + + /** + * 构造函数 + * @param v 顶点v + * @param w 顶点w + */ + public Edge(int v, int w) { + this.v = v; + this.w = w; + isSearched = false; + id = edgeCount; + } + + + /** + * 在当前前提路径下,是否有 + * @param v0 出发顶点 + * @param P 前提路径 + * @return true false + */ + public boolean isFrom(int v0, String P) { + return isTheSameTo(v0, getAnotherV(v0), P); + } + + /** + * 临时路径是否相同 + * @param v0 出发顶点 + * @param v1 到达顶点 + * @param p 前提路径 + * @return true false + */ + public boolean isTheSameTo(int v0, int v1, String p) { + if (to.size() == 0) { + return false; + } + String ss = v0 + PATH_SEPARATOR + v1 + ":" + p; + for (String s : to) { + if (ss.equals(s)) { + return true; + } + } + return false; + } + + /** + * 删除临时路径 + * @param v0 出发顶点 + * @param v1 到达顶点 + * @param p 前提路径 + */ + public void removeTo(int v0, int v1, String p) { + if (to.size() == 0) { + return; + } + String ss = v0 + PATH_SEPARATOR + v1 + ":" + p; + for (Iterator<String> iterator = to.iterator(); iterator.hasNext(); ) { + String s = iterator.next(); + if (ss.equals(s)) { + iterator.remove(); + return; + } + } + } + + /** + * 增加临时路径 + * @param v0 出发顶点 + * @param v1 到达顶点 + * @param p 前提路径 + */ + public void addTo(int v0, int v1, String p) { + String ss = v0 + PATH_SEPARATOR + v1 + ":" + p; + for (String s : to) { + if (ss.equals(s)) { + return; + } + } + to.add(ss); + + } + + /** + * 获取边的另外一条顶点 + * @param vertex + * @return + */ + public int getAnotherV(int vertex) { + if (vertex == v) { + return w; + } else { + return v; + } + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + Edge c = (Edge) obj; + return this.id == c.id; + } + + @Override + public int hashCode() { + return id; + } + } + + /** + * 构造函数 + * @param vertexNum 顶点总数 + * @param edgeCount 边的总数 + */ + public Graph(int vertexNum, int edgeCount) { + this.vertexCount = vertexNum; + this.edgeCount = 0; + edgeList = new LinkedList[edgeCount]; + for (int i = 0; i < edgeCount; i++) { + edgeList[i] = new LinkedList<>(); + } + } + + public void addEdge(int v1, int v2) { + Edge c = new Edge(v2, v1); + edgeList[v1].add(c); + edgeList[v2].add(c); + edgeCount++; + } + + + public void addEdge(int[][] edgeArray) { + for (int i = 0; i < edgeArray.length; i++) { + addEdge(edgeArray[i][0], edgeArray[i][1]); + } + } + + public String toString() { + StringBuilder s = new StringBuilder(); + s.append(vertexCount + " vertices, " + edgeCount + " edges " + NEWLINE); + for (int v = 0; v < vertexCount; v++) { + s.append(v + ": "); + for (Edge w : edgeList[v]) { + s.append(w.getAnotherV(v) + " "); + } + s.append(NEWLINE); + } + return s.toString(); + } + + + /** + * 更新出现过路径的最长边数 + * @param a + */ + private void updateMax(int a) { + if (a > maxEdge) { + maxEdge = a; + } + } + + + public boolean isEuler() { + int start = 0; + Stack<Integer> stack = new Stack<>(); + stack.push(start); + + //TODO 退出递归的条件 +// try { + search(start, start, stack, new Stack<>()); +// }catch (EmptyStackException e){ + +// } + + System.out.println("最长边数:" + maxEdge); + return maxEdge == edgeCount; + } + + + + + /** + * 正向搜索 + * 传进去一个节点,顺着一条没有搜索过的边找到下一个节点。当搜索到死路时,回滚 + * @param v 当前提点 + * @param stack 当前路径的节点顺序 + * @param sp 当前路径的路径顺序 + */ + public void search(int start, int v, Stack<Integer> stack, Stack<Edge> sp) { + + LinkedList<Edge> list = edgeList[v]; + + boolean anotherWay = false; + for (Edge w : list) { + if (!w.isSearched && !w.isTheSameTo(v, w.getAnotherV(v), getPath(sp))) { + anotherWay = true; + w.isSearched = true; + stack.push(w.getAnotherV(v)); + updateMax(sp.size()); + sp.push(w); + search(start, w.getAnotherV(v), stack, sp); + } + } + + if (!anotherWay) { + System.out.println("最长:==============================="); + rollback(start, stack, sp); + } + + } + + + + /** + * 回滚,回滚当上一个节点,如果当前节点有可以使用的边,调用搜索,如果没有,递归继续回滚 + * 如果需要递归回滚,回滚到第二级之前,清空所有,当前路径下,从该点出发的方向 + * 被回滚的路径,需要保存路径方向,以及提前路径 + * @param stack 当前路径的节点顺序 + * @param sp 当前路径的路径顺序 + */ + public void rollback(int start, Stack<Integer> stack, Stack<Edge> sp) { + + String ss = getPath(sp); + String output = "顶点:" + stack.toString() + + NEWLINE + "路径:" + ss + + NEWLINE; + System.out.println(output); + +// if(stack.size() == 1){ +// return; +// } + + + Edge e = sp.pop(); //需要回滚的路径 + String pp = getPath(sp); //前提路径 + + int vz = stack.pop(); + int vy = stack.peek(); + + boolean rollbakc2 = true; + + LinkedList<Edge> l = edgeList[vy]; + + //判断当前节点是否存在空闲路径,是否要回滚两级 + //空闲路径:没有被正向搜索,也没有被缓存当前前提路径下,从改节点出发的方向 + for (Edge w : l) { + if (!w.isSearched && !w.isTheSameTo(vy, w.getAnotherV(vy), pp)) { + rollbakc2 = false; + break; + } + } + + + //回滚当前路径,回滚一级 + int r = vy; + for (Edge w : l) { + if (w.equals(e)) { + w.addTo(vy, vz, pp); + w.isSearched = false; + break; + } + } + + if (rollbakc2) { + //回滚两级, 清空所有,当前路径下,从该点出发的方向 + + for (Edge w : l) { + if (!w.isSearched && w.isFrom(vy, pp)) { + w.removeTo(vy, w.getAnotherV(vy), pp); + } + } + rollback(start, stack, sp); + } + + search(start, r, stack, sp); + + } + + public String getPath(Stack<Edge> stack) { + String s = ""; + for (Edge x : stack) { + s = s + x.id + PATH_SEPARATOR; + } + s = s.replaceAll(PATH_SEPARATOR + "$", ""); + return s; + } + + + public static void main(String[] args) { + int[][] aa = new int[][]{{0, 1}, {0, 1}, {0, 3}, {1, 3}, {1, 2}, {1, 2}, {2, 3}}; + Graph g = new Graph(4, aa.length); + g.addEdge(aa); + System.out.println(g.toString()); + System.out.println(g.isEuler()); + } +} diff --git a/group24/1148285693/learning2017/other/src/main/java/me/lzb/other/lock/ReentrantTest1.java b/group24/1148285693/learning2017/other/src/main/java/me/lzb/other/lock/ReentrantTest1.java new file mode 100644 index 0000000000..4b8b3d4ce8 --- /dev/null +++ b/group24/1148285693/learning2017/other/src/main/java/me/lzb/other/lock/ReentrantTest1.java @@ -0,0 +1,27 @@ +package me.lzb.other.lock; + +/** + * Created by LZB on 2017/3/30. + */ +public class ReentrantTest1 implements Runnable{ + + public synchronized void get(){ + System.out.println(Thread.currentThread().getId()); + set(); + } + + public synchronized void set(){ + System.out.println(Thread.currentThread().getId()); + } + + @Override + public void run() { + get(); + } + public static void main(String[] args) { + ReentrantTest1 ss=new ReentrantTest1(); + new Thread(ss).start(); + new Thread(ss).start(); + new Thread(ss).start(); + } +} \ No newline at end of file diff --git a/group24/1148285693/learning2017/other/src/main/java/me/lzb/other/lock/ReentrantTest2.java b/group24/1148285693/learning2017/other/src/main/java/me/lzb/other/lock/ReentrantTest2.java new file mode 100644 index 0000000000..c630ea9e33 --- /dev/null +++ b/group24/1148285693/learning2017/other/src/main/java/me/lzb/other/lock/ReentrantTest2.java @@ -0,0 +1,35 @@ +package me.lzb.other.lock; + +import java.util.concurrent.locks.ReentrantLock; + +/** + * Created by LZB on 2017/3/30. + */ +public class ReentrantTest2 implements Runnable { + ReentrantLock lock = new ReentrantLock(); + + public void get() { + lock.lock(); + System.out.println(Thread.currentThread().getId()); + set(); + lock.unlock(); + } + + public void set() { + lock.lock(); + System.out.println(Thread.currentThread().getId()); + lock.unlock(); + } + + @Override + public void run() { + get(); + } + + public static void main(String[] args) { + ReentrantTest2 ss = new ReentrantTest2(); + new Thread(ss).start(); + new Thread(ss).start(); + new Thread(ss).start(); + } +} \ No newline at end of file diff --git a/group24/1148285693/learning2017/other/src/main/java/me/lzb/other/proxy/MyInvocationHandler.java b/group24/1148285693/learning2017/other/src/main/java/me/lzb/other/proxy/MyInvocationHandler.java new file mode 100644 index 0000000000..d89298c786 --- /dev/null +++ b/group24/1148285693/learning2017/other/src/main/java/me/lzb/other/proxy/MyInvocationHandler.java @@ -0,0 +1,52 @@ +package me.lzb.other.proxy; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +/** + * Created by LZB on 2017/3/29. + */ +public class MyInvocationHandler implements InvocationHandler { + + // 目标对象 + private Object target; + + /** + * 构造方法 + * + * @param target 目标对象 + */ + public MyInvocationHandler(Object target) { + super(); + this.target = target; + } + + + /** + * 执行目标对象的方法 + */ + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + + // 在目标对象的方法执行之前简单的打印一下 + System.out.println("------------------before------------------"); + + // 执行目标对象的方法 + Object result = method.invoke(target, args); + + // 在目标对象的方法执行之后简单的打印一下 + System.out.println("-------------------after------------------"); + + return result; + } + + /** + * 获取目标对象的代理对象 + * + * @return 代理对象 + */ + public Object getProxy() { + return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), + target.getClass().getInterfaces(), this); + } +} diff --git a/group24/1148285693/learning2017/other/src/main/java/me/lzb/other/proxy/UserService.java b/group24/1148285693/learning2017/other/src/main/java/me/lzb/other/proxy/UserService.java new file mode 100644 index 0000000000..d57431acab --- /dev/null +++ b/group24/1148285693/learning2017/other/src/main/java/me/lzb/other/proxy/UserService.java @@ -0,0 +1,11 @@ +package me.lzb.other.proxy; + +/** + * Created by LZB on 2017/3/29. + */ +public interface UserService { + /** + * 目标方法 + */ + void add(); +} diff --git a/group24/1148285693/learning2017/other/src/main/java/me/lzb/other/proxy/UserServiceImpl.java b/group24/1148285693/learning2017/other/src/main/java/me/lzb/other/proxy/UserServiceImpl.java new file mode 100644 index 0000000000..614b60d9c9 --- /dev/null +++ b/group24/1148285693/learning2017/other/src/main/java/me/lzb/other/proxy/UserServiceImpl.java @@ -0,0 +1,11 @@ +package me.lzb.other.proxy; + +/** + * Created by LZB on 2017/3/29. + */ +public class UserServiceImpl implements UserService { + + public void add() { + System.out.println("--------------------add---------------"); + } +} \ No newline at end of file diff --git a/group24/1148285693/learning2017/other/src/test/java/me/lzb/other/proxy/ProxyTest.java b/group24/1148285693/learning2017/other/src/test/java/me/lzb/other/proxy/ProxyTest.java new file mode 100644 index 0000000000..0a01679ad3 --- /dev/null +++ b/group24/1148285693/learning2017/other/src/test/java/me/lzb/other/proxy/ProxyTest.java @@ -0,0 +1,25 @@ +package me.lzb.other.proxy; + +import org.junit.Test; + +/** + * Created by LZB on 2017/3/29. + */ +public class ProxyTest { + + @Test + public void testProxy() throws Throwable { + // 实例化目标对象 + UserService userService = new UserServiceImpl(); + + // 实例化InvocationHandler + MyInvocationHandler invocationHandler = new MyInvocationHandler(userService); + + // 根据目标对象生成代理对象 + UserService proxy = (UserService) invocationHandler.getProxy(); + + // 调用代理对象的方法 + proxy.add(); + + } +} From 0c6bc489bd518de5fe087c3009d41a6db6d19256 Mon Sep 17 00:00:00 2001 From: Korben_CHY <korben.chy@gmail.com> Date: Sun, 16 Apr 2017 10:26:55 +0800 Subject: [PATCH 267/287] submit "InfixExpr" and "MiniJvm" by Korben --- .../coderising/download/DownloadThread.java | 2 +- .../download/FileDownloaderTest.java | 3 +- .../download/impl/ConnectionManagerImpl.java | 6 +- .../com/coding/basic/stack/StackUtilTest.java | 1 - .../coding/basic/stack/expr/InfixExpr.java | 103 +++++++ .../basic/stack/expr/InfixExprTest.java | 44 +++ .../coderising/jvm/attr/AttributeInfo.java | 18 ++ .../src/com/coderising/jvm/attr/CodeAttr.java | 86 ++++++ .../coderising/jvm/attr/LineNumberTable.java | 55 ++++ .../jvm/attr/LocalVariableItem.java | 49 ++++ .../jvm/attr/LocalVariableTable.java | 37 +++ .../coderising/jvm/attr/StackMapTable.java | 28 ++ .../src/com/coderising/jvm/clz/ClassFile.java | 172 +++++++----- .../coderising/jvm/constant/ConstantPool.java | 1 + .../src/com/coderising/jvm/field/Field.java | 45 +++ .../jvm/loader/ByteCodeIterator.java | 98 ++++--- .../jvm/loader/ClassFileParser.java | 258 ++++++++++-------- .../src/com/coderising/jvm/method/Method.java | 73 +++++ .../jvm/test/ClassFileloaderTest.java | 76 +++++- 19 files changed, 916 insertions(+), 239 deletions(-) create mode 100644 group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/expr/InfixExpr.java create mode 100644 group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/expr/InfixExprTest.java create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/attr/AttributeInfo.java create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/attr/LocalVariableItem.java create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/attr/StackMapTable.java create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/field/Field.java create mode 100644 group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/method/Method.java diff --git a/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/DownloadThread.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/DownloadThread.java index 93f163a44e..031c966086 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/DownloadThread.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/DownloadThread.java @@ -2,10 +2,10 @@ 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 java.io.IOException; import java.io.RandomAccessFile; -import com.coderising.download.api.ConnectionManager; public class DownloadThread extends Thread { diff --git a/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/FileDownloaderTest.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/FileDownloaderTest.java index 3e0a91b573..404e55594f 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/FileDownloaderTest.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/FileDownloaderTest.java @@ -22,7 +22,8 @@ public void tearDown() throws Exception { @Test public void testDownload() { - String url = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1489721424&di=1fda6467501ab1d5e5bff43e801d14ee&imgtype=jpg&er=1&src=http%3A%2F%2Fimg4.duitang.com%2Fuploads%2Fitem%2F201507%2F30%2F20150730163204_A24MX.thumb.700_0.jpeg"; + String url = + "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1489721424&di=1fda6467501ab1d5e5bff43e801d14ee&imgtype=jpg&er=1&src=http%3A%2F%2Fimg4.duitang.com%2Fuploads%2Fitem%2F201507%2F30%2F20150730163204_A24MX.thumb.700_0.jpeg"; //String url = "http://apache.fayea.com/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.tar.gz"; FileDownloader downloader = new FileDownloader(url); diff --git a/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/impl/ConnectionManagerImpl.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/impl/ConnectionManagerImpl.java index 29919834fa..c3ad775b11 100644 --- a/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/impl/ConnectionManagerImpl.java +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coderising/download/impl/ConnectionManagerImpl.java @@ -1,11 +1,11 @@ package com.coderising.download.impl; -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URL; import com.coderising.download.api.Connection; import com.coderising.download.api.ConnectionException; import com.coderising.download.api.ConnectionManager; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; public class ConnectionManagerImpl implements ConnectionManager { 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 index 77bffbf32b..845a53b826 100644 --- 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 @@ -77,6 +77,5 @@ public void isValidPairs() throws Exception { String str = "([b{x]y})"; Assert.assertFalse(StackUtil.isValidPairs(str)); } - } } \ No newline at end of file diff --git a/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/expr/InfixExpr.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/expr/InfixExpr.java new file mode 100644 index 0000000000..7efc063bba --- /dev/null +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/expr/InfixExpr.java @@ -0,0 +1,103 @@ +package com.coding.basic.stack.expr; + +import com.coding.basic.stack.Stack; +import java.util.Arrays; + +public class InfixExpr { + String expr = null; + + public InfixExpr(String expr) { + this.expr = expr; + } + + public static void main(String[] args) { + String[] ss = new InfixExpr("3*20+12*5-40/2").getOperatorsAndNumbers("3*20+12*5-40/2"); + System.out.println(Arrays.toString(ss)); + } + + /** + * 根据输入的表达式,计算结果 + * 只支持 +、-、*、/,不支持括号 + * 数值只支持整数 + * + * @return 计算结果 + */ + public float evaluate() { + if (expr == null) { + throw new NullPointerException("expr can't be null!"); + } + + Stack<String> operators = new Stack<>(); + Stack<Number> nums = new Stack<>(); + + String[] operatorsAndNumbers = getOperatorsAndNumbers(expr); + + for (int i = 0; i < operatorsAndNumbers.length; i++) { + String data = operatorsAndNumbers[i]; + if ("+".equals(data) || "-".equals(data)) { + operators.push(data); + } + // "*" 的优先级最高,遇到 "*" 直接进行计算 + else if ("*".equals(data)) { + nums.push(nums.pop().floatValue() * Integer.valueOf(operatorsAndNumbers[++i])); + } + // "/" 的优先级最高,遇到 "/" 直接进行计算 + else if ("/".equals(data)) { + nums.push(nums.pop().floatValue() / Integer.valueOf(operatorsAndNumbers[++i])); + } + // 如果是数值,判断数值下一位的操作符,如果是 "+" 或 "-", + // 则优先级不高于堆栈中存储的操作符,取出堆栈中的进行计算 + else { + if ((i + 1 < operatorsAndNumbers.length && !nums.isEmpty()) + && + ("+".equals(operatorsAndNumbers[i + 1]) || "-".equals(operatorsAndNumbers[i + 1])) + ) { + String operator = operators.pop(); + float rightValue = Integer.valueOf(data); + float leftValue = nums.pop().floatValue(); + + if ("+".equals(operator)) { + nums.push(leftValue + rightValue); + } else { + nums.push(leftValue - rightValue); + } + } else { + try { + nums.push(Integer.valueOf(data)); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("表达式不合法!"); + } + } + } + } + + if (!operators.isEmpty()) { + String operator = operators.pop(); + float rightValue = nums.pop().floatValue(); + float leftValue = nums.pop().floatValue(); + + if ("+".equals(operator)) { + nums.push(leftValue + rightValue); + } else { + nums.push(leftValue - rightValue); + } + } + + return nums.pop().floatValue(); + } + + private String[] getOperatorsAndNumbers(String expr) { + String[] numberArray = expr.split("\\+|-|\\*|/"); + String[] operatorsArray = expr.split("[0-9]+"); + + String[] operatorsAndNumbers = new String[operatorsArray.length + numberArray.length - 1]; + for (int i = 1; i < operatorsArray.length; i++) { + operatorsAndNumbers[2 * i - 1] = operatorsArray[i]; + } + for (int i = 0; i < numberArray.length; i++) { + operatorsAndNumbers[2 * i] = numberArray[i]; + } + + return operatorsAndNumbers; + } +} diff --git a/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/expr/InfixExprTest.java b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/expr/InfixExprTest.java new file mode 100644 index 0000000000..77768b3847 --- /dev/null +++ b/group20/1107837739/1107837739Learning/data-structure/src/com/coding/basic/stack/expr/InfixExprTest.java @@ -0,0 +1,44 @@ +package com.coding.basic.stack.expr; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class InfixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + { + InfixExpr expr = new InfixExpr("2+3*4+5"); + Assert.assertEquals(19.0, expr.evaluate(), 0.001f); + } + { + InfixExpr expr = new InfixExpr("3*20+12*5-40/2"); + Assert.assertEquals(100.0, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("3*20/2"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("20/2*3"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("10-30+50"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + } +} diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/attr/AttributeInfo.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/attr/AttributeInfo.java new file mode 100644 index 0000000000..1edbad5321 --- /dev/null +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/attr/AttributeInfo.java @@ -0,0 +1,18 @@ +package com.coderising.jvm.attr; + +public abstract class AttributeInfo { + public static final String CODE = "Code"; + public static final String CONST_VALUE = "ConstantValue"; + public static final String EXCEPTIONS = "Exceptions"; + public static final String LINE_NUM_TABLE = "LineNumberTable"; + public static final String LOCAL_VAR_TABLE = "LocalVariableTable"; + public static final String STACK_MAP_TABLE = "StackMapTable"; + int attrNameIndex; + int attrLen; + + public AttributeInfo(int attrNameIndex, int attrLen) { + + this.attrNameIndex = attrNameIndex; + this.attrLen = attrLen; + } +} diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java new file mode 100644 index 0000000000..8876114724 --- /dev/null +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java @@ -0,0 +1,86 @@ +package com.coderising.jvm.attr; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.loader.ByteCodeIterator; + +public class CodeAttr extends AttributeInfo { + private int maxStack; + private int maxLocals; + private int codeLen; + private String code; + //private ByteCodeCommand[] cmds ; + //public ByteCodeCommand[] getCmds() { + // return cmds; + //} + private LineNumberTable lineNumTable; + private LocalVariableTable localVarTable; + private StackMapTable stackMapTable; + + public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen, String code /*ByteCodeCommand[] cmds*/) { + super(attrNameIndex, attrLen); + this.maxStack = maxStack; + this.maxLocals = maxLocals; + this.codeLen = codeLen; + this.code = code; + //this.cmds = cmds; + } + + public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter) { + int attrNameIndex = iter.nextU2ToInt(); + int attrLen = iter.nextU4ToInt(); + int maxStack = iter.nextU2ToInt(); + int maxLocals = iter.nextU2ToInt(); + int codeLen = iter.nextU4ToInt(); + + String code = iter.nextUxToHexString(codeLen); + System.out.println("Code: " + code); + + CodeAttr codeAttr = new CodeAttr(attrNameIndex, attrLen, maxStack, maxLocals, codeLen, code); + + int exceptionCodeLen = iter.nextU2ToInt(); + if (exceptionCodeLen > 0) { + String exTable = iter.nextUxToHexString(exceptionCodeLen); + System.out.println("Encountered exception table, just ignore it"); + } + + int subAttrCount = iter.nextU2ToInt(); + + for (int i = 0; i < subAttrCount; i++) { + int subAttrIndex = iter.nextU2ToInt(); + String subAttrName = clzFile.getConstantPool().getUTF8String(subAttrIndex); + + iter.back(2); + + if (AttributeInfo.LINE_NUM_TABLE.equalsIgnoreCase(subAttrName)) { + LineNumberTable t = LineNumberTable.parse(iter); + codeAttr.setLineNumberTable(t); + } else if (AttributeInfo.LOCAL_VAR_TABLE.equalsIgnoreCase(subAttrName)) { + LocalVariableTable t = LocalVariableTable.parse(iter); + codeAttr.setLocalVariableTable(t); + } else if (AttributeInfo.STACK_MAP_TABLE.equalsIgnoreCase(subAttrName)) { + StackMapTable t = StackMapTable.parse(iter); + codeAttr.setStackMapTable(t); + } else { + throw new RuntimeException(subAttrName + " hasn't been implemented yet"); + } + } + + return codeAttr; + } + + public String getCode() { + return code; + } + + public void setLineNumberTable(LineNumberTable t) { + this.lineNumTable = t; + } + + public void setLocalVariableTable(LocalVariableTable t) { + this.localVarTable = t; + } + + private void setStackMapTable(StackMapTable t) { + this.stackMapTable = t; + } +} diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java new file mode 100644 index 0000000000..fa037d407f --- /dev/null +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java @@ -0,0 +1,55 @@ +package com.coderising.jvm.attr; + +import com.coderising.jvm.loader.ByteCodeIterator; +import java.util.ArrayList; +import java.util.List; + +public class LineNumberTable extends AttributeInfo { + List<LineNumberItem> items = new ArrayList<LineNumberItem>(); + + public LineNumberTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static LineNumberTable parse(ByteCodeIterator iter) { + int attributeNameIndex = iter.nextU2ToInt(); + int attributeLen = iter.nextU4ToInt(); + int itemLen = iter.nextU2ToInt(); + + LineNumberTable numberTable = new LineNumberTable(attributeNameIndex, attributeLen); + + for (int i = 0; i < itemLen; i++) { + LineNumberItem item = new LineNumberItem(); + item.setStartPC(iter.nextU2ToInt()); + item.setLineNum(iter.nextU2ToInt()); + + numberTable.addLineNumberItem(item); + } + return numberTable; + } + + public void addLineNumberItem(LineNumberItem item) { + this.items.add(item); + } + + private static class LineNumberItem { + int startPC; + int lineNum; + + public int getStartPC() { + return startPC; + } + + public void setStartPC(int startPC) { + this.startPC = startPC; + } + + public int getLineNum() { + return lineNum; + } + + public void setLineNum(int lineNum) { + this.lineNum = lineNum; + } + } +} diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/attr/LocalVariableItem.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/attr/LocalVariableItem.java new file mode 100644 index 0000000000..224858246a --- /dev/null +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/attr/LocalVariableItem.java @@ -0,0 +1,49 @@ +package com.coderising.jvm.attr; + +public class LocalVariableItem { + private int startPC; + private int length; + private int nameIndex; + private int descIndex; + private int index; + + public int getStartPC() { + return startPC; + } + + public void setStartPC(int startPC) { + this.startPC = startPC; + } + + public int getLength() { + return length; + } + + public void setLength(int length) { + this.length = length; + } + + public int getNameIndex() { + return nameIndex; + } + + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + + public int getDescIndex() { + return descIndex; + } + + public void setDescIndex(int descIndex) { + this.descIndex = descIndex; + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } +} diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java new file mode 100644 index 0000000000..93cbe31c82 --- /dev/null +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java @@ -0,0 +1,37 @@ +package com.coderising.jvm.attr; + +import com.coderising.jvm.loader.ByteCodeIterator; +import java.util.ArrayList; +import java.util.List; + +public class LocalVariableTable extends AttributeInfo { + + List<LocalVariableItem> items = new ArrayList<LocalVariableItem>(); + + public LocalVariableTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static LocalVariableTable parse(ByteCodeIterator iter) { + int attributeNameIndex = iter.nextU2ToInt(); + int attributeLen = iter.nextU4ToInt(); + int itemLen = iter.nextU2ToInt(); + + LocalVariableTable variableTable = new LocalVariableTable(attributeNameIndex, attributeLen); + for (int i = 0; i < itemLen; i++) { + LocalVariableItem item = new LocalVariableItem(); + item.setStartPC(iter.nextU2ToInt()); + item.setLength(iter.nextU2ToInt()); + item.setNameIndex(iter.nextU2ToInt()); + item.setDescIndex(iter.nextU2ToInt()); + item.setIndex(iter.nextU2ToInt()); + + variableTable.addLocalVariableItem(item); + } + return variableTable; + } + + private void addLocalVariableItem(LocalVariableItem item) { + this.items.add(item); + } +} diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/attr/StackMapTable.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/attr/StackMapTable.java new file mode 100644 index 0000000000..9f838584fd --- /dev/null +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/attr/StackMapTable.java @@ -0,0 +1,28 @@ +package com.coderising.jvm.attr; + +import com.coderising.jvm.loader.ByteCodeIterator; + +public class StackMapTable extends AttributeInfo { + + private String originalCode; + + public StackMapTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static StackMapTable parse(ByteCodeIterator iter) { + int index = iter.nextU2ToInt(); + int len = iter.nextU4ToInt(); + StackMapTable t = new StackMapTable(index, len); + + //后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 + String code = iter.nextUxToHexString(len); + t.setOriginalCode(code); + + return t; + } + + private void setOriginalCode(String code) { + this.originalCode = code; + } +} diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java index cc23a7799d..a56d8793dc 100644 --- a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java @@ -1,75 +1,97 @@ -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(); - } -} +package com.coderising.jvm.clz; + +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.field.Field; +import com.coderising.jvm.method.Method; +import java.util.ArrayList; +import java.util.List; + +public class ClassFile { + + private int minorVersion; + private int majorVersion; + + private AccessFlag accessFlag; + private ClassIndex clzIndex; + private ConstantPool pool; + private List<Field> fields = new ArrayList<Field>(); + private List<Method> methods = new ArrayList<Method>(); + + 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 addField(Field f) { + this.fields.add(f); + } + + public List<Field> getFields() { + return this.fields; + } + + public void addMethod(Method m) { + this.methods.add(m); + } + + public List<Method> getMethods() { + return methods; + } + + 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/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/ConstantPool.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/ConstantPool.java index b44e7fef74..1f65ae0d0c 100644 --- a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/ConstantPool.java +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/constant/ConstantPool.java @@ -12,6 +12,7 @@ public ConstantPool() { } public void addConstantInfo(ConstantInfo info) { + this.constantInfos.add(info); } diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/field/Field.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/field/Field.java new file mode 100644 index 0000000000..c52202ee69 --- /dev/null +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/field/Field.java @@ -0,0 +1,45 @@ +package com.coderising.jvm.field; + +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.loader.ByteCodeIterator; + +public class Field { + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private ConstantPool pool; + + public Field(int accessFlag, int nameIndex, int descriptorIndex, ConstantPool pool) { + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + this.pool = pool; + } + + public static Field parse(ConstantPool pool, ByteCodeIterator iter) { + int accessFlag = iter.nextU2ToInt(); + int nameIndex = iter.nextU2ToInt(); + int descriptorIndex = iter.nextU2ToInt(); + int attributeCount = iter.nextU2ToInt(); + + System.out.println("Filed accessFlag: " + accessFlag); + System.out.println("Filed nameIndex: " + nameIndex); + System.out.println("Filed descriptorIndex: " + descriptorIndex); + System.out.println("Filed attributeCount: " + attributeCount); + + if (attributeCount > 0) { + throw new RuntimeException("Filed attribute hasn't been implemented yet"); + } + + return new Field(accessFlag, nameIndex, descriptorIndex, pool); + } + + @Override + public String toString() { + String name = pool.getUTF8String(this.nameIndex); + String desc = pool.getUTF8String(this.descriptorIndex); + + return name + ":" + desc; + } +} 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 index 35a6a8b207..2667b40753 100644 --- 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 @@ -1,45 +1,53 @@ -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; - } -} +package com.coderising.jvm.loader; + +import com.coderising.jvm.util.Util; +import java.util.Arrays; + +public class ByteCodeIterator { + byte[] codes; + int pos = 0; + + ByteCodeIterator(byte[] codes) { + this.codes = codes; + } + + 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; + } + + 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 nextUxToHexString(int len) { + byte[] tmp = new byte[len]; + + for (int i = 0; i < len; i++) { + tmp[i] = codes[pos++]; + } + return Util.byteToHexString(tmp).toLowerCase(); + } + + public void back(int n) { + this.pos -= n; + } +} 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 index 8ac21a8870..78b419c23f 100644 --- 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 @@ -1,112 +1,146 @@ -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; - } -} +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 com.coderising.jvm.field.Field; +import com.coderising.jvm.method.Method; +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)); + + parseInterfaces(classFile, iterator); + + parseFields(classFile, iterator); + + parseMethods(classFile, 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; + } + + private void parseInterfaces(ClassFile clzFile, ByteCodeIterator iter) { + int interfaceCount = iter.nextU2ToInt(); + + System.out.println("Interface Count: " + interfaceCount); + } + + private void parseFields(ClassFile clzFile, ByteCodeIterator iter) { + int filedCount = iter.nextU2ToInt(); + System.out.println("Field Count: " + filedCount); + + for (int i = 0; i < filedCount; i++) { + Field field = Field.parse(clzFile.getConstantPool(), iter); + clzFile.addField(field); + } + } + + private void parseMethods(ClassFile clzFile, ByteCodeIterator iter) { + int methodCount = iter.nextU2ToInt(); + System.out.println("Method Count: " + methodCount); + + for (int i = 0; i < methodCount; i++) { + Method method = Method.parse(clzFile, iter); + clzFile.addMethod(method); + } + } +} diff --git a/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/method/Method.java b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/method/Method.java new file mode 100644 index 0000000000..bc3d9a843a --- /dev/null +++ b/group20/1107837739/1107837739Learning/mini-jvm/src/com/coderising/jvm/method/Method.java @@ -0,0 +1,73 @@ +package com.coderising.jvm.method; + +import com.coderising.jvm.attr.AttributeInfo; +import com.coderising.jvm.attr.CodeAttr; +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.loader.ByteCodeIterator; + +public class Method { + + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private CodeAttr codeAttr; + + private ClassFile clzFile; + + public Method(ClassFile clzFile, int accessFlag, int nameIndex, int descriptorIndex) { + this.clzFile = clzFile; + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + } + + public static Method parse(ClassFile clzFile, ByteCodeIterator iter) { + int accessFlag = iter.nextU2ToInt(); + int nameIndex = iter.nextU2ToInt(); + int descriptorIndex = iter.nextU2ToInt(); + int attributeCount = iter.nextU2ToInt(); + + System.out.println("Filed accessFlag: " + accessFlag); + System.out.println("Filed nameIndex: " + nameIndex); + System.out.println("Filed descriptorIndex: " + descriptorIndex); + System.out.println("Filed attributeCount: " + attributeCount); + + Method method = new Method(clzFile, accessFlag, nameIndex, descriptorIndex); + + for (int i = 0; i < attributeCount; i++) { + int attrNameIndex = iter.nextU2ToInt(); + String attrName = clzFile.getConstantPool().getUTF8String(attrNameIndex); + iter.back(2); + + if (AttributeInfo.CODE.equalsIgnoreCase(attrName)) { + CodeAttr codeAttr = CodeAttr.parse(clzFile, iter); + method.setCodeAttr(codeAttr); + } else { + throw new RuntimeException("Only CODE attribute is implemented!"); + } + } + + return method; + } + + public ClassFile getClzFile() { + return clzFile; + } + + public int getNameIndex() { + return nameIndex; + } + + public int getDescriptorIndex() { + return descriptorIndex; + } + + public CodeAttr getCodeAttr() { + return codeAttr; + } + + public void setCodeAttr(CodeAttr code) { + this.codeAttr = code; + } +} 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 d033dfe252..e92c5580ac 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 @@ -7,7 +7,10 @@ import com.coderising.jvm.constant.MethodRefInfo; import com.coderising.jvm.constant.NameAndTypeInfo; import com.coderising.jvm.constant.UTF8Info; +import com.coderising.jvm.field.Field; import com.coderising.jvm.loader.ClassFileLoader; +import com.coderising.jvm.method.Method; +import java.util.List; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -17,7 +20,7 @@ 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 path1 = "/Users/Korben/Downloads"; static String path2 = "C:\temp"; static ClassFile clzFile = null; @@ -181,4 +184,75 @@ public void testClassIndex() { Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); } + + /** + * 下面是第三次JVM课应实现的测试用例 + */ + @Test + public void testReadFields() { + + List<Field> fields = clzFile.getFields(); + Assert.assertEquals(2, fields.size()); + { + Field f = fields.get(0); + Assert.assertEquals("name:Ljava/lang/String;", f.toString()); + } + { + Field f = fields.get(1); + Assert.assertEquals("age:I", f.toString()); + } + } + + @Test + public void testMethods() { + + List<Method> methods = clzFile.getMethods(); + ConstantPool pool = clzFile.getConstantPool(); + + { + Method m = methods.get(0); + assertMethodEquals(pool, m, + "<init>", + "(Ljava/lang/String;I)V", + "2ab7000c2a2bb5000f2a1cb50011b1"); + } + { + Method m = methods.get(1); + assertMethodEquals(pool, m, + "setName", + "(Ljava/lang/String;)V", + "2a2bb5000fb1"); + } + { + Method m = methods.get(2); + assertMethodEquals(pool, m, + "setAge", + "(I)V", + "2a1bb50011b1"); + } + { + Method m = methods.get(3); + assertMethodEquals(pool, m, + "sayHello", + "()V", + "b2001c1222b60024b1"); + } + { + Method m = methods.get(4); + assertMethodEquals(pool, m, + "main", + "([Ljava/lang/String;)V", + "bb000159122b101db7002d4c2bb6002fb1"); + } + } + + private void assertMethodEquals(ConstantPool pool, Method m, String expectedName, String expectedDesc, + String expectedCode) { + String methodName = pool.getUTF8String(m.getNameIndex()); + String methodDesc = pool.getUTF8String(m.getDescriptorIndex()); + String code = m.getCodeAttr().getCode(); + Assert.assertEquals(expectedName, methodName); + Assert.assertEquals(expectedDesc, methodDesc); + Assert.assertEquals(expectedCode, code); + } } From 444f8bd7e86e8148e7e6fd6c7a4d722d9aa07132 Mon Sep 17 00:00:00 2001 From: "kaitao.li" <kaitao.li@wormpex.com> Date: Sun, 16 Apr 2017 13:36:13 +0800 Subject: [PATCH 268/287] week5 jvm init --- .../com/coding2017/jvm/bean/EmployeeV1.java | 30 +++ .../com/coding2017/jvm/clz/AccessFlag.java | 26 +++ .../com/coding2017/jvm/clz/ClassFile.java | 77 +++++++ .../com/coding2017/jvm/clz/ClassIndex.java | 22 ++ .../coding2017/jvm/constant/ClassInfo.java | 28 +++ .../coding2017/jvm/constant/ConstantInfo.java | 31 +++ .../coding2017/jvm/constant/ConstantPool.java | 31 +++ .../coding2017/jvm/constant/FieldRefInfo.java | 58 ++++++ .../jvm/constant/MethodRefInfo.java | 57 ++++++ .../jvm/constant/NameAndTypeInfo.java | 48 +++++ .../jvm/constant/NullConstantInfo.java | 14 ++ .../coding2017/jvm/constant/StringInfo.java | 27 +++ .../com/coding2017/jvm/constant/UTF8Info.java | 37 ++++ .../jvm/loader/ByteCodeIterator.java | 5 + .../jvm/loader/ClassFileLoader.java | 81 ++++++++ .../jvm/loader/ClassFileParser.java | 31 +++ .../jvm/loader/ClassFileLoaderTest.java | 189 ++++++++++++++++++ group01/280646174/pom.xml | 14 ++ 18 files changed, 806 insertions(+) create mode 100644 group01/280646174/jvm/src/main/java/com/coding2017/jvm/bean/EmployeeV1.java create mode 100644 group01/280646174/jvm/src/main/java/com/coding2017/jvm/clz/AccessFlag.java create mode 100644 group01/280646174/jvm/src/main/java/com/coding2017/jvm/clz/ClassFile.java create mode 100644 group01/280646174/jvm/src/main/java/com/coding2017/jvm/clz/ClassIndex.java create mode 100644 group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/ClassInfo.java create mode 100644 group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/ConstantInfo.java create mode 100644 group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/ConstantPool.java create mode 100644 group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/FieldRefInfo.java create mode 100644 group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/MethodRefInfo.java create mode 100644 group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/NameAndTypeInfo.java create mode 100644 group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/NullConstantInfo.java create mode 100644 group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/StringInfo.java create mode 100644 group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/UTF8Info.java create mode 100644 group01/280646174/jvm/src/main/java/com/coding2017/jvm/loader/ByteCodeIterator.java create mode 100644 group01/280646174/jvm/src/main/java/com/coding2017/jvm/loader/ClassFileLoader.java create mode 100644 group01/280646174/jvm/src/main/java/com/coding2017/jvm/loader/ClassFileParser.java create mode 100644 group01/280646174/jvm/src/test/java/com/coding2017/jvm/loader/ClassFileLoaderTest.java diff --git a/group01/280646174/jvm/src/main/java/com/coding2017/jvm/bean/EmployeeV1.java b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/bean/EmployeeV1.java new file mode 100644 index 0000000000..4fdddbb2eb --- /dev/null +++ b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/bean/EmployeeV1.java @@ -0,0 +1,30 @@ +package com.coding2017.jvm.bean; + +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/group01/280646174/jvm/src/main/java/com/coding2017/jvm/clz/AccessFlag.java b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..b2d58a1b50 --- /dev/null +++ b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/clz/AccessFlag.java @@ -0,0 +1,26 @@ +package com.coding2017.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/group01/280646174/jvm/src/main/java/com/coding2017/jvm/clz/ClassFile.java b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..19c738f8d4 --- /dev/null +++ b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/clz/ClassFile.java @@ -0,0 +1,77 @@ +package com.coding2017.jvm.clz; + +import com.coding2017.jvm.constant.ClassInfo; +import com.coding2017.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/group01/280646174/jvm/src/main/java/com/coding2017/jvm/clz/ClassIndex.java b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..2844afe494 --- /dev/null +++ b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/clz/ClassIndex.java @@ -0,0 +1,22 @@ +package com.coding2017.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/group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/ClassInfo.java b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..e87c283295 --- /dev/null +++ b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/ClassInfo.java @@ -0,0 +1,28 @@ +package com.coding2017.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/group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/ConstantInfo.java b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..9acf6d70fa --- /dev/null +++ b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/ConstantInfo.java @@ -0,0 +1,31 @@ +package com.coding2017.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/group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/ConstantPool.java b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..61f8f8d5ba --- /dev/null +++ b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/ConstantPool.java @@ -0,0 +1,31 @@ +package com.coding2017.jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + 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/280646174/jvm/src/main/java/com/coding2017/jvm/constant/FieldRefInfo.java b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..4f440c59d5 --- /dev/null +++ b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/FieldRefInfo.java @@ -0,0 +1,58 @@ +package com.coding2017.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/group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/MethodRefInfo.java b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..091bb4a5d3 --- /dev/null +++ b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/MethodRefInfo.java @@ -0,0 +1,57 @@ +package com.coding2017.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/group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/NameAndTypeInfo.java b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..cda8ec8cd4 --- /dev/null +++ b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,48 @@ +package com.coding2017.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/group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/NullConstantInfo.java b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..7ce288e868 --- /dev/null +++ b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/NullConstantInfo.java @@ -0,0 +1,14 @@ +package com.coding2017.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo() { + + } + + @Override + public int getType() { + return -1; + } + +} diff --git a/group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/StringInfo.java b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..6408f56b0a --- /dev/null +++ b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/StringInfo.java @@ -0,0 +1,27 @@ +package com.coding2017.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/group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/UTF8Info.java b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..93bdd6f231 --- /dev/null +++ b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/constant/UTF8Info.java @@ -0,0 +1,37 @@ +package com.coding2017.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/group01/280646174/jvm/src/main/java/com/coding2017/jvm/loader/ByteCodeIterator.java b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..3b03c0ddd4 --- /dev/null +++ b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,5 @@ +package com.coding2017.jvm.loader; + +public class ByteCodeIterator { + +} diff --git a/group01/280646174/jvm/src/main/java/com/coding2017/jvm/loader/ClassFileLoader.java b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..74796fbbcf --- /dev/null +++ b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/loader/ClassFileLoader.java @@ -0,0 +1,81 @@ +package com.coding2017.jvm.loader; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import com.coding2017.jvm.clz.ClassFile; +import com.google.common.base.Joiner; +import com.google.common.base.Splitter; + +public class ClassFileLoader { + private static Joiner SEMICOLON_JOINER = Joiner.on(";").skipNulls(); + private static Splitter DOT_SPLITTER = Splitter.on(".").trimResults(); + private static Joiner SLASH_JOINER = Joiner.on("/").skipNulls(); + + private static String CLASS_SUFFIX = ".class"; + + private List<String> clzPaths = new ArrayList<String>(); + + public byte[] readBinaryCode(String className) { + List<String> list = DOT_SPLITTER.splitToList(className); + String childDirectory = SLASH_JOINER.join(list); + for (String clzPath : clzPaths) { + String fullPath = makeFullPath(clzPath, childDirectory); + if (fileExist(fullPath)) { + return readFileBytes(fullPath); + } + } + System.out.println("no this class file: " + className); + return null; + } + + private byte[] readFileBytes(String filePath) { + try { + File file = new File(filePath); + long length = file.length(); + byte[] fileBytes = new byte[(int) length]; + int readLength = new FileInputStream(filePath).read(fileBytes); + if (readLength != length) { + System.out.println("read file error. read length: " + readLength + ", full length : " + length); + return null; + } + return fileBytes; + } catch (IOException e) { + System.out.println("read file error. " + filePath); + return null; + } + } + + private boolean fileExist(String fullPath) { + File classFile = new File(fullPath); + return classFile.exists() && classFile.isFile(); + } + + private String makeFullPath(String clzPath, String childDirectory) { + if (clzPath.endsWith("/") || clzPath.endsWith("\\")) { + return clzPath + childDirectory + CLASS_SUFFIX; + } else { + return clzPath + "/" + childDirectory + CLASS_SUFFIX; + } + } + + public void addClassPath(String path) { + if (!clzPaths.contains(path)) { + clzPaths.add(path); + } + } + + public String getClassPath() { + return SEMICOLON_JOINER.join(clzPaths); + } + + public ClassFile loadClass(String className) { + byte[] codes = this.readBinaryCode(className); + ClassFileParser parser = new ClassFileParser(); + return parser.parse(codes); + } + +} diff --git a/group01/280646174/jvm/src/main/java/com/coding2017/jvm/loader/ClassFileParser.java b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..b913aed951 --- /dev/null +++ b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/loader/ClassFileParser.java @@ -0,0 +1,31 @@ +package com.coding2017.jvm.loader; + +import com.coding2017.jvm.clz.AccessFlag; +import com.coding2017.jvm.clz.ClassFile; +import com.coding2017.jvm.clz.ClassIndex; +import com.coding2017.jvm.constant.ConstantPool; + +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/group01/280646174/jvm/src/test/java/com/coding2017/jvm/loader/ClassFileLoaderTest.java b/group01/280646174/jvm/src/test/java/com/coding2017/jvm/loader/ClassFileLoaderTest.java new file mode 100644 index 0000000000..d93a3d5bcf --- /dev/null +++ b/group01/280646174/jvm/src/test/java/com/coding2017/jvm/loader/ClassFileLoaderTest.java @@ -0,0 +1,189 @@ +package com.coding2017.jvm.loader; + +import com.coding2017.jvm.clz.ClassFile; +import com.coding2017.jvm.clz.ClassIndex; +import com.coding2017.jvm.constant.*; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Created by kaitao.li on 2017/4/16. + */ +public class ClassFileLoaderTest { + + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + + static String path1 = "/Users/kaitao.li/code/study/coding2017/group01/280646174/jvm/target/classes"; + 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 { + } + + @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(1056, byteCodes.length); + + } + + @Test + public void testMagicNumber() { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "com.coding2017.week4.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(); + } + + /** + * ---------------------------------------------------------------------- + */ + + + @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("<init>", 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()); + } + +} \ No newline at end of file diff --git a/group01/280646174/pom.xml b/group01/280646174/pom.xml index 75422ec638..cf3eefc767 100644 --- a/group01/280646174/pom.xml +++ b/group01/280646174/pom.xml @@ -10,6 +10,7 @@ <version>1.0-SNAPSHOT</version> <modules> <module>basic</module> + <module>jvm</module> </modules> <properties> @@ -46,4 +47,17 @@ </dependencies> </dependencyManagement> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <source>1.8</source> + <target>1.8</target> + </configuration> + </plugin> + </plugins> + </build> + </project> \ No newline at end of file From 52b73988908c3dec46f5a1f86b888ad470f4abf6 Mon Sep 17 00:00:00 2001 From: "kaitao.li" <kaitao.li@wormpex.com> Date: Sun, 16 Apr 2017 14:41:36 +0800 Subject: [PATCH 269/287] =?UTF-8?q?week5=20jvm=20=E5=B8=B8=E9=87=8F?= =?UTF-8?q?=E6=B1=A0=20done?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jvm/loader/ByteCodeIterator.java | 33 ++++++++ .../jvm/loader/ClassFileParser.java | 82 +++++++++++++++++-- .../com/coding2017/jvm/util/ByteUtil.java | 29 +++++++ .../jvm/loader/ClassFileLoaderTest.java | 2 +- 4 files changed, 138 insertions(+), 8 deletions(-) create mode 100644 group01/280646174/jvm/src/main/java/com/coding2017/jvm/util/ByteUtil.java diff --git a/group01/280646174/jvm/src/main/java/com/coding2017/jvm/loader/ByteCodeIterator.java b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/loader/ByteCodeIterator.java index 3b03c0ddd4..566b251c32 100644 --- a/group01/280646174/jvm/src/main/java/com/coding2017/jvm/loader/ByteCodeIterator.java +++ b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/loader/ByteCodeIterator.java @@ -1,5 +1,38 @@ package com.coding2017.jvm.loader; +import com.coding2017.jvm.util.ByteUtil; + public class ByteCodeIterator { + private byte[] data; + private int pos; + + public ByteCodeIterator(byte[] data) { + this.data = data; + pos = 0; + } + + public void skip(int n) { + pos += n; + } + + public int nextU1ToInt() { + return nextByteN(1)[0]; + } + + public int nextU2ToInt() { + return ByteUtil.bytesToInt(nextByteN(2)); + } + + public String nextU4ToString() { + return ByteUtil.byteToHexString(nextByteN(4)); + } + + public byte[] nextByteN(int n) { + byte[] bytes = new byte[n]; + for (int i = 0; i < n; i++) { + bytes[i] = data[pos++]; + } + return bytes; + } } diff --git a/group01/280646174/jvm/src/main/java/com/coding2017/jvm/loader/ClassFileParser.java b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/loader/ClassFileParser.java index b913aed951..ff21b4fa0c 100644 --- a/group01/280646174/jvm/src/main/java/com/coding2017/jvm/loader/ClassFileParser.java +++ b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/loader/ClassFileParser.java @@ -3,29 +3,97 @@ import com.coding2017.jvm.clz.AccessFlag; import com.coding2017.jvm.clz.ClassFile; import com.coding2017.jvm.clz.ClassIndex; -import com.coding2017.jvm.constant.ConstantPool; +import com.coding2017.jvm.constant.*; public class ClassFileParser { public ClassFile parse(byte[] codes) { + ClassFile classFile = new ClassFile(); - return null; + ByteCodeIterator iterator = new ByteCodeIterator(codes); + boolean check = checkMagicNumber(iterator); + if (!check) { + System.out.println("不是标准class文件, magic number不正确"); + return null; + } + + // 版本号 + classFile.setMinorVersion(iterator.nextU2ToInt()); + classFile.setMajorVersion(iterator.nextU2ToInt()); + + // 常量池 + classFile.setConstPool(parseConstantPool(iterator)); + + // 访问标志 + classFile.setAccessFlag(parseAccessFlag(iterator)); + + // this class and super class + classFile.setClassIndex(parseClassInfex(iterator)); + + return classFile; } - private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + private boolean checkMagicNumber(ByteCodeIterator iterator) { + String magicNumber = iterator.nextU4ToString(); + return "cafebabe".equals(magicNumber); + } - return null; + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + AccessFlag accessFlag = new AccessFlag(iter.nextU2ToInt()); + return accessFlag; } private ClassIndex parseClassInfex(ByteCodeIterator iter) { - - return null; + ClassIndex classIndex = new ClassIndex(); + classIndex.setThisClassIndex(iter.nextU2ToInt()); + classIndex.setSuperClassIndex(iter.nextU2ToInt()); + return classIndex; } private ConstantPool parseConstantPool(ByteCodeIterator iter) { + ConstantPool constantPool = new ConstantPool(); + int constantCount = iter.nextU2ToInt(); + constantPool.addConstantInfo(new NullConstantInfo()); + for (int i = 1; i < constantCount; i++) { + constantPool.addConstantInfo(parseConstantInfo(constantPool, iter)); + } + return constantPool; + } - return null; + private ConstantInfo parseConstantInfo(ConstantPool constantPool, ByteCodeIterator iterator) { + int tag = iterator.nextU1ToInt(); + if (tag == ConstantInfo.UTF8_INFO) { + UTF8Info utf8Info = new UTF8Info(constantPool); + utf8Info.setLength(iterator.nextU2ToInt()); + utf8Info.setValue(new String(iterator.nextByteN(utf8Info.getLength()))); + return utf8Info; + } else if (tag == ConstantInfo.CLASS_INFO) { + ClassInfo classInfo = new ClassInfo(constantPool); + classInfo.setUtf8Index(iterator.nextU2ToInt()); + return classInfo; + } else if (tag == ConstantInfo.STRING_INFO) { + StringInfo stringInfo = new StringInfo(constantPool); + stringInfo.setIndex(iterator.nextU2ToInt()); + return stringInfo; + } else if (tag == ConstantInfo.FIELD_INFO) { + FieldRefInfo fieldRefInfo = new FieldRefInfo(constantPool); + fieldRefInfo.setClassInfoIndex(iterator.nextU2ToInt()); + fieldRefInfo.setNameAndTypeIndex(iterator.nextU2ToInt()); + return fieldRefInfo; + } else if (tag == ConstantInfo.METHOD_INFO) { + MethodRefInfo methodRefInfo = new MethodRefInfo(constantPool); + methodRefInfo.setClassInfoIndex(iterator.nextU2ToInt()); + methodRefInfo.setNameAndTypeIndex(iterator.nextU2ToInt()); + return methodRefInfo; + } else if (tag == ConstantInfo.NAME_AND_TYPE_INFO) { + NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(constantPool); + nameAndTypeInfo.setIndex1(iterator.nextU2ToInt()); + nameAndTypeInfo.setIndex2(iterator.nextU2ToInt()); + return nameAndTypeInfo; + } else { + throw new RuntimeException("not support tag " + tag); + } } } diff --git a/group01/280646174/jvm/src/main/java/com/coding2017/jvm/util/ByteUtil.java b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/util/ByteUtil.java new file mode 100644 index 0000000000..f1f3ec883f --- /dev/null +++ b/group01/280646174/jvm/src/main/java/com/coding2017/jvm/util/ByteUtil.java @@ -0,0 +1,29 @@ +package com.coding2017.jvm.util; + +/** + * Created by kaitao.li on 2017/4/16. + */ +public class ByteUtil { + + public static int bytesToInt(byte[] data) { + int result = 0; + for (int i = 0; i < data.length; i++) { + result = result * 256 + data[i]; + } + return result; + } + + 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/group01/280646174/jvm/src/test/java/com/coding2017/jvm/loader/ClassFileLoaderTest.java b/group01/280646174/jvm/src/test/java/com/coding2017/jvm/loader/ClassFileLoaderTest.java index d93a3d5bcf..c25f6f2c0f 100644 --- a/group01/280646174/jvm/src/test/java/com/coding2017/jvm/loader/ClassFileLoaderTest.java +++ b/group01/280646174/jvm/src/test/java/com/coding2017/jvm/loader/ClassFileLoaderTest.java @@ -24,7 +24,7 @@ public class ClassFileLoaderTest { static { ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); - String className = "com.coderising.jvm.test.EmployeeV1"; + String className = "EmployeeV1"; clzFile = loader.loadClass(className); clzFile.print(); From 1249d07b4113598d203af6edb35c7d81d6079a83 Mon Sep 17 00:00:00 2001 From: GZ-RXP <283091182@qq.com> Date: Sun, 16 Apr 2017 15:32:45 +0800 Subject: [PATCH 270/287] jvm 2nd week DataStructure -StackUtil --- .../loader/ClassFileLoader.java | 93 +++++++++++ .../test/ClassFileloaderTest.java | 92 +++++++++++ .../test/EmployeeV1.java | 0 .../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 | 87 +++++++++++ .../jvm/loader/ClassFileLoader.java | 147 ++++++++++++------ .../jvm/loader/ClassFileParser.java | 101 ++++++++++++ .../jvm/test/ClassFileloaderTest.java | 134 ++++++++++++++-- .../basic => coderising/array}/ArrayList.java | 5 +- .../array}/ArrayListTest.java | 22 +-- .../283091182/src/com/coding/basic/Queue.java | 2 + .../283091182/src/com/coding/basic/Stack.java | 2 + .../basic/{ => linklist}/LinkedList.java | 5 +- .../src/com/coding/basic/stack/Stack.java | 50 ++++++ .../src/com/coding/basic/stack/StackUtil.java | 140 +++++++++++++++++ 26 files changed, 1231 insertions(+), 75 deletions(-) create mode 100644 group11/283091182/mini-jvm-week1-bk/loader/ClassFileLoader.java create mode 100644 group11/283091182/mini-jvm-week1-bk/test/ClassFileloaderTest.java rename group11/283091182/{mini-jvm/com/coderising/jvm => mini-jvm-week1-bk}/test/EmployeeV1.java (100%) create mode 100644 group11/283091182/mini-jvm/com/coderising/jvm/clz/AccessFlag.java create mode 100644 group11/283091182/mini-jvm/com/coderising/jvm/clz/ClassFile.java create mode 100644 group11/283091182/mini-jvm/com/coderising/jvm/clz/ClassIndex.java create mode 100644 group11/283091182/mini-jvm/com/coderising/jvm/constant/ClassInfo.java create mode 100644 group11/283091182/mini-jvm/com/coderising/jvm/constant/ConstantInfo.java create mode 100644 group11/283091182/mini-jvm/com/coderising/jvm/constant/ConstantPool.java create mode 100644 group11/283091182/mini-jvm/com/coderising/jvm/constant/FieldRefInfo.java create mode 100644 group11/283091182/mini-jvm/com/coderising/jvm/constant/MethodRefInfo.java create mode 100644 group11/283091182/mini-jvm/com/coderising/jvm/constant/NameAndTypeInfo.java create mode 100644 group11/283091182/mini-jvm/com/coderising/jvm/constant/NullConstantInfo.java create mode 100644 group11/283091182/mini-jvm/com/coderising/jvm/constant/StringInfo.java create mode 100644 group11/283091182/mini-jvm/com/coderising/jvm/constant/UTF8Info.java create mode 100644 group11/283091182/mini-jvm/com/coderising/jvm/loader/ByteCodeIterator.java create mode 100644 group11/283091182/mini-jvm/com/coderising/jvm/loader/ClassFileParser.java rename group11/283091182/src/com/{coding/basic => coderising/array}/ArrayList.java (91%) rename group11/283091182/src/com/{coding/basic => coderising/array}/ArrayListTest.java (69%) rename group11/283091182/src/com/coding/basic/{ => linklist}/LinkedList.java (92%) create mode 100644 group11/283091182/src/com/coding/basic/stack/Stack.java create mode 100644 group11/283091182/src/com/coding/basic/stack/StackUtil.java diff --git a/group11/283091182/mini-jvm-week1-bk/loader/ClassFileLoader.java b/group11/283091182/mini-jvm-week1-bk/loader/ClassFileLoader.java new file mode 100644 index 0000000000..527e2f14d8 --- /dev/null +++ b/group11/283091182/mini-jvm-week1-bk/loader/ClassFileLoader.java @@ -0,0 +1,93 @@ +package com.coderising.jvm.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.Iterator; +import java.util.List; + + + +public class ClassFileLoader { + + private List<String> clzPaths = new ArrayList<String>(); + + public byte[] readBinaryCode(String className) { + + File classFile = getClassFileFromPath(className); + + byte[] buffer = new byte[1024]; + try { + FileInputStream fis = new FileInputStream(classFile); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + int readLen; + while((readLen = fis.read(buffer))>-1){ + baos.write(buffer, 0, readLen); + } + + return baos.toByteArray(); + + } catch (FileNotFoundException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } catch (IOException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + + public void addClassPath(String path) { + File clzPath = new File(path); + if(clzPath.exists() && clzPath.isDirectory()){ + this.clzPaths.add(path); + }else{ + System.out.println("Invalid path:"+ path); + } + } + + + + public String getClassPath(){ + StringBuilder sb = new StringBuilder(); + Iterator it = this.clzPaths.iterator(); + while(it.hasNext()){ + if(sb.length()>0){ + sb.append(";"); + } + sb.append(it.next()); + } + return sb.toString(); + } + + public File getClassFileFromPath(String className) { + Iterator it = this.clzPaths.iterator(); + + //replace "." with "\\" in windows + String fullclassPath = className.replaceAll("\\.", (File.separatorChar=='\\')?"\\\\":"/")+".class"; + + while(it.hasNext()){ + File clzFile; + String path = (String)it.next(); + if(path.endsWith(String.valueOf(File.separatorChar))){ + clzFile = new File(path+fullclassPath); + }else{ + clzFile = new File(path+File.separatorChar+fullclassPath); + } + + //Check file before further proceed + if(clzFile.exists()&&clzFile.isFile()){ + return clzFile; + } + } + + throw new RuntimeException("Class not found:"+className); + } + + + +} diff --git a/group11/283091182/mini-jvm-week1-bk/test/ClassFileloaderTest.java b/group11/283091182/mini-jvm-week1-bk/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..21d7e97074 --- /dev/null +++ b/group11/283091182/mini-jvm-week1-bk/test/ClassFileloaderTest.java @@ -0,0 +1,92 @@ +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\\Administrator\\mygit\\coding2017\\liuxin\\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/group11/283091182/mini-jvm/com/coderising/jvm/test/EmployeeV1.java b/group11/283091182/mini-jvm-week1-bk/test/EmployeeV1.java similarity index 100% rename from group11/283091182/mini-jvm/com/coderising/jvm/test/EmployeeV1.java rename to group11/283091182/mini-jvm-week1-bk/test/EmployeeV1.java diff --git a/group11/283091182/mini-jvm/com/coderising/jvm/clz/AccessFlag.java b/group11/283091182/mini-jvm/com/coderising/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..faae056835 --- /dev/null +++ b/group11/283091182/mini-jvm/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/group11/283091182/mini-jvm/com/coderising/jvm/clz/ClassFile.java b/group11/283091182/mini-jvm/com/coderising/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..650ca8375d --- /dev/null +++ b/group11/283091182/mini-jvm/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/group11/283091182/mini-jvm/com/coderising/jvm/clz/ClassIndex.java b/group11/283091182/mini-jvm/com/coderising/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..e424f284b3 --- /dev/null +++ b/group11/283091182/mini-jvm/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/group11/283091182/mini-jvm/com/coderising/jvm/constant/ClassInfo.java b/group11/283091182/mini-jvm/com/coderising/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..aea9048ea4 --- /dev/null +++ b/group11/283091182/mini-jvm/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/group11/283091182/mini-jvm/com/coderising/jvm/constant/ConstantInfo.java b/group11/283091182/mini-jvm/com/coderising/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..466b072244 --- /dev/null +++ b/group11/283091182/mini-jvm/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/group11/283091182/mini-jvm/com/coderising/jvm/constant/ConstantPool.java b/group11/283091182/mini-jvm/com/coderising/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..86c0445695 --- /dev/null +++ b/group11/283091182/mini-jvm/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<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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/283091182/mini-jvm/com/coderising/jvm/constant/FieldRefInfo.java b/group11/283091182/mini-jvm/com/coderising/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..65475e194c --- /dev/null +++ b/group11/283091182/mini-jvm/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/group11/283091182/mini-jvm/com/coderising/jvm/constant/MethodRefInfo.java b/group11/283091182/mini-jvm/com/coderising/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..7f05870020 --- /dev/null +++ b/group11/283091182/mini-jvm/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/group11/283091182/mini-jvm/com/coderising/jvm/constant/NameAndTypeInfo.java b/group11/283091182/mini-jvm/com/coderising/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..402f9dec86 --- /dev/null +++ b/group11/283091182/mini-jvm/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/group11/283091182/mini-jvm/com/coderising/jvm/constant/NullConstantInfo.java b/group11/283091182/mini-jvm/com/coderising/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..936736016f --- /dev/null +++ b/group11/283091182/mini-jvm/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/group11/283091182/mini-jvm/com/coderising/jvm/constant/StringInfo.java b/group11/283091182/mini-jvm/com/coderising/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..f1f8eb4ed4 --- /dev/null +++ b/group11/283091182/mini-jvm/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/group11/283091182/mini-jvm/com/coderising/jvm/constant/UTF8Info.java b/group11/283091182/mini-jvm/com/coderising/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..5cac9f04f7 --- /dev/null +++ b/group11/283091182/mini-jvm/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/group11/283091182/mini-jvm/com/coderising/jvm/loader/ByteCodeIterator.java b/group11/283091182/mini-jvm/com/coderising/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..514d85e08f --- /dev/null +++ b/group11/283091182/mini-jvm/com/coderising/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,87 @@ +package com.coderising.jvm.loader; + +public class ByteCodeIterator { + private byte[] bytes; + private int pos = 0; + public ByteCodeIterator(byte[] byteCodes){ + this.bytes = byteCodes; + } + + public boolean hasNext(){ + return this.pos < bytes.length-1; + } + + public byte next(){ + byte b = bytes[pos]; + pos ++; + return b; + } + + public byte[] getBytes(int len){ + if(pos+len>bytes.length){ + throw new RuntimeException("Index out of bounds:"+(pos+len)); + } + byte[] bytes = new byte[len]; + int idx = 0; + while(hasNext() && idx<len){ + bytes[idx] = next(); + idx++; + } + return bytes; + } + + public String getBytesAsString(int len){ + return byteToString(getBytes(len)); + } + + public String getBytesAsHexString(int len){ + return byteToHexString(getBytes(len)); + } + + public int nextU1AsInt() { + return byteToInt(getBytes(1)); + } + + public int nextU2AsInt(){ + return byteToInt(getBytes(2)); + } + public int nextU4AsInt(){ + return byteToInt(getBytes(4)); + } + + public String nextU1AsString() { + return byteToString(getBytes(1)); + } + + public String nextU2AsString(){ + return byteToString(getBytes(2)); + } + public String nextU4AsString(){ + return byteToString(getBytes(4)); + } + + //Util Methods for type conversion + private int byteToInt(byte[] codes){ + String s1 = byteToHexString(codes); + return Integer.valueOf(s1, 16).intValue(); + } + + private String byteToString(byte[] codes){ + String s1 = byteToHexString(codes); + return new String(codes); + } + + 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/group11/283091182/mini-jvm/com/coderising/jvm/loader/ClassFileLoader.java b/group11/283091182/mini-jvm/com/coderising/jvm/loader/ClassFileLoader.java index 527e2f14d8..9ff27b16cf 100644 --- a/group11/283091182/mini-jvm/com/coderising/jvm/loader/ClassFileLoader.java +++ b/group11/283091182/mini-jvm/com/coderising/jvm/loader/ClassFileLoader.java @@ -1,14 +1,20 @@ 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.Iterator; 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 { @@ -17,77 +23,118 @@ public class ClassFileLoader { public byte[] readBinaryCode(String className) { - File classFile = getClassFileFromPath(className); - - byte[] buffer = new byte[1024]; - try { - FileInputStream fis = new FileInputStream(classFile); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); + className = className.replace('.', File.separatorChar) +".class"; + + for(String path : this.clzPaths){ - int readLen; - while((readLen = fis.read(buffer))>-1){ - baos.write(buffer, 0, readLen); - } + 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)); - return baos.toByteArray(); - - } catch (FileNotFoundException e) { - e.printStackTrace(); - throw new RuntimeException(e); - } catch (IOException e) { + } catch (IOException e) { e.printStackTrace(); - throw new RuntimeException(e); + return null; } } + public void addClassPath(String path) { - File clzPath = new File(path); - if(clzPath.exists() && clzPath.isDirectory()){ - this.clzPaths.add(path); - }else{ - System.out.println("Invalid path:"+ path); + if(this.clzPaths.contains(path)){ + return; } + + this.clzPaths.add(path); + } public String getClassPath(){ - StringBuilder sb = new StringBuilder(); - Iterator it = this.clzPaths.iterator(); - while(it.hasNext()){ - if(sb.length()>0){ - sb.append(";"); + 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(";"); } - sb.append(it.next()); } - return sb.toString(); + return buffer.toString(); } - - public File getClassFileFromPath(String className) { - Iterator it = this.clzPaths.iterator(); - - //replace "." with "\\" in windows - String fullclassPath = className.replaceAll("\\.", (File.separatorChar=='\\')?"\\\\":"/")+".class"; - - while(it.hasNext()){ - File clzFile; - String path = (String)it.next(); - if(path.endsWith(String.valueOf(File.separatorChar))){ - clzFile = new File(path+fullclassPath); - }else{ - clzFile = new File(path+File.separatorChar+fullclassPath); + + 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); } - //Check file before further proceed - if(clzFile.exists()&&clzFile.isFile()){ - return clzFile; + 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; - throw new RuntimeException("Class not found:"+className); } + -} +} \ No newline at end of file diff --git a/group11/283091182/mini-jvm/com/coderising/jvm/loader/ClassFileParser.java b/group11/283091182/mini-jvm/com/coderising/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..4c2cef5504 --- /dev/null +++ b/group11/283091182/mini-jvm/com/coderising/jvm/loader/ClassFileParser.java @@ -0,0 +1,101 @@ +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; + +public class ClassFileParser { + + public ClassFile parse(byte[] codes) { + ByteCodeIterator iter = new ByteCodeIterator(codes); + ClassFile clzFile = new ClassFile(); + + String magicNum = iter.getBytesAsHexString(4); + if(!"cafebabe".equals(magicNum)){ + throw new RuntimeException("Magic Number validation failure, this may not be a java class file."); + } + + int minVer = iter.nextU2AsInt(); + int majVer = iter.nextU2AsInt(); + System.out.println("magicNum="+magicNum+",minVer="+minVer+",majVer="+majVer); + clzFile.setMajorVersion(majVer); + clzFile.setMinorVersion(minVer); + ConstantPool pool = parseConstantPool(iter); + clzFile.setConstPool(pool); + AccessFlag accFlag = parseAccessFlag(iter); + clzFile.setAccessFlag(accFlag); + ClassIndex clsIdx = parseClassIndex(iter); + clzFile.setClassIndex(clsIdx); + return clzFile; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + AccessFlag af = new AccessFlag(iter.nextU2AsInt()); + return af; + } + + private ClassIndex parseClassIndex(ByteCodeIterator iter) { + ClassIndex ci = new ClassIndex(); + ci.setThisClassIndex(iter.nextU2AsInt()); + ci.setSuperClassIndex(iter.nextU2AsInt()); + return ci; + + } + + private ConstantPool parseConstantPool(ByteCodeIterator iter) { + ConstantPool cp = new ConstantPool(); + cp.addConstantInfo(new NullConstantInfo()); + int cpLen = iter.nextU2AsInt(); + for(int i=0;i<cpLen-1;i++){ + int typeFlag = iter.nextU1AsInt(); + switch(typeFlag){ + case ConstantInfo.CLASS_INFO: //class info + ClassInfo cf = new ClassInfo(cp); + cf.setUtf8Index(iter.nextU2AsInt()); + cp.addConstantInfo(cf); + break; + case ConstantInfo.UTF8_INFO: //UTF8 info + UTF8Info ui = new UTF8Info(cp); + ui.setLength(iter.nextU2AsInt()); + ui.setValue(iter.getBytesAsString(ui.getLength())); + cp.addConstantInfo(ui); + break; + case ConstantInfo.STRING_INFO: + StringInfo ci = new StringInfo(cp); + ci.setIndex(iter.nextU2AsInt()); + cp.addConstantInfo(ci); + break; + case ConstantInfo.FIELD_INFO: + FieldRefInfo fri = new FieldRefInfo(cp); + fri.setClassInfoIndex(iter.nextU2AsInt()); + fri.setNameAndTypeIndex(iter.nextU2AsInt()); + cp.addConstantInfo(fri); + break; + case ConstantInfo.METHOD_INFO: + MethodRefInfo mri = new MethodRefInfo(cp); + mri.setClassInfoIndex(iter.nextU2AsInt()); + mri.setNameAndTypeIndex(iter.nextU2AsInt()); + cp.addConstantInfo(mri); + break; + case ConstantInfo.NAME_AND_TYPE_INFO: + NameAndTypeInfo nti = new NameAndTypeInfo(cp); + nti.setIndex1(iter.nextU2AsInt()); + nti.setIndex2(iter.nextU2AsInt()); + cp.addConstantInfo(nti); + break; + default : throw new RuntimeException("Parse exception:"+typeFlag); + } + } + return cp; + } + +} diff --git a/group11/283091182/mini-jvm/com/coderising/jvm/test/ClassFileloaderTest.java b/group11/283091182/mini-jvm/com/coderising/jvm/test/ClassFileloaderTest.java index 21d7e97074..3d707a4fb2 100644 --- a/group11/283091182/mini-jvm/com/coderising/jvm/test/ClassFileloaderTest.java +++ b/group11/283091182/mini-jvm/com/coderising/jvm/test/ClassFileloaderTest.java @@ -5,6 +5,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; @@ -14,9 +21,20 @@ public class ClassFileloaderTest { + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + static String path1 = "C:\\Users\\Administrator\\mygit\\coding2017\\liuxin\\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 @@ -72,21 +90,113 @@ public void testMagicNumber(){ + 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(); + } + /** + * ---------------------------------------------------------------------- + */ - 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); + @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()); } - return buffer.toString(); - } + { + 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("<init>", 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/group11/283091182/src/com/coding/basic/ArrayList.java b/group11/283091182/src/com/coderising/array/ArrayList.java similarity index 91% rename from group11/283091182/src/com/coding/basic/ArrayList.java rename to group11/283091182/src/com/coderising/array/ArrayList.java index 402d05c019..18b0dcca6f 100644 --- a/group11/283091182/src/com/coding/basic/ArrayList.java +++ b/group11/283091182/src/com/coderising/array/ArrayList.java @@ -1,7 +1,10 @@ -package com.coding.basic; +package com.coderising.array; import java.util.Arrays; +import com.coding.basic.Iterator; +import com.coding.basic.List; + public class ArrayList implements List { private int size = 0; diff --git a/group11/283091182/src/com/coding/basic/ArrayListTest.java b/group11/283091182/src/com/coderising/array/ArrayListTest.java similarity index 69% rename from group11/283091182/src/com/coding/basic/ArrayListTest.java rename to group11/283091182/src/com/coderising/array/ArrayListTest.java index 7807fa831e..8bdc0515d1 100644 --- a/group11/283091182/src/com/coding/basic/ArrayListTest.java +++ b/group11/283091182/src/com/coderising/array/ArrayListTest.java @@ -1,7 +1,7 @@ /** * */ -package com.coding.basic; +package com.coderising.array; import static org.junit.Assert.*; @@ -51,7 +51,7 @@ public void tearDown() throws Exception { } /** - * Test method for {@link com.coding.basic.ArrayList#add(java.lang.Object)}. + * Test method for {@link com.coderising.array.ArrayList#add(java.lang.Object)}. */ @Test public final void testAddObject() { @@ -65,7 +65,7 @@ public final void testAddObject() { } /** - * Test method for {@link com.coding.basic.ArrayList#add(int, java.lang.Object)}. + * Test method for {@link com.coderising.array.ArrayList#add(int, java.lang.Object)}. */ @Test public final void testAddIntObject() { @@ -78,14 +78,14 @@ public final void testAddIntObject() { assertEquals(3,al.size()); } /** - * Test method for {@link com.coding.basic.ArrayList#add(int, java.lang.Object)}. + * Test method for {@link com.coderising.array.ArrayList#add(int, java.lang.Object)}. */ @Test(expected=IndexOutOfBoundsException.class) public final void testAddIntObjectWithException1() { al.add(-1, "aaa"); } /** - * Test method for {@link com.coding.basic.ArrayList#add(int, java.lang.Object)}. + * Test method for {@link com.coderising.array.ArrayList#add(int, java.lang.Object)}. */ @Test(expected=IndexOutOfBoundsException.class) public final void testAddIntObjectWithException2() { @@ -94,21 +94,21 @@ public final void testAddIntObjectWithException2() { } /** - * Test method for {@link com.coding.basic.ArrayList#get(int)}. + * Test method for {@link com.coderising.array.ArrayList#get(int)}. */ @Test public final void testGet() { fail("Not yet implemented"); // TODO } /** - * Test method for {@link com.coding.basic.ArrayList#get(int)}. + * Test method for {@link com.coderising.array.ArrayList#get(int)}. */ @Test public final void testGetWithException1() { fail("Not yet implemented"); // TODO } /** - * Test method for {@link com.coding.basic.ArrayList#get(int)}. + * Test method for {@link com.coderising.array.ArrayList#get(int)}. */ @Test public final void testGetWithException2() { @@ -116,7 +116,7 @@ public final void testGetWithException2() { } /** - * Test method for {@link com.coding.basic.ArrayList#remove(int)}. + * Test method for {@link com.coderising.array.ArrayList#remove(int)}. */ @Test public final void testRemove() { @@ -124,7 +124,7 @@ public final void testRemove() { } /** - * Test method for {@link com.coding.basic.ArrayList#size()}. + * Test method for {@link com.coderising.array.ArrayList#size()}. */ @Test public final void testSize() { @@ -132,7 +132,7 @@ public final void testSize() { } /** - * Test method for {@link com.coding.basic.ArrayList#iterator()}. + * Test method for {@link com.coderising.array.ArrayList#iterator()}. */ @Test public final void testIterator() { diff --git a/group11/283091182/src/com/coding/basic/Queue.java b/group11/283091182/src/com/coding/basic/Queue.java index 45fea2a118..0f1f068e19 100644 --- a/group11/283091182/src/com/coding/basic/Queue.java +++ b/group11/283091182/src/com/coding/basic/Queue.java @@ -1,5 +1,7 @@ package com.coding.basic; +import com.coding.basic.linklist.LinkedList; + public class Queue { private LinkedList list = new LinkedList(); diff --git a/group11/283091182/src/com/coding/basic/Stack.java b/group11/283091182/src/com/coding/basic/Stack.java index 915d173b1b..5ff5ce5279 100644 --- a/group11/283091182/src/com/coding/basic/Stack.java +++ b/group11/283091182/src/com/coding/basic/Stack.java @@ -1,5 +1,7 @@ package com.coding.basic; +import com.coderising.array.ArrayList; + public class Stack { private ArrayList elementData = new ArrayList(); diff --git a/group11/283091182/src/com/coding/basic/LinkedList.java b/group11/283091182/src/com/coding/basic/linklist/LinkedList.java similarity index 92% rename from group11/283091182/src/com/coding/basic/LinkedList.java rename to group11/283091182/src/com/coding/basic/linklist/LinkedList.java index 233c243130..2c5959890a 100644 --- a/group11/283091182/src/com/coding/basic/LinkedList.java +++ b/group11/283091182/src/com/coding/basic/linklist/LinkedList.java @@ -1,4 +1,7 @@ -package com.coding.basic; +package com.coding.basic.linklist; + +import com.coding.basic.Iterator; +import com.coding.basic.List; public class LinkedList implements List { diff --git a/group11/283091182/src/com/coding/basic/stack/Stack.java b/group11/283091182/src/com/coding/basic/stack/Stack.java new file mode 100644 index 0000000000..c59be3c1e4 --- /dev/null +++ b/group11/283091182/src/com/coding/basic/stack/Stack.java @@ -0,0 +1,50 @@ +package com.coding.basic.stack; + +import com.coderising.array.ArrayList; + +public class Stack { + private ArrayList elementData = new ArrayList(); + + public void push(Object o){ + elementData.add(o); + } + + public Object pop(){ + if(elementData.size()==0)throw new RuntimeException("Stack is empty."); + return elementData.remove(elementData.size()-1); + } + + public Object peek(){ + if(elementData.size()==0)throw new RuntimeException("Stack is empty."); + return elementData.get(elementData.size()-1); + } + public boolean isEmpty(){ + return (elementData.size()==0); + } + public int size(){ + return elementData.size(); + } + + @Override + public String toString(){ + return elementData.toString(); + } + + public static void main(String[] args){ + Stack s = new Stack(); + s.push("aaa"); + s.push("bbb"); + s.push("ccc"); + System.out.println(s); + System.out.println(s.isEmpty()); + System.out.println(s.size()); + System.out.println(s.peek()); + System.out.println(s.pop()); + System.out.println(s.pop()); + System.out.println(s.pop()); + System.out.println(s); + System.out.println(s.isEmpty()); + System.out.println(s.size()); + //System.out.println(s.pop()); + } +} diff --git a/group11/283091182/src/com/coding/basic/stack/StackUtil.java b/group11/283091182/src/com/coding/basic/stack/StackUtil.java new file mode 100644 index 0000000000..cd5aa08d06 --- /dev/null +++ b/group11/283091182/src/com/coding/basic/stack/StackUtil.java @@ -0,0 +1,140 @@ +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) { + if(s==null || s.isEmpty()){ + return; + }; + Stack temp = new Stack(); + int counter = s.size(); + while(counter>1){ + //Get the peek one + Object o = s.pop(); + for(int i=0;i<counter-1;i++){ + temp.push(s.pop()); + } + s.push(o); + for(int j=0;j<counter-1;j++){ + s.push(temp.pop()); + } + counter--; + } + } + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s,Object o) { + if(s==null || s.isEmpty()){ + return; + }; + int size = s.size(); + int counter; + Stack tmpStk = new Stack(); + for(counter = 0; counter<size;counter++){ + Object tmp = s.pop(); + if(!tmp.equals(o)){ + tmpStk.push(tmp); + }else{ + break; + } + } + for(int i=0;i<counter;i++){ + s.push(tmpStk.pop()); + } + + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * @param len + * @return + */ + public static Object[] getTop(Stack s,int len) { + if(s==null || s.isEmpty()){ + return new Object[0]; + } + if(len>s.size()){ + throw new RuntimeException("Index Out of Bound:"+ len); + } + Object[] objArr = new Object[len]; + Stack tmpStk = new Stack(); + for(int i=0;i<len;i++){ + Object obj = s.pop(); + objArr[i] = obj; + tmpStk.push(obj); + } + for(int i=0;i<len;i++){ + s.push(tmpStk.pop()); + } + return objArr; + } + /** + * 字符串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.length()==0){ + return false; + } + if(s.indexOf("(")<0 && s.indexOf(")")<0 && + s.indexOf("[")<0 && s.indexOf("]")<0 && + s.indexOf("{")<0 && s.indexOf("}")<0){ + return false; + } + + char[] charArr = s.toCharArray(); + Stack stk = new Stack(); + + for(int i=0;i<charArr.length;i++){ + char c = charArr[i]; + if(c=='(' || c=='[' || c=='{'){ + stk.push(c); + } + if(c==')' && stk.peek().equals('(')){ + stk.pop(); + } + if(c==']' && stk.peek().equals('[')){ + stk.pop(); + } + if(c=='}' && stk.peek().equals('{')){ + stk.pop(); + } + } + System.out.println(stk); + return stk.isEmpty(); + } + + public static void main(String args[]){ + Stack s = new Stack(); + s.push("1"); + s.push("2"); + s.push("3"); + s.push("4"); + s.push("5"); + System.out.println(s); + StackUtil.reverse(s); + System.out.println(s); + StackUtil.remove(s, "2"); + System.out.println(s); + Object[] arr = StackUtil.getTop(s, 3); + System.out.println(s); + System.out.println(arr.length+":"+arr[0]+arr[1]+arr[2]); + System.out.println("isValidPairs:"+StackUtil.isValidPairs("ABCDF")); + System.out.println("isValidPairs:"+StackUtil.isValidPairs("{A[B(C)D]F}")); + System.out.println("isValidPairs:"+StackUtil.isValidPairs("{([A[B)}CDF")); + } +} From 737e5058b9d5ed5592dc44fd9668466d9bc7226d Mon Sep 17 00:00:00 2001 From: James <1310368322@qq.com> Date: Sun, 16 Apr 2017 15:50:16 +0800 Subject: [PATCH 271/287] sixHomework --- .../RemoteSystemsTempFiles/.project | 12 ++ .../FourthHomework/jvm/ClassFileLoader.java | 51 --------- .../src/FourthHomework/jvm/TestJVM.java | 7 -- .../coderising/jvm/attr/AttributeInfo.java | 19 ++++ .../com/coderising/jvm/attr/CodeAttr.java | 86 ++++++++++++++ .../coderising/jvm/attr/LineNumberTable.java | 52 +++++++++ .../jvm/attr/LocalVariableItem.java | 41 +++++++ .../jvm/attr/LocalVariableTable.java | 41 +++++++ .../coderising/jvm/attr/StackMapTable.java | 29 +++++ .../com/coderising}/jvm/clz/AccessFlag.java | 0 .../com/coderising}/jvm/clz/ClassFile.java | 20 ++++ .../com/coderising}/jvm/clz/ClassIndex.java | 0 .../coderising}/jvm/constant/ClassInfo.java | 0 .../jvm/constant/ConstantInfo.java | 0 .../jvm/constant/ConstantPool.java | 1 + .../jvm/constant/FieldRefInfo.java | 0 .../jvm/constant/MethodRefInfo.java | 0 .../jvm/constant/NameAndTypeInfo.java | 0 .../jvm/constant/NullConstantInfo.java | 0 .../coderising}/jvm/constant/StringInfo.java | 0 .../coderising}/jvm/constant/UTF8Info.java | 0 .../com/coderising/jvm/field/Field.java | 43 +++++++ .../jvm/loader/ByteCodeIterator.java | 16 +++ .../jvm/loader/ClassFileLoader.java | 0 .../jvm/loader/ClassFileParser.java | 43 ++++++- .../com/coderising}/jvm/loader/TestJVM.java | 0 .../com/coderising/jvm/method/Method.java | 68 +++++++++++ .../BigHomework}/Download/DownloadThread.java | 0 .../BigHomework}/Download/FileDownloader.java | 0 .../BigHomework}/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_1}/ArrayList.java | 0 .../baseDataStructure_1}/LinkedList.java | 0 .../baseDataStructure_2}/ArrayUtil.java | 0 .../baseDataStructure_3}/LinkedList.java | 0 .../LRUPageFrame.java | 0 .../baseDataStructure_5_Stack}/StackUtil.java | 0 .../InfixExpr.java | 106 ++++++++++++++++++ .../DataStructure_5_Stack/TestSwitch.java | 15 --- .../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/TestIntegerToHexString.java | 10 -- .../test/FourthHomework/JVM/EmployeeV1.java | 28 ----- .../JVM/TestClassFileLoader.java | 67 ----------- .../jvm/loader => Mini_JVM}/EmployeeV1.java | 0 .../TestClassFileLoader.java | 92 +++++++++++++-- .../Download/FileDownloaderTest.java | 0 .../baseDataStructure_2}/ArrayUtilTest.java | 0 .../baseDataStructure_3}/TestLinkedList.java | 0 .../TestLRUPageFrame.java | 0 .../TestStackUtil.java | 0 .../InfixExpr.java | 106 ++++++++++++++++++ 59 files changed, 763 insertions(+), 251 deletions(-) create mode 100644 group11/1310368322/RemoteSystemsTempFiles/.project delete mode 100644 group11/1310368322/src/FourthHomework/jvm/ClassFileLoader.java delete mode 100644 group11/1310368322/src/FourthHomework/jvm/TestJVM.java create mode 100644 group11/1310368322/src/Mini_JVM/com/coderising/jvm/attr/AttributeInfo.java create mode 100644 group11/1310368322/src/Mini_JVM/com/coderising/jvm/attr/CodeAttr.java create mode 100644 group11/1310368322/src/Mini_JVM/com/coderising/jvm/attr/LineNumberTable.java create mode 100644 group11/1310368322/src/Mini_JVM/com/coderising/jvm/attr/LocalVariableItem.java create mode 100644 group11/1310368322/src/Mini_JVM/com/coderising/jvm/attr/LocalVariableTable.java create mode 100644 group11/1310368322/src/Mini_JVM/com/coderising/jvm/attr/StackMapTable.java rename group11/1310368322/src/{FifthHomework => Mini_JVM/com/coderising}/jvm/clz/AccessFlag.java (100%) rename group11/1310368322/src/{FifthHomework => Mini_JVM/com/coderising}/jvm/clz/ClassFile.java (78%) rename group11/1310368322/src/{FifthHomework => Mini_JVM/com/coderising}/jvm/clz/ClassIndex.java (100%) rename group11/1310368322/src/{FifthHomework => Mini_JVM/com/coderising}/jvm/constant/ClassInfo.java (100%) rename group11/1310368322/src/{FifthHomework => Mini_JVM/com/coderising}/jvm/constant/ConstantInfo.java (100%) rename group11/1310368322/src/{FifthHomework => Mini_JVM/com/coderising}/jvm/constant/ConstantPool.java (93%) rename group11/1310368322/src/{FifthHomework => Mini_JVM/com/coderising}/jvm/constant/FieldRefInfo.java (100%) rename group11/1310368322/src/{FifthHomework => Mini_JVM/com/coderising}/jvm/constant/MethodRefInfo.java (100%) rename group11/1310368322/src/{FifthHomework => Mini_JVM/com/coderising}/jvm/constant/NameAndTypeInfo.java (100%) rename group11/1310368322/src/{FifthHomework => Mini_JVM/com/coderising}/jvm/constant/NullConstantInfo.java (100%) rename group11/1310368322/src/{FifthHomework => Mini_JVM/com/coderising}/jvm/constant/StringInfo.java (100%) rename group11/1310368322/src/{FifthHomework => Mini_JVM/com/coderising}/jvm/constant/UTF8Info.java (100%) create mode 100644 group11/1310368322/src/Mini_JVM/com/coderising/jvm/field/Field.java rename group11/1310368322/src/{FifthHomework => Mini_JVM/com/coderising}/jvm/loader/ByteCodeIterator.java (74%) rename group11/1310368322/src/{FifthHomework => Mini_JVM/com/coderising}/jvm/loader/ClassFileLoader.java (100%) rename group11/1310368322/src/{FifthHomework => Mini_JVM/com/coderising}/jvm/loader/ClassFileParser.java (81%) rename group11/1310368322/src/{FifthHomework => Mini_JVM/com/coderising}/jvm/loader/TestJVM.java (100%) create mode 100644 group11/1310368322/src/Mini_JVM/com/coderising/jvm/method/Method.java rename group11/1310368322/src/{ThirdHomework => data_structure/BigHomework}/Download/DownloadThread.java (100%) rename group11/1310368322/src/{ThirdHomework => data_structure/BigHomework}/Download/FileDownloader.java (100%) rename group11/1310368322/src/{ThirdHomework => data_structure/BigHomework}/Download/api/Connection.java (100%) rename group11/1310368322/src/{ThirdHomework => data_structure/BigHomework}/Download/api/ConnectionException.java (100%) rename group11/1310368322/src/{ThirdHomework => data_structure/BigHomework}/Download/api/ConnectionManager.java (100%) rename group11/1310368322/src/{ThirdHomework => data_structure/BigHomework}/Download/api/DownloadListener.java (100%) rename group11/1310368322/src/{ThirdHomework => data_structure/BigHomework}/Download/impl/ConnectionImpl.java (100%) rename group11/1310368322/src/{ThirdHomework => data_structure/BigHomework}/Download/impl/ConnectionManagerImpl.java (100%) rename group11/1310368322/src/{FirstHomework/BaseDataStructure => data_structure/baseDataStructure_1}/ArrayList.java (100%) rename group11/1310368322/src/{FirstHomework/BaseDataStructure => data_structure/baseDataStructure_1}/LinkedList.java (100%) rename group11/1310368322/src/{SecondHomework/BaseDataStructure => data_structure/baseDataStructure_2}/ArrayUtil.java (100%) rename group11/1310368322/src/{ThirdHomework/BaseDataStructure => data_structure/baseDataStructure_3}/LinkedList.java (100%) rename group11/1310368322/src/{FourthHomework/BaseDataStructure => data_structure/baseDataStructure_4_LRU}/LRUPageFrame.java (100%) rename group11/1310368322/src/{FifthHomework/DataStructure_5_Stack => data_structure/baseDataStructure_5_Stack}/StackUtil.java (100%) create mode 100644 group11/1310368322/src/data_structure/baseDataStructure_6InfixExpr/InfixExpr.java delete mode 100644 group11/1310368322/test/FifthHomework/DataStructure_5_Stack/TestSwitch.java delete mode 100644 group11/1310368322/test/FifthHomework/jvm/loader/TestArray.java delete mode 100644 group11/1310368322/test/FifthHomework/jvm/loader/TestArrayList.java delete mode 100644 group11/1310368322/test/FifthHomework/jvm/loader/TestByteArrayToHexString.java delete mode 100644 group11/1310368322/test/FifthHomework/jvm/loader/TestByteArrayToInt.java delete mode 100644 group11/1310368322/test/FifthHomework/jvm/loader/TestByteToInt.java delete mode 100644 group11/1310368322/test/FifthHomework/jvm/loader/TestIntegerToHexString.java delete mode 100644 group11/1310368322/test/FourthHomework/JVM/EmployeeV1.java delete mode 100644 group11/1310368322/test/FourthHomework/JVM/TestClassFileLoader.java rename group11/1310368322/test/{FifthHomework/jvm/loader => Mini_JVM}/EmployeeV1.java (100%) rename group11/1310368322/test/{FifthHomework/jvm/loader => Mini_JVM}/TestClassFileLoader.java (68%) rename group11/1310368322/test/{ThirdHomework => data_structure/BigHomework}/Download/FileDownloaderTest.java (100%) rename group11/1310368322/test/{SecondHomwork/BaseDataStructure => data_structure/baseDataStructure_2}/ArrayUtilTest.java (100%) rename group11/1310368322/test/{ThirdHomework/BaseDataStructure => data_structure/baseDataStructure_3}/TestLinkedList.java (100%) rename group11/1310368322/test/{FourthHomework/BaseDataStructure => data_structure/baseDataStructure_4_LRU}/TestLRUPageFrame.java (100%) rename group11/1310368322/test/{FifthHomework/DataStructure_5_Stack => data_structure/baseDataStructure_5_Stack}/TestStackUtil.java (100%) create mode 100644 group11/1310368322/test/data_structure/baseDataStructure_6InfixExpr/InfixExpr.java diff --git a/group11/1310368322/RemoteSystemsTempFiles/.project b/group11/1310368322/RemoteSystemsTempFiles/.project new file mode 100644 index 0000000000..5447a64fa9 --- /dev/null +++ b/group11/1310368322/RemoteSystemsTempFiles/.project @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>RemoteSystemsTempFiles</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + </buildSpec> + <natures> + <nature>org.eclipse.rse.ui.remoteSystemsTempNature</nature> + </natures> +</projectDescription> diff --git a/group11/1310368322/src/FourthHomework/jvm/ClassFileLoader.java b/group11/1310368322/src/FourthHomework/jvm/ClassFileLoader.java deleted file mode 100644 index 6db696e5aa..0000000000 --- a/group11/1310368322/src/FourthHomework/jvm/ClassFileLoader.java +++ /dev/null @@ -1,51 +0,0 @@ -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<String> clzPaths = new ArrayList<String>(); - 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 deleted file mode 100644 index 735e4d1dc2..0000000000 --- a/group11/1310368322/src/FourthHomework/jvm/TestJVM.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.coderising.jvm.loader; - -public class TestJVM { - public static void main(String[] args) { - System.out.println("Hello"); - } -} diff --git a/group11/1310368322/src/Mini_JVM/com/coderising/jvm/attr/AttributeInfo.java b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/attr/AttributeInfo.java new file mode 100644 index 0000000000..58f2190146 --- /dev/null +++ b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/attr/AttributeInfo.java @@ -0,0 +1,19 @@ +package com.coderising.jvm.attr; + +public abstract class AttributeInfo { + public static final String CODE = "Code"; + public static final String CONST_VALUE = "ConstantValue"; + public static final String EXCEPTIONS = "Exceptions"; + public static final String LINE_NUM_TABLE = "LineNumberTable"; + public static final String LOCAL_VAR_TABLE = "LocalVariableTable"; + public static final String STACK_MAP_TABLE = "StackMapTable"; + + int attrNameIndex; + int attrLen ; + + public AttributeInfo(int attrNameIndex, int attrLen) { + this.attrNameIndex = attrNameIndex; + this.attrLen = attrLen; + } + +} diff --git a/group11/1310368322/src/Mini_JVM/com/coderising/jvm/attr/CodeAttr.java b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/attr/CodeAttr.java new file mode 100644 index 0000000000..e07662a68b --- /dev/null +++ b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/attr/CodeAttr.java @@ -0,0 +1,86 @@ +package com.coderising.jvm.attr; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.loader.ByteCodeIterator; + +public class CodeAttr extends AttributeInfo{ + + private int maxStack; + private int maxLocals; + private int codeLen; + private String code; + + public String getCode(){ + return code; + } + + + private LineNumberTable lineNumTable; + private LocalVariableTable localVarTable; + private StackMapTable stackMapTable; + + + + public CodeAttr(int attrNameIndex, int attrLen , int maxStack, int maxLocals, int codeLen,String code) { + super(attrNameIndex, attrLen); + this.maxStack = maxStack; + this.maxLocals = maxLocals; + this.codeLen = codeLen; + this.code = code; + } + + public void setLineNumberTable(LineNumberTable t) { + this.lineNumTable = t; + } + + public void setLocalVariableTable(LocalVariableTable t) { + this.localVarTable = t; + } + + private void setStackMapTable(StackMapTable t) { + this.stackMapTable = t; + + } + + public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ + int attrNameIndex = iter.nextU2toInt(); + int attrLen = iter.nextU2toInt(); + int maxStack = iter.nextU2toInt(); + int max_Locals = iter.nextU2toInt(); + int codeLen = iter.nextU4toInt(); + // code + String code = iter.nextUxToHexString(codeLen); + CodeAttr codeAttr = new CodeAttr(attrNameIndex, attrLen, maxStack, max_Locals, max_Locals, code); + + int exceptionTableLen = iter.nextU2toInt(); + + if(exceptionTableLen > 0){ + String exTable = iter.nextUxToHexString(exceptionTableLen); + System.out.println("Encounted exception table, just ignore it"); + } + + int subAttributesCount = iter.nextU2toInt(); + + for(int i = 0; i < subAttributesCount; i++){ + int subAttrNameIndex = iter.nextU2toInt(); + String subAttrName = clzFile.getConstantPool().getUTF8String(subAttrNameIndex); + if(CodeAttr.LOCAL_VAR_TABLE.equalsIgnoreCase(subAttrName)){ + int subAttrLen = iter.nextU4toInt();// localVariableTable Ե + LocalVariableTable locVarTable = LocalVariableTable.parse(iter, subAttrNameIndex, subAttrLen); + codeAttr.setLocalVariableTable(locVarTable); + }else if(CodeAttr.LINE_NUM_TABLE.equalsIgnoreCase(subAttrName)){ + int subAttrLen = iter.nextU4toInt(); + LineNumberTable lineNumTable = LineNumberTable.parse(iter, subAttrNameIndex, subAttrLen); + codeAttr.setLineNumberTable(lineNumTable); + }else if(CodeAttr.STACK_MAP_TABLE.equalsIgnoreCase(subAttrName)){ + int subAttrLen = iter.nextU4toInt(); + StackMapTable stackMapTable = StackMapTable.parse(iter); + codeAttr.setStackMapTable(stackMapTable); + }else{ + throw new RuntimeException("need code to process" + subAttrName); + } + } + + return codeAttr; + } +} diff --git a/group11/1310368322/src/Mini_JVM/com/coderising/jvm/attr/LineNumberTable.java b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/attr/LineNumberTable.java new file mode 100644 index 0000000000..24bcb25572 --- /dev/null +++ b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/attr/LineNumberTable.java @@ -0,0 +1,52 @@ +package com.coderising.jvm.attr; + +import java.util.ArrayList; +import java.util.List; + +import com.coderising.jvm.loader.ByteCodeIterator; + +public class LineNumberTable extends AttributeInfo{ + + List<LineNumberItem> items = new ArrayList<LineNumberItem>();// кűкܶġкŶӦ + + // LineNumberTableһṹñ˿ + private static class LineNumberItem{ + int startPC;// ¼ֽк + int lineNum;// ¼JavaԴк + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLineNum() { + return lineNum; + } + public void setLineNum(int lineNum) { + this.lineNum = lineNum; + } + } + + public void addLineNumberItem(LineNumberItem item){ + this.items.add(item); + } + + public LineNumberTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static LineNumberTable parse(ByteCodeIterator iter, int subAttrNameIndex, int subAttrLen){ + LineNumberTable lineNumTable = new LineNumberTable(subAttrNameIndex, subAttrLen); + int lineNumTableLen = iter.nextU2toInt(); + for(int i = 0; i < lineNumTableLen; i ++){ + int startPC = iter.nextU2toInt(); + int lineNum = iter.nextU2toInt(); + LineNumberItem lineNumItem = new LineNumberItem(); + lineNumItem.setStartPC(startPC); + lineNumItem.setLineNum(lineNum); + lineNumTable.addLineNumberItem(lineNumItem); + } + return lineNumTable; + } + +} diff --git a/group11/1310368322/src/Mini_JVM/com/coderising/jvm/attr/LocalVariableItem.java b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/attr/LocalVariableItem.java new file mode 100644 index 0000000000..842e1d0a96 --- /dev/null +++ b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/attr/LocalVariableItem.java @@ -0,0 +1,41 @@ +package com.coderising.jvm.attr; + +public class LocalVariableItem { + + private int startPC;// ֲڿʼʱֽƫ + private int length; // ֽij + private int nameIndex; // ֲ + private int descIndex; // ֲ + private int index; // ֲջ֡еľֲе slot λ + + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getNameIndex() { + return nameIndex; + } + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + public int getDescIndex() { + return descIndex; + } + public void setDescIndex(int descIndex) { + this.descIndex = descIndex; + } + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } +} diff --git a/group11/1310368322/src/Mini_JVM/com/coderising/jvm/attr/LocalVariableTable.java b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/attr/LocalVariableTable.java new file mode 100644 index 0000000000..757f28918b --- /dev/null +++ b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/attr/LocalVariableTable.java @@ -0,0 +1,41 @@ +package com.coderising.jvm.attr; + +import java.util.ArrayList; +import java.util.List; + +import com.coderising.jvm.loader.ByteCodeIterator; + +public class LocalVariableTable extends AttributeInfo{ + + List<LocalVariableItem> items = new ArrayList<LocalVariableItem>(); + + public LocalVariableTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static LocalVariableTable parse(ByteCodeIterator iter, int subAttrName, int subAttrLen){ + + LocalVariableTable locVarTable = new LocalVariableTable(subAttrName, subAttrLen); + int localVarTableLen = iter.nextU2toInt(); + for(int i = 0; i < localVarTableLen; i++){ + int startPC = iter.nextU2toInt(); + int length = iter.nextU2toInt(); + int nameIndex = iter.nextU2toInt(); + int descIndex = iter.nextU2toInt(); + int index = iter.nextU2toInt(); + LocalVariableItem locVarItem = new LocalVariableItem(); + locVarItem.setStartPC(startPC); + locVarItem.setLength(length); + locVarItem.setNameIndex(nameIndex); + locVarItem.setDescIndex(descIndex); + locVarItem.setIndex(index); + locVarTable.addLocalVariableItem(locVarItem); + } + + return locVarTable; + } + private void addLocalVariableItem(LocalVariableItem item) { + this.items.add(item); + } + +} diff --git a/group11/1310368322/src/Mini_JVM/com/coderising/jvm/attr/StackMapTable.java b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/attr/StackMapTable.java new file mode 100644 index 0000000000..9df44fb5ca --- /dev/null +++ b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/attr/StackMapTable.java @@ -0,0 +1,29 @@ +package com.coderising.jvm.attr; + +import com.coderising.jvm.loader.ByteCodeIterator; + +public class StackMapTable extends AttributeInfo{ + + private String originalCode; + + public StackMapTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static StackMapTable parse(ByteCodeIterator iter){ + int index = iter.nextU2toInt(); + int len = iter.nextU4toInt(); + StackMapTable t = new StackMapTable(index,len); + + //StackMapTable̫ӣ ٴ ֻԭʼĴ + String code = iter.nextUxToHexString(len); + t.setOriginalCode(code); + + return t; + } + + private void setOriginalCode(String code) { + this.originalCode = code; + + } +} diff --git a/group11/1310368322/src/FifthHomework/jvm/clz/AccessFlag.java b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/clz/AccessFlag.java similarity index 100% rename from group11/1310368322/src/FifthHomework/jvm/clz/AccessFlag.java rename to group11/1310368322/src/Mini_JVM/com/coderising/jvm/clz/AccessFlag.java diff --git a/group11/1310368322/src/FifthHomework/jvm/clz/ClassFile.java b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/clz/ClassFile.java similarity index 78% rename from group11/1310368322/src/FifthHomework/jvm/clz/ClassFile.java rename to group11/1310368322/src/Mini_JVM/com/coderising/jvm/clz/ClassFile.java index 3bf1a8c56e..4492d2df9e 100644 --- a/group11/1310368322/src/FifthHomework/jvm/clz/ClassFile.java +++ b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/clz/ClassFile.java @@ -1,7 +1,12 @@ package com.coderising.jvm.clz; +import java.util.ArrayList; +import java.util.List; + import com.coderising.jvm.constant.ClassInfo; import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.field.Field; +import com.coderising.jvm.method.Method; public class ClassFile { private int minorVersion; @@ -10,6 +15,8 @@ public class ClassFile { private AccessFlag accessFlag;// ڳ֮ private ClassIndex clzIndex;// ڷʱ־֮, ͽӿ private ConstantPool pool; + private List<Field> fields = new ArrayList<Field>(); + private List<Method> methods = new ArrayList<Method>(); public AccessFlag getAccessFlag(){ @@ -48,6 +55,19 @@ public void setConstantPool(ConstantPool pool){ this.pool = pool; } + public void addField(Field f){ + this.fields.add(f); + } + public List<Field> getFields(){ + return this.fields; + } + public void addMethod(Method m){ + this.methods.add(m); + } + public List<Method> getMethods() { + return methods; + } + public void print(){ if(this.accessFlag.isPublicClass()){ System.out.println("Access flag : public "); diff --git a/group11/1310368322/src/FifthHomework/jvm/clz/ClassIndex.java b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/clz/ClassIndex.java similarity index 100% rename from group11/1310368322/src/FifthHomework/jvm/clz/ClassIndex.java rename to group11/1310368322/src/Mini_JVM/com/coderising/jvm/clz/ClassIndex.java diff --git a/group11/1310368322/src/FifthHomework/jvm/constant/ClassInfo.java b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/constant/ClassInfo.java similarity index 100% rename from group11/1310368322/src/FifthHomework/jvm/constant/ClassInfo.java rename to group11/1310368322/src/Mini_JVM/com/coderising/jvm/constant/ClassInfo.java diff --git a/group11/1310368322/src/FifthHomework/jvm/constant/ConstantInfo.java b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/constant/ConstantInfo.java similarity index 100% rename from group11/1310368322/src/FifthHomework/jvm/constant/ConstantInfo.java rename to group11/1310368322/src/Mini_JVM/com/coderising/jvm/constant/ConstantInfo.java diff --git a/group11/1310368322/src/FifthHomework/jvm/constant/ConstantPool.java b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/constant/ConstantPool.java similarity index 93% rename from group11/1310368322/src/FifthHomework/jvm/constant/ConstantPool.java rename to group11/1310368322/src/Mini_JVM/com/coderising/jvm/constant/ConstantPool.java index 9dbd3ed9ef..82565b7f59 100644 --- a/group11/1310368322/src/FifthHomework/jvm/constant/ConstantPool.java +++ b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/constant/ConstantPool.java @@ -20,6 +20,7 @@ public ConstantInfo getConstantInfo(int index){ } public String getUTF8String(int index){ + System.out.println("index: " + index); return ((UTF8Info)this.constantInfos.get(index)).getValue(); } diff --git a/group11/1310368322/src/FifthHomework/jvm/constant/FieldRefInfo.java b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/constant/FieldRefInfo.java similarity index 100% rename from group11/1310368322/src/FifthHomework/jvm/constant/FieldRefInfo.java rename to group11/1310368322/src/Mini_JVM/com/coderising/jvm/constant/FieldRefInfo.java diff --git a/group11/1310368322/src/FifthHomework/jvm/constant/MethodRefInfo.java b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/constant/MethodRefInfo.java similarity index 100% rename from group11/1310368322/src/FifthHomework/jvm/constant/MethodRefInfo.java rename to group11/1310368322/src/Mini_JVM/com/coderising/jvm/constant/MethodRefInfo.java diff --git a/group11/1310368322/src/FifthHomework/jvm/constant/NameAndTypeInfo.java b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/constant/NameAndTypeInfo.java similarity index 100% rename from group11/1310368322/src/FifthHomework/jvm/constant/NameAndTypeInfo.java rename to group11/1310368322/src/Mini_JVM/com/coderising/jvm/constant/NameAndTypeInfo.java diff --git a/group11/1310368322/src/FifthHomework/jvm/constant/NullConstantInfo.java b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/constant/NullConstantInfo.java similarity index 100% rename from group11/1310368322/src/FifthHomework/jvm/constant/NullConstantInfo.java rename to group11/1310368322/src/Mini_JVM/com/coderising/jvm/constant/NullConstantInfo.java diff --git a/group11/1310368322/src/FifthHomework/jvm/constant/StringInfo.java b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/constant/StringInfo.java similarity index 100% rename from group11/1310368322/src/FifthHomework/jvm/constant/StringInfo.java rename to group11/1310368322/src/Mini_JVM/com/coderising/jvm/constant/StringInfo.java diff --git a/group11/1310368322/src/FifthHomework/jvm/constant/UTF8Info.java b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/constant/UTF8Info.java similarity index 100% rename from group11/1310368322/src/FifthHomework/jvm/constant/UTF8Info.java rename to group11/1310368322/src/Mini_JVM/com/coderising/jvm/constant/UTF8Info.java diff --git a/group11/1310368322/src/Mini_JVM/com/coderising/jvm/field/Field.java b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/field/Field.java new file mode 100644 index 0000000000..9e110b1867 --- /dev/null +++ b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/field/Field.java @@ -0,0 +1,43 @@ +package com.coderising.jvm.field; + +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.loader.ByteCodeIterator; + +public class Field { + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private ConstantPool pool; + public int getNameIndex(){ + return nameIndex; + } + public int getDescIndex(){ + return descriptorIndex; + } + public String toString(){ + return pool.getUTF8String(nameIndex) + ":" + pool.getUTF8String(descriptorIndex); + } + public Field(int accessFlag, int nameIndex, int descriptorIndex, ConstantPool pool){ + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + this.pool = pool; + } + + + public static Field parse(ConstantPool pool, ByteCodeIterator iter){ + int accessFlag = iter.nextU2toInt(); + int nameIndex = iter.nextU2toInt(); + int descriptorIndex = iter.nextU2toInt(); + int attrLen = iter.nextU2toInt(); + if(attrLen > 0){ + throw new RuntimeException("Field attributes has not been implemented"); + } + Field field = new Field(accessFlag,nameIndex,descriptorIndex,pool); + + return field; + } + + +} diff --git a/group11/1310368322/src/FifthHomework/jvm/loader/ByteCodeIterator.java b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/loader/ByteCodeIterator.java similarity index 74% rename from group11/1310368322/src/FifthHomework/jvm/loader/ByteCodeIterator.java rename to group11/1310368322/src/Mini_JVM/com/coderising/jvm/loader/ByteCodeIterator.java index 4d740d8149..41516cd506 100644 --- a/group11/1310368322/src/FifthHomework/jvm/loader/ByteCodeIterator.java +++ b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/loader/ByteCodeIterator.java @@ -42,4 +42,20 @@ public String nextU4ToHexString(){ } return buffer.toString(); } + + public String nextUxToHexString(int len) { + + StringBuffer buffer = new StringBuffer(); + for(int i = 0; i < len; 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/Mini_JVM/com/coderising/jvm/loader/ClassFileLoader.java similarity index 100% rename from group11/1310368322/src/FifthHomework/jvm/loader/ClassFileLoader.java rename to group11/1310368322/src/Mini_JVM/com/coderising/jvm/loader/ClassFileLoader.java diff --git a/group11/1310368322/src/FifthHomework/jvm/loader/ClassFileParser.java b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/loader/ClassFileParser.java similarity index 81% rename from group11/1310368322/src/FifthHomework/jvm/loader/ClassFileParser.java rename to group11/1310368322/src/Mini_JVM/com/coderising/jvm/loader/ClassFileParser.java index a2de56dfc7..43e3796ef5 100644 --- a/group11/1310368322/src/FifthHomework/jvm/loader/ClassFileParser.java +++ b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/loader/ClassFileParser.java @@ -15,6 +15,8 @@ import com.coderising.jvm.constant.NullConstantInfo; import com.coderising.jvm.constant.StringInfo; import com.coderising.jvm.constant.UTF8Info; +import com.coderising.jvm.field.Field; +import com.coderising.jvm.method.Method; /* * һֽ飬ɶа ClassFile @@ -31,7 +33,7 @@ public ClassFile parse(byte[] codes){ } clzFile.setMinorVersion(iter.nextU2toInt()); clzFile.setMajorVersion(iter.nextU2toInt()); - + // ȡ ConstantPool pool = parseConstantPool(iter); AccessFlag accessFlag = parseAccessFlag(iter); @@ -40,10 +42,17 @@ public ClassFile parse(byte[] codes){ clzFile.setClassIndex(clzIndex); clzFile.setConstantPool(pool);// м볣 + parseInterfaces(iter); + parseFields(clzFile,iter); + parseMethods(clzFile,iter); + return clzFile; } - + + + + private AccessFlag parseAccessFlag(ByteCodeIterator iter){ int accessFlagValue = iter.nextU2toInt(); AccessFlag accessFlag = new AccessFlag(accessFlagValue); @@ -127,4 +136,34 @@ private ConstantPool parseConstantPool(ByteCodeIterator iter){ } return pool; } + + private void parseInterfaces(ByteCodeIterator iter) { + int interfacesCount = iter.nextU2toInt(); + System.out.println("interfacesCount: " + interfacesCount); + if(interfacesCount > 0){ + throw new RuntimeException("interfaces has not been implemented"); + } + + } + + private void parseFields(ClassFile clzFile, ByteCodeIterator iter) { + int fieldsCount = iter.nextU2toInt(); + System.out.println("fieldsCount: " + fieldsCount); + for(int i = 0; i < fieldsCount; i++){ + Field f = Field.parse(clzFile.getConstantPool(), iter); + clzFile.addField(f); + } + + } + + private void parseMethods(ClassFile clzFile, ByteCodeIterator iter) { + int methodsCount = iter.nextU2toInt(); + System.out.println("methodsCount: " + methodsCount); + for(int i = 0; i < methodsCount; i++){ + Method m = Method.parse(clzFile, iter); + clzFile.addMethod(m); + } + + } + } diff --git a/group11/1310368322/src/FifthHomework/jvm/loader/TestJVM.java b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/loader/TestJVM.java similarity index 100% rename from group11/1310368322/src/FifthHomework/jvm/loader/TestJVM.java rename to group11/1310368322/src/Mini_JVM/com/coderising/jvm/loader/TestJVM.java diff --git a/group11/1310368322/src/Mini_JVM/com/coderising/jvm/method/Method.java b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/method/Method.java new file mode 100644 index 0000000000..572880f729 --- /dev/null +++ b/group11/1310368322/src/Mini_JVM/com/coderising/jvm/method/Method.java @@ -0,0 +1,68 @@ +package com.coderising.jvm.method; + +import com.coderising.jvm.attr.AttributeInfo; +import com.coderising.jvm.attr.CodeAttr; +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.loader.ByteCodeIterator; + +public class Method { + + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private CodeAttr codeAttr; + + private ClassFile clzFile; + + public int getNameIndex() { + return nameIndex; + } + + public int getDescriptorIndex() { + return descriptorIndex; + } + + public CodeAttr getCodeAttr() { + return codeAttr; + } + + public void setCodeAttr(CodeAttr code) { + this.codeAttr = code; + } + + public ClassFile getClzFile() { + return clzFile; + } + + public Method(ClassFile clzFile,int accessFlag, int nameIndex, int descriptorIndex) { + this.clzFile = clzFile; + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + } + + + public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ + int accessFlag = iter.nextU2toInt(); + int nameIndex = iter.nextU2toInt(); + int descriptor = iter.nextU2toInt(); + int attrCount = iter.nextU2toInt(); + + + Method method = new Method(clzFile,accessFlag,nameIndex,descriptor); + System.out.println("attrCount: " + attrCount); + // methodе + for(int i = 0; i < attrCount; i++){ + int attrNameIndex = iter.nextU2toInt(); + String attrName = clzFile.getConstantPool().getUTF8String(attrNameIndex); + System.out.println(attrName); + if(AttributeInfo.CODE.equalsIgnoreCase(attrName)){ + CodeAttr attrCode = CodeAttr.parse(clzFile, iter); + method.setCodeAttr(attrCode); + } + + } + return method; + } +} diff --git a/group11/1310368322/src/ThirdHomework/Download/DownloadThread.java b/group11/1310368322/src/data_structure/BigHomework/Download/DownloadThread.java similarity index 100% rename from group11/1310368322/src/ThirdHomework/Download/DownloadThread.java rename to group11/1310368322/src/data_structure/BigHomework/Download/DownloadThread.java diff --git a/group11/1310368322/src/ThirdHomework/Download/FileDownloader.java b/group11/1310368322/src/data_structure/BigHomework/Download/FileDownloader.java similarity index 100% rename from group11/1310368322/src/ThirdHomework/Download/FileDownloader.java rename to group11/1310368322/src/data_structure/BigHomework/Download/FileDownloader.java diff --git a/group11/1310368322/src/ThirdHomework/Download/api/Connection.java b/group11/1310368322/src/data_structure/BigHomework/Download/api/Connection.java similarity index 100% rename from group11/1310368322/src/ThirdHomework/Download/api/Connection.java rename to group11/1310368322/src/data_structure/BigHomework/Download/api/Connection.java diff --git a/group11/1310368322/src/ThirdHomework/Download/api/ConnectionException.java b/group11/1310368322/src/data_structure/BigHomework/Download/api/ConnectionException.java similarity index 100% rename from group11/1310368322/src/ThirdHomework/Download/api/ConnectionException.java rename to group11/1310368322/src/data_structure/BigHomework/Download/api/ConnectionException.java diff --git a/group11/1310368322/src/ThirdHomework/Download/api/ConnectionManager.java b/group11/1310368322/src/data_structure/BigHomework/Download/api/ConnectionManager.java similarity index 100% rename from group11/1310368322/src/ThirdHomework/Download/api/ConnectionManager.java rename to group11/1310368322/src/data_structure/BigHomework/Download/api/ConnectionManager.java diff --git a/group11/1310368322/src/ThirdHomework/Download/api/DownloadListener.java b/group11/1310368322/src/data_structure/BigHomework/Download/api/DownloadListener.java similarity index 100% rename from group11/1310368322/src/ThirdHomework/Download/api/DownloadListener.java rename to group11/1310368322/src/data_structure/BigHomework/Download/api/DownloadListener.java diff --git a/group11/1310368322/src/ThirdHomework/Download/impl/ConnectionImpl.java b/group11/1310368322/src/data_structure/BigHomework/Download/impl/ConnectionImpl.java similarity index 100% rename from group11/1310368322/src/ThirdHomework/Download/impl/ConnectionImpl.java rename to group11/1310368322/src/data_structure/BigHomework/Download/impl/ConnectionImpl.java diff --git a/group11/1310368322/src/ThirdHomework/Download/impl/ConnectionManagerImpl.java b/group11/1310368322/src/data_structure/BigHomework/Download/impl/ConnectionManagerImpl.java similarity index 100% rename from group11/1310368322/src/ThirdHomework/Download/impl/ConnectionManagerImpl.java rename to group11/1310368322/src/data_structure/BigHomework/Download/impl/ConnectionManagerImpl.java diff --git a/group11/1310368322/src/FirstHomework/BaseDataStructure/ArrayList.java b/group11/1310368322/src/data_structure/baseDataStructure_1/ArrayList.java similarity index 100% rename from group11/1310368322/src/FirstHomework/BaseDataStructure/ArrayList.java rename to group11/1310368322/src/data_structure/baseDataStructure_1/ArrayList.java diff --git a/group11/1310368322/src/FirstHomework/BaseDataStructure/LinkedList.java b/group11/1310368322/src/data_structure/baseDataStructure_1/LinkedList.java similarity index 100% rename from group11/1310368322/src/FirstHomework/BaseDataStructure/LinkedList.java rename to group11/1310368322/src/data_structure/baseDataStructure_1/LinkedList.java diff --git a/group11/1310368322/src/SecondHomework/BaseDataStructure/ArrayUtil.java b/group11/1310368322/src/data_structure/baseDataStructure_2/ArrayUtil.java similarity index 100% rename from group11/1310368322/src/SecondHomework/BaseDataStructure/ArrayUtil.java rename to group11/1310368322/src/data_structure/baseDataStructure_2/ArrayUtil.java diff --git a/group11/1310368322/src/ThirdHomework/BaseDataStructure/LinkedList.java b/group11/1310368322/src/data_structure/baseDataStructure_3/LinkedList.java similarity index 100% rename from group11/1310368322/src/ThirdHomework/BaseDataStructure/LinkedList.java rename to group11/1310368322/src/data_structure/baseDataStructure_3/LinkedList.java diff --git a/group11/1310368322/src/FourthHomework/BaseDataStructure/LRUPageFrame.java b/group11/1310368322/src/data_structure/baseDataStructure_4_LRU/LRUPageFrame.java similarity index 100% rename from group11/1310368322/src/FourthHomework/BaseDataStructure/LRUPageFrame.java rename to group11/1310368322/src/data_structure/baseDataStructure_4_LRU/LRUPageFrame.java diff --git a/group11/1310368322/src/FifthHomework/DataStructure_5_Stack/StackUtil.java b/group11/1310368322/src/data_structure/baseDataStructure_5_Stack/StackUtil.java similarity index 100% rename from group11/1310368322/src/FifthHomework/DataStructure_5_Stack/StackUtil.java rename to group11/1310368322/src/data_structure/baseDataStructure_5_Stack/StackUtil.java diff --git a/group11/1310368322/src/data_structure/baseDataStructure_6InfixExpr/InfixExpr.java b/group11/1310368322/src/data_structure/baseDataStructure_6InfixExpr/InfixExpr.java new file mode 100644 index 0000000000..c7285dd9a2 --- /dev/null +++ b/group11/1310368322/src/data_structure/baseDataStructure_6InfixExpr/InfixExpr.java @@ -0,0 +1,106 @@ +package dataStructure_6InfixExpr; + +import java.util.Stack; + +public class InfixExpr { + + String expr = null; + + public InfixExpr(String expr){ + this.expr = expr; + } + + public double evaluate(){ + + Stack operatorStack = new Stack(); + Stack<Double> operandStack = new Stack<Double>(); + + int tag = -1; + for(int i = 0; i < expr.length(); i++){ + if(operatorStack.isEmpty()){ + tag = -1; + } + char c = expr.charAt(i); + if( tag == 1 && (c == '+' || c == '-' || c == '*' || c == '/')){ + System.out.println("i= " + i); + char down = (char) operatorStack.pop(); + System.out.println("down: " + down); + System.out.println("up: " + c); + if(judgePriority(down,c)){ + double operand = (double) operandStack.pop(); + double operanded = (double) operandStack.pop(); + operandStack.push(operator(down,operanded,operand)); + operatorStack.push(c); + }else{ + operatorStack.push(down); + operatorStack.push(c); + } + }else if(tag == -1 && (c == '+' || c == '-' || c == '*' || c == '/')){ + tag = 1; + operatorStack.push(c); + + }else{ + String number = extractNumber(i,expr); + int length = number.length(); + i += length-1; + double operand = Double.parseDouble(number); + operandStack.push(operand); + } + } + + while(!operatorStack.isEmpty()){ + char operator = (char) operatorStack.pop(); + System.out.println(operator); + double operand = (double) operandStack.pop(); + System.out.println(operand); + double operanded = (double) operandStack.pop(); + System.out.println(operanded); + operandStack.push( operator(operator,operanded,operand)); + } + + return (double) operandStack.pop(); + } + + private String extractNumber(int i, String expr2) { + + StringBuffer buffer = new StringBuffer(); + while( (expr.charAt(i) != '+') && (expr.charAt(i) != '-') && (expr.charAt(i) != '*') && (expr.charAt(i) != '/') ){ + buffer.append(expr.charAt(i)); + if(i >= expr2.length()-1){ + break; + } + i++; + } + return buffer.toString(); + } + + private boolean judgePriority(char down, char up) { + boolean tag = false; + + if((up == '+' || up == '-') && (down == '*' || down == '/')){ + tag = true; + }else if( (up == '*') && (down == '/')){ + tag = true; + }else if( (up == '/') && (down == '*')){ + tag = true; + }else if( (up == '+') && (down == '-') ){ + tag = true; + }else if( (up == '-') && (down == '+') ){ + tag = true; + } + return tag; + } + + private double operator(char operator, double operanded, double operand) { + double result = 0; + + switch(operator){ + case '+': result = operanded + operand; break; + case '-': result = operanded - operand; break; + case '*': System.out.println("˷"); result = operanded * operand; break; + case '/': result = operanded / operand; break; + } + + return result; + } +} diff --git a/group11/1310368322/test/FifthHomework/DataStructure_5_Stack/TestSwitch.java b/group11/1310368322/test/FifthHomework/DataStructure_5_Stack/TestSwitch.java deleted file mode 100644 index a14ae1683b..0000000000 --- a/group11/1310368322/test/FifthHomework/DataStructure_5_Stack/TestSwitch.java +++ /dev/null @@ -1,15 +0,0 @@ -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/TestArray.java b/group11/1310368322/test/FifthHomework/jvm/loader/TestArray.java deleted file mode 100644 index 6d78273d8c..0000000000 --- a/group11/1310368322/test/FifthHomework/jvm/loader/TestArray.java +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 13bfb372fb..0000000000 --- a/group11/1310368322/test/FifthHomework/jvm/loader/TestArrayList.java +++ /dev/null @@ -1,14 +0,0 @@ -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 deleted file mode 100644 index d0ef456005..0000000000 --- a/group11/1310368322/test/FifthHomework/jvm/loader/TestByteArrayToHexString.java +++ /dev/null @@ -1,15 +0,0 @@ -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 deleted file mode 100644 index 8bde4d5974..0000000000 --- a/group11/1310368322/test/FifthHomework/jvm/loader/TestByteArrayToInt.java +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index 2c51afb572..0000000000 --- a/group11/1310368322/test/FifthHomework/jvm/loader/TestByteToInt.java +++ /dev/null @@ -1,12 +0,0 @@ -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-128intͲ룩 - int c = a & 0xFFFF;// λڴнеģҲ˵ǶaIJвģ 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/TestIntegerToHexString.java b/group11/1310368322/test/FifthHomework/jvm/loader/TestIntegerToHexString.java deleted file mode 100644 index b5be2a16d1..0000000000 --- a/group11/1310368322/test/FifthHomework/jvm/loader/TestIntegerToHexString.java +++ /dev/null @@ -1,10 +0,0 @@ -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); - } -} diff --git a/group11/1310368322/test/FourthHomework/JVM/EmployeeV1.java b/group11/1310368322/test/FourthHomework/JVM/EmployeeV1.java deleted file mode 100644 index acbc34c9bb..0000000000 --- a/group11/1310368322/test/FourthHomework/JVM/EmployeeV1.java +++ /dev/null @@ -1,28 +0,0 @@ -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 deleted file mode 100644 index 263384e71a..0000000000 --- a/group11/1310368322/test/FourthHomework/JVM/TestClassFileLoader.java +++ /dev/null @@ -1,67 +0,0 @@ -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(); - } - - - - - - - - -} diff --git a/group11/1310368322/test/FifthHomework/jvm/loader/EmployeeV1.java b/group11/1310368322/test/Mini_JVM/EmployeeV1.java similarity index 100% rename from group11/1310368322/test/FifthHomework/jvm/loader/EmployeeV1.java rename to group11/1310368322/test/Mini_JVM/EmployeeV1.java diff --git a/group11/1310368322/test/FifthHomework/jvm/loader/TestClassFileLoader.java b/group11/1310368322/test/Mini_JVM/TestClassFileLoader.java similarity index 68% rename from group11/1310368322/test/FifthHomework/jvm/loader/TestClassFileLoader.java rename to group11/1310368322/test/Mini_JVM/TestClassFileLoader.java index 3971ac81cd..d1874a0834 100644 --- a/group11/1310368322/test/FifthHomework/jvm/loader/TestClassFileLoader.java +++ b/group11/1310368322/test/Mini_JVM/TestClassFileLoader.java @@ -3,21 +3,24 @@ import static org.junit.Assert.*; import java.io.IOException; +import java.util.List; import org.junit.*; import com.coderising.jvm.clz.ClassFile; import com.coderising.jvm.clz.ClassIndex; import com.coderising.jvm.constant.*; +import com.coderising.jvm.field.Field; +import com.coderising.jvm.method.Method; 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 String classPath1 = "D:/ProgramWorld/Java/Practice/LangSi/2017Ⱥ/bin/com/coderising/jvm/loader/EmployeeV1.class"; + static String classPath2 = "D:/TestClass.class"; static ClassFile clzFile = null; - - + @Test public void test() { @@ -75,8 +78,7 @@ private String byteToHexString(byte[] codes){ @Test public void testVersion() throws IOException{ ClassFileLoader loader = new ClassFileLoader(); - String className = "D:/TestJVM.class"; - clzFile = loader.loadClass(className); + clzFile = loader.loadClass(classPath2); Assert.assertEquals(0, clzFile.getMinorVersion()); Assert.assertEquals(51, clzFile.getMajorVersion()); @@ -86,7 +88,7 @@ public void testVersion() throws IOException{ public void testConstantPool() throws IOException{ ClassFileLoader loader = new ClassFileLoader(); - clzFile = loader.loadClass(path); + clzFile = loader.loadClass(classPath1); ConstantPool pool = clzFile.getConstantPool(); Assert.assertEquals(53, pool.getSize()); @@ -155,7 +157,7 @@ public void testConstantPool() throws IOException{ public void testClassIndex() throws IOException{ ClassFileLoader loader = new ClassFileLoader(); - clzFile = loader.loadClass(path); + clzFile = loader.loadClass(classPath1); ClassIndex clzIndex = clzFile.getClzIndex(); System.out.println("clzIndex="+clzIndex); ClassInfo thisClassInfo = (ClassInfo)clzFile.getConstantPool().getConstantInfo(clzIndex.getThisClassIndex()); @@ -166,9 +168,79 @@ public void testClassIndex() throws IOException{ Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); } - - - + + // --------------------- JVM + @Test + public void testReadFields() throws IOException{ + ClassFileLoader loader = new ClassFileLoader(); + clzFile = loader.loadClass(classPath1); + List<Field> fields = clzFile.getFields(); + Assert.assertEquals(2, fields.size()); + { + Field f = fields.get(0); + Assert.assertEquals("name:Ljava/lang/String;", f.toString()); + } + { + Field f = fields.get(1); + Assert.assertEquals("age:I", f.toString()); + } + } + + @Test + public void testMethods() throws IOException{ + ClassFileLoader loader = new ClassFileLoader(); + clzFile = loader.loadClass(classPath1); + List<Method> methods = clzFile.getMethods(); + ConstantPool pool = clzFile.getConstantPool(); + + { + Method m = methods.get(0); + assertMethodEquals(pool,m, + "<init>", + "(Ljava/lang/String;I)V", + "2ab7000c2a2bb5000f2a1cb50011b1"); + + } + { + Method m = methods.get(1); + assertMethodEquals(pool,m, + "setName", + "(Ljava/lang/String;)V", + "2a2bb5000fb1"); + + } + { + Method m = methods.get(2); + assertMethodEquals(pool,m, + "setAge", + "(I)V", + "2a1bb50011b1"); + } + { + Method m = methods.get(3); + assertMethodEquals(pool,m, + "sayHello", + "()V", + "b2001c1222b60024b1"); + + } + { + Method m = methods.get(4); + assertMethodEquals(pool,m, + "main", + "([Ljava/lang/String;)V", + "bb000159122b101db7002d4c2bb6002fb1"); + } + } + + private void assertMethodEquals(ConstantPool pool,Method m , String expectedName, String expectedDesc,String expectedCode){ + String methodName = pool.getUTF8String(m.getNameIndex()); + String methodDesc = pool.getUTF8String(m.getDescriptorIndex()); + String code = m.getCodeAttr().getCode(); + Assert.assertEquals(expectedName, methodName); + Assert.assertEquals(expectedDesc, methodDesc); + Assert.assertEquals(expectedCode, code); + } } diff --git a/group11/1310368322/test/ThirdHomework/Download/FileDownloaderTest.java b/group11/1310368322/test/data_structure/BigHomework/Download/FileDownloaderTest.java similarity index 100% rename from group11/1310368322/test/ThirdHomework/Download/FileDownloaderTest.java rename to group11/1310368322/test/data_structure/BigHomework/Download/FileDownloaderTest.java diff --git a/group11/1310368322/test/SecondHomwork/BaseDataStructure/ArrayUtilTest.java b/group11/1310368322/test/data_structure/baseDataStructure_2/ArrayUtilTest.java similarity index 100% rename from group11/1310368322/test/SecondHomwork/BaseDataStructure/ArrayUtilTest.java rename to group11/1310368322/test/data_structure/baseDataStructure_2/ArrayUtilTest.java diff --git a/group11/1310368322/test/ThirdHomework/BaseDataStructure/TestLinkedList.java b/group11/1310368322/test/data_structure/baseDataStructure_3/TestLinkedList.java similarity index 100% rename from group11/1310368322/test/ThirdHomework/BaseDataStructure/TestLinkedList.java rename to group11/1310368322/test/data_structure/baseDataStructure_3/TestLinkedList.java diff --git a/group11/1310368322/test/FourthHomework/BaseDataStructure/TestLRUPageFrame.java b/group11/1310368322/test/data_structure/baseDataStructure_4_LRU/TestLRUPageFrame.java similarity index 100% rename from group11/1310368322/test/FourthHomework/BaseDataStructure/TestLRUPageFrame.java rename to group11/1310368322/test/data_structure/baseDataStructure_4_LRU/TestLRUPageFrame.java diff --git a/group11/1310368322/test/FifthHomework/DataStructure_5_Stack/TestStackUtil.java b/group11/1310368322/test/data_structure/baseDataStructure_5_Stack/TestStackUtil.java similarity index 100% rename from group11/1310368322/test/FifthHomework/DataStructure_5_Stack/TestStackUtil.java rename to group11/1310368322/test/data_structure/baseDataStructure_5_Stack/TestStackUtil.java diff --git a/group11/1310368322/test/data_structure/baseDataStructure_6InfixExpr/InfixExpr.java b/group11/1310368322/test/data_structure/baseDataStructure_6InfixExpr/InfixExpr.java new file mode 100644 index 0000000000..c7285dd9a2 --- /dev/null +++ b/group11/1310368322/test/data_structure/baseDataStructure_6InfixExpr/InfixExpr.java @@ -0,0 +1,106 @@ +package dataStructure_6InfixExpr; + +import java.util.Stack; + +public class InfixExpr { + + String expr = null; + + public InfixExpr(String expr){ + this.expr = expr; + } + + public double evaluate(){ + + Stack operatorStack = new Stack(); + Stack<Double> operandStack = new Stack<Double>(); + + int tag = -1; + for(int i = 0; i < expr.length(); i++){ + if(operatorStack.isEmpty()){ + tag = -1; + } + char c = expr.charAt(i); + if( tag == 1 && (c == '+' || c == '-' || c == '*' || c == '/')){ + System.out.println("i= " + i); + char down = (char) operatorStack.pop(); + System.out.println("down: " + down); + System.out.println("up: " + c); + if(judgePriority(down,c)){ + double operand = (double) operandStack.pop(); + double operanded = (double) operandStack.pop(); + operandStack.push(operator(down,operanded,operand)); + operatorStack.push(c); + }else{ + operatorStack.push(down); + operatorStack.push(c); + } + }else if(tag == -1 && (c == '+' || c == '-' || c == '*' || c == '/')){ + tag = 1; + operatorStack.push(c); + + }else{ + String number = extractNumber(i,expr); + int length = number.length(); + i += length-1; + double operand = Double.parseDouble(number); + operandStack.push(operand); + } + } + + while(!operatorStack.isEmpty()){ + char operator = (char) operatorStack.pop(); + System.out.println(operator); + double operand = (double) operandStack.pop(); + System.out.println(operand); + double operanded = (double) operandStack.pop(); + System.out.println(operanded); + operandStack.push( operator(operator,operanded,operand)); + } + + return (double) operandStack.pop(); + } + + private String extractNumber(int i, String expr2) { + + StringBuffer buffer = new StringBuffer(); + while( (expr.charAt(i) != '+') && (expr.charAt(i) != '-') && (expr.charAt(i) != '*') && (expr.charAt(i) != '/') ){ + buffer.append(expr.charAt(i)); + if(i >= expr2.length()-1){ + break; + } + i++; + } + return buffer.toString(); + } + + private boolean judgePriority(char down, char up) { + boolean tag = false; + + if((up == '+' || up == '-') && (down == '*' || down == '/')){ + tag = true; + }else if( (up == '*') && (down == '/')){ + tag = true; + }else if( (up == '/') && (down == '*')){ + tag = true; + }else if( (up == '+') && (down == '-') ){ + tag = true; + }else if( (up == '-') && (down == '+') ){ + tag = true; + } + return tag; + } + + private double operator(char operator, double operanded, double operand) { + double result = 0; + + switch(operator){ + case '+': result = operanded + operand; break; + case '-': result = operanded - operand; break; + case '*': System.out.println("˷"); result = operanded * operand; break; + case '/': result = operanded / operand; break; + } + + return result; + } +} From 7717f0a03030cfdaef9a827b7dcf7c42750ffa31 Mon Sep 17 00:00:00 2001 From: lzb <lzbferrari@gmail.com> Date: Sun, 16 Apr 2017 15:55:12 +0800 Subject: [PATCH 272/287] =?UTF-8?q?=E4=BD=9C=E4=B8=9A=E8=A1=A5=E5=AE=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/me/lzb/basic/InfixExpr.java | 144 ++++++++++++++- .../src/main/java/me/lzb/basic/StackUtil.java | 173 ++++++++++++++---- .../test/java/me/lzb/basic/StackUtilTest.java | 1 + 3 files changed, 280 insertions(+), 38 deletions(-) diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/InfixExpr.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/InfixExpr.java index cd682a65c2..e30cc00cc2 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/InfixExpr.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/InfixExpr.java @@ -1,10 +1,15 @@ package me.lzb.basic; +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + /** * Created by LZB on 2017/4/15. */ public class InfixExpr { + private String expr; public InfixExpr(String expr) { @@ -13,7 +18,144 @@ public InfixExpr(String expr) { public float evaluate() { - return 0.0f; + List<Node> list = processExpr(); + + Stack<String> symbolStack = new Stack<>(); + Stack<Float> numberStack = new Stack<>(); + + boolean calLevel2 = false; + for (Node n : list) { + if (n.isNumber) { + numberStack.push(n.number); + if (calLevel2) { + calculate(symbolStack, numberStack, false); + calLevel2 = false; + } + } else { + symbolStack.push(n.symbol); + + if (n.isLevel2()) { + calLevel2 = true; + } + } + } + + + Stack<Float> tn = new Stack<>(); + int nsize = numberStack.size(); + for (int i = 0; i < nsize; i++) { + tn.push(numberStack.pop()); + } + + numberStack = tn; + + + Stack<String> ts = new Stack<>(); + int ssize = symbolStack.size(); + for (int i = 0; i < ssize; i++) { + ts.push(symbolStack.pop()); + } + + symbolStack = ts; + + + while (!symbolStack.isEmpty()) { + calculate(symbolStack, numberStack, true); + } + + + return numberStack.pop(); + } + + + + private List<Node> processExpr() { + List<Node> list = new ArrayList<>(); + char[] array = this.expr.toCharArray(); + String number = ""; + for (int i = 0; i < array.length; i++) { + if (Character.isDigit(array[i])) { + number = number + String.valueOf(array[i]); + } else { + Node num = new Node(Float.valueOf(number), null, true, -1); + number = ""; + int calLevel = "+-".indexOf(array[i]) >= 0 ? 1 : 2; + Node sym = new Node(0, String.valueOf(array[i]), false, calLevel); + list.add(num); + list.add(sym); + } + } + + Node num = new Node(Float.valueOf(number), null, true, -1); + list.add(num); + return list; + } + + + private void calculate(Stack<String> symbolStack, Stack<Float> numberStack, boolean isRe) { + if (symbolStack.isEmpty()) { + return; + } + + + String symbole = symbolStack.pop(); + + float right; + float left; + + if(isRe){ + left = numberStack.pop(); + right = numberStack.pop(); + }else { + right = numberStack.pop(); + left = numberStack.pop(); + } + + + + float r = calculate(symbole, left, right); + + numberStack.push(r); + } + + + private float calculate(String symbol, float left, float right) { + if ("+".equals(symbol)) { + return left + right; + } + + if ("-".equals(symbol)) { + return left - right; + } + + if ("*".equals(symbol)) { + return left * right; + } + + if ("/".equals(symbol)) { + return left / right; + } + + return 0; + } + + + private class Node { + float number; + String symbol; + boolean isNumber; + int calLevel;//加减1,乘除2 + + public Node(float number, String symbol, boolean isNumber, int calLevel) { + this.number = number; + this.symbol = symbol; + this.isNumber = isNumber; + this.calLevel = calLevel; + } + + private boolean isLevel2() { + return calLevel == 2; + } } } diff --git a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/StackUtil.java b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/StackUtil.java index 8fd3e94d19..547eb6105f 100644 --- a/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/StackUtil.java +++ b/group24/1148285693/learning2017/learning-basic/src/main/java/me/lzb/basic/StackUtil.java @@ -1,56 +1,155 @@ package me.lzb.basic; + import java.util.Stack; public class StackUtil { - public static void bad_reverse(Stack<Integer> s) { + public static void bad_reverse(Stack<Integer> s) { + + + } + + /** + * 假设栈中的元素是Integer, 从栈顶到栈底是 : 5,4,3,2,1 调用该方法后, 元素次序变为: 1,2,3,4,5 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + */ + public static void reverse(Stack<Integer> s) { + Stack<Integer> t = new Stack<>(); + for (Integer i : s) { + t.push(i); + } + + s.clear(); + + int size = t.size(); + for (int i = 0; i < size; i++) { + s.push(t.pop()); + } + + } + + public static void addToBottom(Stack<Integer> s, Integer value) { + Stack<Integer> t = new Stack<>(); + int size = s.size(); + for (int i = 0; i < size; i++) { + t.push(s.pop()); + } + + s.clear(); + + s.push(value); + + for (int i = 0; i < size; i++) { + s.push(t.pop()); + } + + } + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s, Object o) { + Stack t = new Stack(); + int size = s.size(); + for (int i = 0; i < size; i++) { + Object ro = s.pop(); + if (!ro.equals(o)) { + t.push(ro); + } + } + + s.clear(); + + int sizet = t.size(); + for (int i = 0; i < sizet; i++) { + s.push(t.pop()); + } + + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param len + * @return + */ + public static Object[] getTop(Stack s, int len) { + Object[] array = new Object[len]; + for (int i = 0; i < len; i++) { + array[i] = s.pop(); + } + + for (int i = len - 1; i >= 0; i--) { + s.push(array[i]); + } + return array; + } + + /** + * 字符串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[] array = s.toCharArray(); + Stack<String> stack = new Stack<>(); + for (int i = 0; i < array.length; i++) { + stack.push(String.valueOf(array[i])); + } + + int a = -1; + int b = -1; + int c = -1; - } - /** - * 假设栈中的元素是Integer, 从栈顶到栈底是 : 5,4,3,2,1 调用该方法后, 元素次序变为: 1,2,3,4,5 - * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 - */ - public static void reverse(Stack<Integer> s) { + for (int i = 0; i < array.length; i++) { + String cc = stack.pop(); + if ("{}".indexOf(cc) >= 0) { + if (a == -1) { + a = i; + } else { + if (stack.size() != a) { + return false; + } + } + } + if ("[]".indexOf(cc) >= 0) { - } - public static void addToBottom(Stack<Integer> s, Integer value){ + if (b == -1) { + b = i; + } else { + if (stack.size() != b) { + return false; + } + } + } - } - /** - * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 - * - * @param o - */ - public static void remove(Stack s,Object o) { + if ("()".indexOf(cc) >= 0) { - } + if (c == -1) { + c = i; + } else { + if (stack.size() != c) { + return false; + } + } - /** - * 从栈顶取得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; - } + } + return true; + } } diff --git a/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/basic/StackUtilTest.java b/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/basic/StackUtilTest.java index 1fa9396c0a..48589f57d3 100644 --- a/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/basic/StackUtilTest.java +++ b/group24/1148285693/learning2017/learning-basic/src/test/java/me/lzb/basic/StackUtilTest.java @@ -66,6 +66,7 @@ public void testGetTop() { Assert.assertEquals(4, values[1]); Assert.assertEquals(3, values[2]); } + Assert.assertEquals("[1, 2, 3, 4, 5]", s.toString()); } @Test From bfc7c0059f371b29751288d9f319ed24090f1e45 Mon Sep 17 00:00:00 2001 From: ZhaoHongxin <zhaohongxin621@126.com> Date: Sun, 16 Apr 2017 17:33:52 +0800 Subject: [PATCH 273/287] =?UTF-8?q?JVM=E7=AC=AC=E4=B8=89=E6=AC=A1=E8=AF=BE?= =?UTF-8?q?=E4=BD=9C=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/com/coderising/jvm/attr/CodeAttr.java | 42 ++++++++++++++++++- .../coderising/jvm/attr/LineNumberTable.java | 16 ++++++- .../jvm/attr/LocalVariableTable.java | 19 ++++++++- .../coderising/jvm/attr/StackMapTable.java | 4 +- .../src/com/coderising/jvm/clz/ClassFile.java | 12 ++++-- .../src/com/coderising/jvm/field/Field.java | 9 ++++ .../jvm/loader/ClassFileParser.java | 13 ++++-- .../src/com/coderising/jvm/method/Method.java | 17 +++++++- .../jvm/test/ClassFileloaderTest.java | 25 ++++++----- 9 files changed, 132 insertions(+), 25 deletions(-) diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java index b0c67b4b93..0e0e46f925 100644 --- a/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java @@ -3,6 +3,7 @@ import com.coderising.jvm.clz.ClassFile; import com.coderising.jvm.constant.ConstantPool; import com.coderising.jvm.loader.ByteCodeIterator; +import com.sun.org.apache.bcel.internal.classfile.Attribute; public class CodeAttr extends AttributeInfo { @@ -40,9 +41,48 @@ public void setLocalVariableTable(LocalVariableTable t) { } public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ + int attrNameIndex = iter.nextU2toInt(); + int attrLen = iter.nextU4toInt(); + int maxStack = iter.nextU2toInt(); + int maxLocals = iter.nextU2toInt(); + int codeLen = iter.nextU4toInt(); + String code = iter.nextUxToHexString(codeLen); + System.out.println("code:" + code); + CodeAttr codeAttr = new CodeAttr(attrNameIndex, attrLen, maxStack, maxLocals, codeLen, code); - return null; + int exceptionTableLen = iter.nextU2toInt(); + if (exceptionTableLen > 0) { + String exTable = iter.nextUxToHexString(exceptionTableLen); + //TODO parse exception_table + System.out.println("exception_table has not been parsed !"); + + } + + int subAttrCount = iter.nextU2toInt(); + System.out.println("subAttrCount:"+subAttrCount); + for (int i = 0; i < subAttrCount; i++) { + int subAttrIndex = iter.nextU2toInt(); + String subAttrName = clzFile.getConstantPool().getUTF8String(subAttrIndex); + System.out.println("subAttrName:" + subAttrName); + + iter.back(2); + + if (AttributeInfo.LINE_NUM_TABLE.equals(subAttrName)) { + LineNumberTable t = LineNumberTable.parse(iter); + codeAttr.setLineNumberTable(t); + + } else if (AttributeInfo.LOCAL_VAR_TABLE.equals(subAttrName)) { + LocalVariableTable t = LocalVariableTable.parse(iter); + codeAttr.setLocalVariableTable(t); + } else if (AttributeInfo.STACK_MAP_TABLE.equals(subAttrName)) { + StackMapTable t = StackMapTable.parse(iter); + codeAttr.setStackMapTable(t); + } else { + throw new RuntimeException("Need to parse " + subAttrName); + } + } + return codeAttr; } private void setStackMapTable(StackMapTable t) { this.stackMapTable = t; diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java index 22941f83b1..c6813a07a2 100644 --- a/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java @@ -33,8 +33,22 @@ public LineNumberTable(int attrNameIndex, int attrLen) { } public static LineNumberTable parse(ByteCodeIterator iter){ + int attrNameIndex = iter.nextU2toInt(); + int attrLen = iter.nextU4toInt(); - return null; + LineNumberTable t = new LineNumberTable(attrNameIndex, attrLen); + + int linNumTableLen = iter.nextU2toInt(); + + for(int i = 0; i < linNumTableLen; i++) { + LineNumberItem m = new LineNumberItem(); + m.setStartPC(iter.nextU2toInt()); + m.setLineNum(iter.nextU2toInt()); + + t.addLineNumberItem(m); + } + + return t; } diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java index fa69dc9bdb..1b1233f748 100644 --- a/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java @@ -17,8 +17,25 @@ public LocalVariableTable(int attrNameIndex, int attrLen) { } public static LocalVariableTable parse(ByteCodeIterator iter){ + int index = iter.nextU2toInt(); + int len = iter.nextU4toInt(); - return null; + LocalVariableTable table = new LocalVariableTable(index, len); + + int itemLen = iter.nextU2toInt(); + + for(int i = 0; i < itemLen; i++) { + LocalVariableItem item = new LocalVariableItem(); + item.setStartPC(iter.nextU2toInt()); + item.setLength(iter.nextU2toInt()); + item.setNameIndex(iter.nextU2toInt()); + item.setDescIndex(iter.nextU2toInt()); + item.setIndex(iter.nextU2toInt()); + + table.addLocalVariableItem(item); + } + + return table; } private void addLocalVariableItem(LocalVariableItem item) { this.items.add(item); diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/StackMapTable.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/StackMapTable.java index 44c5d90d46..caff593698 100644 --- a/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/StackMapTable.java +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/attr/StackMapTable.java @@ -12,8 +12,8 @@ public StackMapTable(int attrNameIndex, int attrLen) { } public static StackMapTable parse(ByteCodeIterator iter){ - int index = iter.nextU2ToInt(); - int len = iter.nextU4ToInt(); + int index = iter.nextU2toInt(); + int len = iter.nextU4toInt(); StackMapTable t = new StackMapTable(index,len); //后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 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 index a43b350531..e38d3091e4 100644 --- a/group05/1094051862/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java @@ -3,6 +3,7 @@ import com.coderising.jvm.constant.ClassInfo; import com.coderising.jvm.constant.ConstantPool; import com.coderising.jvm.field.Field; +import com.coderising.jvm.method.Method; import com.coding.basic.ArrayList; import com.coding.basic.List; public class ClassFile { @@ -15,7 +16,7 @@ public class ClassFile { private ConstantPool pool; private List fields = new ArrayList(); - + private List methods = new ArrayList(); public void addField(Field f) { fields.add(f); } @@ -24,10 +25,9 @@ public List getFields() { return fields; } - public void setFields(List fields) { - this.fields = fields; + public List getMethods() { + return methods; } - public ClassIndex getClzIndex() { return clzIndex; } @@ -87,4 +87,8 @@ private String getSuperClassName(){ ClassInfo superClass = (ClassInfo)this.getConstantPool().getConstantInfo(this.clzIndex.getSuperClassIndex()); return superClass.getClassName(); } + + public void addMethod(Method m) { + methods.add(m); + } } diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/field/Field.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/field/Field.java index 6656090d22..d0009dc59c 100644 --- a/group05/1094051862/mini-jvm/src/com/coderising/jvm/field/Field.java +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/field/Field.java @@ -32,6 +32,7 @@ public static Field parse(ConstantPool pool,ByteCodeIterator iter){ int nameIndex = iter.nextU2toInt(); int descriptorIndex = iter.nextU2toInt(); int attributesCount = iter.nextU2toInt(); + System.out.println("Field AttributesCount: "+attributesCount); Field f = new Field(accessFlag, nameIndex, descriptorIndex, pool); @@ -41,5 +42,13 @@ public static Field parse(ConstantPool pool,ByteCodeIterator iter){ return f; } + + public String toString() { + StringBuffer s = new StringBuffer(); + s.append(pool.getUTF8String(nameIndex)); + s.append(':'); + s.append(pool.getUTF8String(descriptorIndex)); + return s.toString(); + } } 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 index b7ea187e94..09354e7f5f 100644 --- a/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java @@ -14,6 +14,7 @@ import com.coderising.jvm.constant.StringInfo; import com.coderising.jvm.constant.UTF8Info; import com.coderising.jvm.field.Field; +import com.coderising.jvm.method.Method; public class ClassFileParser { @@ -39,12 +40,18 @@ public ClassFile parse(byte[] codes) { parseFields(clzFile, iter); - parrsMethods(clzFile, iter); + parseMethods(clzFile, iter); return clzFile; } - private void parrsMethods(ClassFile clzFile, ByteCodeIterator iter) { - + private void parseMethods(ClassFile clzFile, ByteCodeIterator iter) { + int methodCount = iter.nextU2toInt(); + System.out.println("methodCount:" + methodCount); + for (int i = 0; i < methodCount; i++) { + System.out.println("method :" + (i+1)); + Method m = Method.parse(clzFile, iter); + clzFile.addMethod(m); + } } private void parseFields(ClassFile clzFile, ByteCodeIterator iter) { diff --git a/group05/1094051862/mini-jvm/src/com/coderising/jvm/method/Method.java b/group05/1094051862/mini-jvm/src/com/coderising/jvm/method/Method.java index 8ad9b7d7fa..13a8e41994 100644 --- a/group05/1094051862/mini-jvm/src/com/coderising/jvm/method/Method.java +++ b/group05/1094051862/mini-jvm/src/com/coderising/jvm/method/Method.java @@ -1,6 +1,9 @@ package com.coderising.jvm.method; import com.coderising.jvm.clz.ClassFile; + +import javax.management.RuntimeErrorException; + import com.coderising.jvm.attr.AttributeInfo; import com.coderising.jvm.attr.CodeAttr; import com.coderising.jvm.constant.ConstantPool; @@ -53,15 +56,25 @@ public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ int descriptorIndex = iter.nextU2toInt(); int attributesCount = iter.nextU2toInt(); + System.out.println("Method AttributesCount:"+ attributesCount); + Method m = new Method(clzFile, accessFlag, nameIndex, descriptorIndex); for (int i = 0; i < attributesCount; i++) { int attrNameIndex = iter.nextU2toInt(); + iter.back(2); //解析attrNameIndex就是下面一个属性的一部分,所以下面要解析属性,指针应该回退。 String attrName = clzFile.getConstantPool().getUTF8String(attrNameIndex); - + System.out.println("attrName:"+attrName); + if (AttributeInfo.CODE.equals(attrName)) { + CodeAttr codeAttr = CodeAttr.parse(clzFile, iter); + m.setCodeAttr(codeAttr); + } else { + throw new RuntimeException("The attribute '"+ attrName +"' has not been implemented, " + + "the only implemented attribute is Code attribute !"); + } } - return null; + return m; } } 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 2210a51934..db02c29132 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 @@ -14,7 +14,10 @@ import com.coderising.jvm.constant.MethodRefInfo; import com.coderising.jvm.constant.NameAndTypeInfo; import com.coderising.jvm.constant.UTF8Info; +import com.coderising.jvm.field.Field; import com.coderising.jvm.loader.ClassFileLoader; +import com.coderising.jvm.method.Method; +import com.coding.basic.List; @@ -203,28 +206,28 @@ public void testClassIndex(){ /** * 下面是第三次JVM课应实现的测试用例 */ - /* @Test + @Test public void testReadFields(){ - List<Field> fields = clzFile.getFields(); + List fields = clzFile.getFields(); Assert.assertEquals(2, fields.size()); { - Field f = fields.get(0); + Field f = (Field) fields.get(0); Assert.assertEquals("name:Ljava/lang/String;", f.toString()); } { - Field f = fields.get(1); + Field f = (Field) fields.get(1); Assert.assertEquals("age:I", f.toString()); } } @Test public void testMethods(){ - List<Method> methods = clzFile.getMethods(); + List methods = clzFile.getMethods(); ConstantPool pool = clzFile.getConstantPool(); { - Method m = methods.get(0); + Method m = (Method) methods.get(0); assertMethodEquals(pool,m, "<init>", "(Ljava/lang/String;I)V", @@ -232,7 +235,7 @@ public void testMethods(){ } { - Method m = methods.get(1); + Method m = (Method) methods.get(1); assertMethodEquals(pool,m, "setName", "(Ljava/lang/String;)V", @@ -240,14 +243,14 @@ public void testMethods(){ } { - Method m = methods.get(2); + Method m = (Method) methods.get(2); assertMethodEquals(pool,m, "setAge", "(I)V", "2a1bb50011b1"); } { - Method m = methods.get(3); + Method m = (Method) methods.get(3); assertMethodEquals(pool,m, "sayHello", "()V", @@ -255,7 +258,7 @@ public void testMethods(){ } { - Method m = methods.get(4); + Method m = (Method) methods.get(4); assertMethodEquals(pool,m, "main", "([Ljava/lang/String;)V", @@ -270,5 +273,5 @@ private void assertMethodEquals(ConstantPool pool,Method m , String expectedName Assert.assertEquals(expectedName, methodName); Assert.assertEquals(expectedDesc, methodDesc); Assert.assertEquals(expectedCode, code); - }*/ + } } From 69ee3d3b19ef4115895b76d391678ef85802f5b5 Mon Sep 17 00:00:00 2001 From: xukai <xukai@raycloud.com> Date: Sun, 16 Apr 2017 19:39:26 +0800 Subject: [PATCH 274/287] =?UTF-8?q?jvm=E7=AC=AC=E4=B8=89=E6=AC=A1=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A=E8=A7=A3=E6=9E=90=E5=B1=9E=E6=80=A7=E4=B8=8E=E6=95=B0?= =?UTF-8?q?=E5=AD=A6=E8=BF=90=E7=AE=97=E5=85=AC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/xukai/coderising/stack/InfixExpr.java | 139 ++++++++++++++++++ .../xukai/coderising/stack/InfixExprTest.java | 48 ++++++ .../org/xukai/jvm/attr/AttributeInfo.java | 59 ++++++++ .../java/org/xukai/jvm/attr/CodeAttr.java | 83 +++++++++++ .../org/xukai/jvm/attr/LineNumberTable.java | 55 +++++++ .../org/xukai/jvm/attr/LocalVariableItem.java | 39 +++++ .../xukai/jvm/attr/LocalVariableTable.java | 46 ++++++ .../org/xukai/jvm/attr/StackMapTable.java | 30 ++++ .../java/org/xukai/jvm/clz/ClassFile.java | 23 ++- .../main/java/org/xukai/jvm/field/Field.java | 42 ++++++ .../xukai/jvm/loader/ByteCodeIterator.java | 10 ++ .../org/xukai/jvm/loader/ClassFileParser.java | 43 ++++++ .../java/org/xukai/jvm/method/Method.java | 88 +++++++++++ .../xukai/jvm/test/ClassFileloaderTest.java | 80 +++++++++- 14 files changed, 778 insertions(+), 7 deletions(-) create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/InfixExpr.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/InfixExprTest.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/AttributeInfo.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/CodeAttr.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/LineNumberTable.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/LocalVariableItem.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/LocalVariableTable.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/StackMapTable.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/field/Field.java create mode 100644 group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/method/Method.java diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/InfixExpr.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/InfixExpr.java new file mode 100644 index 0000000000..bec5202645 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/InfixExpr.java @@ -0,0 +1,139 @@ +package org.xukai.coderising.stack; + +import com.google.common.collect.Maps; +import com.sun.org.apache.bcel.internal.generic.IFNE; + +import java.util.HashMap; + +public class InfixExpr { + + public static enum TypeToken { + + add('+',0),substruct('-',1),devide('/',3),plus('*',2); + + TypeToken(char token, Integer priority) { + this.token = token; + this.priority = priority; + } + + private char token; + + private Integer priority; + } + + String expr = null; + + public InfixExpr(String expr) { + this.expr = expr; + } +//3*20+12*5-40/2 + public Double evaluate() { + HashMap<String, Integer> map = new HashMap<>(); + map.put("+",0); + map.put("-",1); + map.put("/",3); + map.put("*",2); + + + Stack tokenStack = new Stack(); + Stack numStack = new Stack(); + char[] chars = expr.toCharArray(); + boolean isNem = true; + for (int i = 0; i < expr.length(); i++) { +// if (expr.charAt(i) == TypeToken.add.token || expr.charAt(i) == TypeToken.substruct.token) { +// isNem = true; +// if (!tokenStack.isEmpty() && (char)tokenStack.pop() == '*') { +// Float num2 = Float.valueOf(numStack.pop().toString()); +// Float num1 = Float.valueOf(numStack.pop().toString()); +// numStack.push(num1*num2); +// } else if (!tokenStack.isEmpty() && ((char)tokenStack.pop()) == '/') { +// Float num2 = Float.valueOf(numStack.pop().toString()); +// Float num1 = Float.valueOf(numStack.pop().toString()); +// numStack.push(num1/num2); +// } +// tokenStack.push(expr.charAt(i)); +// } else if (expr.charAt(i) == TypeToken.devide.token){ +// isNem = true; +// tokenStack.push(expr.charAt(i)); +// } else if (expr.charAt(i) == TypeToken.plus.token){ +// isNem = true; +// tokenStack.push(expr.charAt(i)); +// } else if (String.valueOf(expr.charAt(i)).matches("\\d{1}")){ +// if (isNem) { +// numStack.push((expr.charAt(i))); +// } else { +// numStack.push(numStack.pop().toString() + (expr.charAt(i))); +// } +// isNem = false; +// +// } else { +// throw new RuntimeException(); +// } + String token = (expr.charAt(i)) + ""; + Integer priprity = map.get(token); + + if (priprity != null) { + //表示是运算符 + if (!tokenStack.isEmpty() && priprity < map.get(tokenStack.peek())) { + Float num2 = Float.valueOf(numStack.pop().toString()); + Float num1 = Float.valueOf(numStack.pop().toString()); + String pop = tokenStack.pop()+""; + if (pop.equals("-")) { + numStack.push(num1 - num2); + } else if (pop.equals("*")){ + numStack.push(num1 * num2); + } else if (pop.equals("/")){ + numStack.push(num1 / num2); + } else { + throw new RuntimeException(); + } + + } + tokenStack.push(token); + isNem = true; + } else if(token.matches("\\d{1}")) { + //表示是数字 + if (isNem) { + numStack.push(token); + } else { + numStack.push(numStack.pop().toString() + token); + } + isNem = false; + } else { + throw new RuntimeException(); + } + } + while (!tokenStack.isEmpty()) { + System.out.println(tokenStack.size()); + if (tokenStack.peek().equals("+")) { + Float num2 = Float.valueOf(numStack.pop().toString()); + Float num1 = Float.valueOf(numStack.pop().toString()); + numStack.push(num1+num2+""); + } else if (tokenStack.peek().equals("-")) { + Float num2 = Float.valueOf(numStack.pop().toString()); + Float num1 = Float.valueOf(numStack.pop().toString()); + numStack.push(num1-num2+""); + } else if (tokenStack.peek().equals("/")) { + Float num2 = Float.valueOf(numStack.pop().toString()); + Float num1 = Float.valueOf(numStack.pop().toString()); + numStack.push(num1/num2+""); + } else if (tokenStack.peek().equals("*")) { + Float num2 = Float.valueOf(numStack.pop().toString()); + Float num1 = Float.valueOf(numStack.pop().toString()); + numStack.push(num1*num2+""); + } else { + throw new RuntimeException(); + } + tokenStack.pop(); + } +// System.out.println(Double.valueOf(numStack.pop().toString())); + return Double.valueOf(numStack.pop().toString()); + } + + public static void main(String[] args) { + + } + + + +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/InfixExprTest.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/InfixExprTest.java new file mode 100644 index 0000000000..b261935703 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/InfixExprTest.java @@ -0,0 +1,48 @@ +package org.xukai.coderising.stack; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class InfixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + //InfixExpr expr = new InfixExpr("300*20+12*5-20/4"); + { + InfixExpr expr = new InfixExpr("2+3*4+5"); + Assert.assertEquals(19.0, expr.evaluate(), 0.001f); + } + { + InfixExpr expr = new InfixExpr("3*20+12*5-40/2"); + Assert.assertEquals(100.0, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("3*20/2"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("20/2*3"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("10-30+50"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + } + +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/AttributeInfo.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/AttributeInfo.java new file mode 100644 index 0000000000..1408111d77 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/AttributeInfo.java @@ -0,0 +1,59 @@ +package org.xukai.jvm.attr; + +import org.xukai.jvm.clz.ClassFile; +import org.xukai.jvm.constant.UTF8Info; +import org.xukai.jvm.loader.ByteCodeIterator; + +public abstract class AttributeInfo { + public static final String CODE = "Code"; + public static final String CONST_VALUE = "ConstantValue"; + public static final String EXCEPTIONS = "Exceptions"; + public static final String LINE_NUM_TABLE = "LineNumberTable"; + public static final String LOCAL_VAR_TABLE = "LocalVariableTable"; + public static final String STACK_MAP_TABLE = "StackMapTable"; + int attrNameIndex; + int attrLen ; + public AttributeInfo(int attrNameIndex, int attrLen) { + + this.attrNameIndex = attrNameIndex; + this.attrLen = attrLen; + } + + + public static AttributeInfo parseAttribute(ByteCodeIterator iter, ClassFile clzFile) { + int attributeNameIndex = iter.nextToInt(2); + System.out.println(((UTF8Info)clzFile.getConstantPool().getConstantInfo(attributeNameIndex)).getValue()); + String attributeName = ((UTF8Info) clzFile.getConstantPool().getConstantInfo(attributeNameIndex)).getValue(); + switch(attributeName){ + case AttributeInfo.CODE : + iter.preToInt(2); + CodeAttr codeAttr = CodeAttr.parse(clzFile, iter); + return codeAttr; + case AttributeInfo.EXCEPTIONS : + iter.preToInt(2); + System.out.println("解析exception"); + return null; + case AttributeInfo.CONST_VALUE : + iter.preToInt(2); + System.out.println("解析constValue"); + return null; + case AttributeInfo.LINE_NUM_TABLE : + iter.preToInt(2); + LineNumberTable lineNumberTable = LineNumberTable.parse(iter); + return lineNumberTable; + case AttributeInfo.LOCAL_VAR_TABLE : + iter.preToInt(2); + LocalVariableTable localVariableTable = LocalVariableTable.parse(iter); + return localVariableTable; + case AttributeInfo.STACK_MAP_TABLE : + iter.preToInt(2); + StackMapTable stackMapTable = StackMapTable.parse(iter); + return stackMapTable; + default: + throw new RuntimeException(); + } + + + } + +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/CodeAttr.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/CodeAttr.java new file mode 100644 index 0000000000..d0c8ef4e32 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/CodeAttr.java @@ -0,0 +1,83 @@ +package org.xukai.jvm.attr; + + +import org.xukai.jvm.clz.ClassFile; +import org.xukai.jvm.loader.ByteCodeIterator; + +public class CodeAttr extends AttributeInfo { + private int maxStack ; + private int maxLocals ; + private int codeLen ; + private String code; + + + + public String getCode() { + return code; + } + + //private ByteCodeCommand[] cmds ; + //public ByteCodeCommand[] getCmds() { + // return cmds; + //} + private LineNumberTable lineNumTable; + private LocalVariableTable localVarTable; + private StackMapTable stackMapTable; + + public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen,String code /*ByteCodeCommand[] cmds*/) { + super(attrNameIndex, attrLen); + this.maxStack = maxStack; + this.maxLocals = maxLocals; + this.codeLen = codeLen; + this.code = code; + //this.cmds = cmds; + } + + public void setLineNumberTable(LineNumberTable t) { + this.lineNumTable = t; + } + + public void setLocalVariableTable(LocalVariableTable t) { + this.localVarTable = t; + } + + public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ + int attributeNameIndex = iter.nextToInt(2); + int attributeLength = iter.nextToInt(4); + int maxStack = iter.nextToInt(2); + int maxLocals = iter.nextToInt(2); + int codeLength = iter.nextToInt(4); + String code = iter.nextToString(codeLength); + System.out.println(code); + CodeAttr codeAttr = new CodeAttr(attributeNameIndex, attributeLength, maxStack, maxLocals, codeLength, code); + int exceptionTableLength = iter.nextToInt(2); + if (exceptionTableLength > 0) { + iter.nextToInt(exceptionTableLength); + System.out.println("解析exception"); + } + int subAttributeCount = iter.nextToInt(2); + System.out.println("subAttributeCount" + subAttributeCount); + if (subAttributeCount > 0) { + for (int i = 0; i < subAttributeCount; i++) { + AttributeInfo attributeInfo = AttributeInfo.parseAttribute(iter, clzFile); + if (attributeInfo instanceof LineNumberTable) { + codeAttr.setLineNumberTable((LineNumberTable)attributeInfo); + } else if (attributeInfo instanceof LocalVariableTable){ + codeAttr.setLocalVariableTable((LocalVariableTable)attributeInfo); + } else if (attributeInfo instanceof StackMapTable){ + codeAttr.setStackMapTable((StackMapTable)attributeInfo); + } + } + } + return codeAttr; + } + private void setStackMapTable(StackMapTable t) { + this.stackMapTable = t; + + } + + + + + +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/LineNumberTable.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/LineNumberTable.java new file mode 100644 index 0000000000..fa66c6a2f1 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/LineNumberTable.java @@ -0,0 +1,55 @@ +package org.xukai.jvm.attr; + +import org.xukai.jvm.loader.ByteCodeIterator; + +import java.util.ArrayList; +import java.util.List; + +public class LineNumberTable extends AttributeInfo { + List<LineNumberItem> items = new ArrayList<LineNumberItem>(); + + private static class LineNumberItem{ + int startPC; + int lineNum; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLineNum() { + return lineNum; + } + public void setLineNum(int lineNum) { + this.lineNum = lineNum; + } + } + public void addLineNumberItem(LineNumberItem item){ + this.items.add(item); + } + public LineNumberTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + + } + + public static LineNumberTable parse(ByteCodeIterator iter){ + int attributeNameIndex = iter.nextToInt(2); + int attributeLength = iter.nextToInt(4); + LineNumberTable lineNumberTable = new LineNumberTable(attributeNameIndex, attributeLength); + int lineNumberTableLengh = iter.nextToInt(2); + if (lineNumberTableLengh > 0) { + for (int i = 0; i < lineNumberTableLengh; i++) { + int startPc = iter.nextToInt(2); + int lineNum = iter.nextToInt(2); + LineNumberItem lineNumberItem = new LineNumberItem(); + lineNumberItem.setStartPC(startPc); + lineNumberItem.setLineNum(lineNum); + lineNumberTable.addLineNumberItem(lineNumberItem); + } + } + return lineNumberTable; + } + + + +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/LocalVariableItem.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/LocalVariableItem.java new file mode 100644 index 0000000000..658481d33b --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/LocalVariableItem.java @@ -0,0 +1,39 @@ +package org.xukai.jvm.attr; + +public class LocalVariableItem { + private int startPC; + private int length; + private int nameIndex; + private int descIndex; + private int index; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getNameIndex() { + return nameIndex; + } + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + public int getDescIndex() { + return descIndex; + } + public void setDescIndex(int descIndex) { + this.descIndex = descIndex; + } + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/LocalVariableTable.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/LocalVariableTable.java new file mode 100644 index 0000000000..dcc5bbd4f3 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/LocalVariableTable.java @@ -0,0 +1,46 @@ +package org.xukai.jvm.attr; + + +import org.xukai.jvm.loader.ByteCodeIterator; + +import java.util.ArrayList; +import java.util.List; + + +public class LocalVariableTable extends AttributeInfo{ + + List<LocalVariableItem> items = new ArrayList<LocalVariableItem>(); + + public LocalVariableTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static LocalVariableTable parse(ByteCodeIterator iter){ + int attributeNameIndex = iter.nextToInt(2); + int attributeLength = iter.nextToInt(4); + LocalVariableTable localVariableTable = new LocalVariableTable(attributeNameIndex, attributeLength); + int localVariableTableLength = iter.nextToInt(2); + if (localVariableTableLength > 0) { + for (int i = 0; i < localVariableTableLength; i++) { + int startPc = iter.nextToInt(2); + int length = iter.nextToInt(2); + int nameIndex = iter.nextToInt(2); + int descriptorIndex = iter.nextToInt(2); + int index = iter.nextToInt(2); + LocalVariableItem lineNumberItem = new LocalVariableItem(); + lineNumberItem.setStartPC(startPc); + lineNumberItem.setLength(length); + lineNumberItem.setNameIndex(nameIndex); + lineNumberItem.setLength(descriptorIndex); + lineNumberItem.setLength(index); + localVariableTable.addLocalVariableItem(lineNumberItem); + } + } + return localVariableTable; + } + private void addLocalVariableItem(LocalVariableItem item) { + this.items.add(item); + } + + +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/StackMapTable.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/StackMapTable.java new file mode 100644 index 0000000000..1ad1f9d1ed --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/StackMapTable.java @@ -0,0 +1,30 @@ +package org.xukai.jvm.attr; + + +import org.xukai.jvm.loader.ByteCodeIterator; + +public class StackMapTable extends AttributeInfo{ + + private String originalCode; + + public StackMapTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static StackMapTable parse(ByteCodeIterator iter){ + int index = iter.nextToInt(2); + int len = iter.nextToInt(4); + StackMapTable t = new StackMapTable(index,len); + + //后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 + String code = iter.nextToString(len); + t.setOriginalCode(code); + + return t; + } + + private void setOriginalCode(String code) { + this.originalCode = code; + + } +} 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 index a66ec2e5a0..a2b2dfb515 100644 --- 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 @@ -1,8 +1,13 @@ package org.xukai.jvm.clz; - import org.xukai.jvm.constant.ClassInfo; import org.xukai.jvm.constant.ConstantPool; +import org.xukai.jvm.field.Field; +import org.xukai.jvm.method.Method; + +import java.util.ArrayList; +import java.util.List; + public class ClassFile { @@ -12,7 +17,8 @@ public class ClassFile { private AccessFlag accessFlag; private ClassIndex clzIndex; private ConstantPool pool; - + private List<Field> fields = new ArrayList<Field>(); + private List<Method> methods = new ArrayList<Method>(); public ClassIndex getClzIndex() { return clzIndex; @@ -49,7 +55,18 @@ public void setClassIndex(ClassIndex clzIndex) { this.clzIndex = clzIndex; } - + public void addField(Field f){ + this.fields.add(f); + } + public List<Field> getFields(){ + return this.fields; + } + public void addMethod(Method m){ + this.methods.add(m); + } + public List<Method> getMethods() { + return methods; + } public void print(){ diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/field/Field.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/field/Field.java new file mode 100644 index 0000000000..b482229294 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/field/Field.java @@ -0,0 +1,42 @@ +package org.xukai.jvm.field; + + +import org.xukai.jvm.constant.ConstantPool; +import org.xukai.jvm.constant.UTF8Info; +import org.xukai.jvm.loader.ByteCodeIterator; + +public class Field { + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + + + private ConstantPool pool; + + public Field( int accessFlag, int nameIndex, int descriptorIndex,ConstantPool pool) { + + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + this.pool = pool; + } + + public String toString(){ + return getFieldName() +":"+ getFieldDescription(); + } + + public String getFieldName(){ + return ((UTF8Info)pool.getConstantInfo(this.nameIndex)).getValue(); + } + + public String getFieldDescription(){ + return ((UTF8Info)pool.getConstantInfo(this.descriptorIndex)).getValue(); + } + + public static Field parse(ConstantPool pool,ByteCodeIterator iter){ + + return null; + } + +} 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 index 26a5ecad60..7e3b9c0e9b 100644 --- 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 @@ -29,6 +29,16 @@ public int nextToInt(int length){ return -1; } + public int preToInt(int length){ + Preconditions.checkArgument(length > 0); + if ((offset - length) > 0) { + int i = Util.byteToInt(Arrays.copyOfRange(bytes, offset - length, offset)); + offset = offset - length; + return i; + } + return -1; + } + public String nextToString(int length){ Preconditions.checkArgument(length > 0); if ((offset + length) < bytes.length) { diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/loader/ClassFileParser.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/loader/ClassFileParser.java index 165427d0bc..33415b5fe0 100644 --- a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/loader/ClassFileParser.java +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/loader/ClassFileParser.java @@ -1,6 +1,7 @@ package org.xukai.jvm.loader; import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; import org.xukai.jvm.clz.AccessFlag; import org.xukai.jvm.clz.ClassFile; import org.xukai.jvm.clz.ClassIndex; @@ -12,6 +13,11 @@ import org.xukai.jvm.constant.NullConstantInfo; import org.xukai.jvm.constant.StringInfo; import org.xukai.jvm.constant.UTF8Info; +import org.xukai.jvm.field.Field; +import org.xukai.jvm.method.Method; + +import java.util.ArrayList; +import java.util.List; public class ClassFileParser { @@ -31,13 +37,43 @@ public ClassFile parse(byte[] codes) { ConstantPool pool = parseConstantPool(iter); AccessFlag accessFlag = parseAccessFlag(iter); ClassIndex classIndex = parseClassInfex(iter); + parseInterfaces(iter); classFile.setConstPool(pool); classFile.setAccessFlag(accessFlag); classFile.setClassIndex(classIndex); + + parseFields(pool, iter, classFile); + parseMethod(pool, iter, classFile); + return classFile; } + private List<Field> parseFields(ConstantPool pool, ByteCodeIterator iter, ClassFile classFile) { + int fieldsCount = iter.nextToInt(2); + ArrayList<Field> fields = new ArrayList<>(fieldsCount); + for (int i = 0; i < fieldsCount; i++) { + int flages = iter.nextToInt(2); + int nameIndex = iter.nextToInt(2); + int descriptorIndex = iter.nextToInt(2); + int attributeCount = iter.nextToInt(2); + if (attributeCount > 0) { + System.out.println("jeixi"); + } + Field field = new Field(flages, nameIndex, descriptorIndex, pool); + classFile.addField(field); + } + + return fields; + } + + private void parseMethod(ConstantPool pool, ByteCodeIterator iter, ClassFile classFile) { + int methodsCount = iter.nextToInt(2); + for (int i = 0; i < methodsCount; i++) { + Method.parse(classFile,iter); + } + } + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { return new AccessFlag(iter.nextToInt(2)); } @@ -122,5 +158,12 @@ private ConstantPool parseConstantPool(ByteCodeIterator iter) { return pool; } + private void parseInterfaces(ByteCodeIterator iter) { + int interfaceCount = iter.nextToInt(2); + + System.out.println("interfaceCount:" + interfaceCount); + + // TODO : 如果实现了interface, 这里需要解析 + } } diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/method/Method.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/method/Method.java new file mode 100644 index 0000000000..6cd71db72c --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/method/Method.java @@ -0,0 +1,88 @@ +package org.xukai.jvm.method; + + +import org.xukai.jvm.attr.AttributeInfo; +import org.xukai.jvm.attr.CodeAttr; +import org.xukai.jvm.clz.ClassFile; +import org.xukai.jvm.constant.UTF8Info; +import org.xukai.jvm.loader.ByteCodeIterator; + +public class Method { + + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private CodeAttr codeAttr; + + private ClassFile clzFile; + + + public ClassFile getClzFile() { + return clzFile; + } + + public int getNameIndex() { + return nameIndex; + } + public int getDescriptorIndex() { + return descriptorIndex; + } + + public CodeAttr getCodeAttr() { + return codeAttr; + } + + public void setCodeAttr(CodeAttr code) { + this.codeAttr = code; + } + + public Method(ClassFile clzFile,int accessFlag, int nameIndex, int descriptorIndex) { + this.clzFile = clzFile; + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + } + + public String toString(){ + return getMethodName() +":"+ getMethodDescription(); + } + + public String getMethodName(){ + return ((UTF8Info)clzFile.getConstantPool().getConstantInfo(this.nameIndex)).getValue(); + } + + public String getMethodDescription(){ + return ((UTF8Info)clzFile.getConstantPool().getConstantInfo(this.descriptorIndex)).getValue(); + } + + + + public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ + int flages = iter.nextToInt(2); + int nameIndex = iter.nextToInt(2); + int descriptorIndex = iter.nextToInt(2); + Method method = new Method(clzFile, flages, nameIndex, descriptorIndex); + int attributeCount = iter.nextToInt(2); + if (attributeCount > 0) { + for (int i = 0; i < attributeCount; i++) { + AttributeInfo info = AttributeInfo.parseAttribute(iter, clzFile); + if (info instanceof CodeAttr) { + method.setCodeAttr((CodeAttr) info); + } + } + } + clzFile.addMethod(method); + return method; + + } + + public static void main(String[] args) { + CodeAttr codeAttr = new CodeAttr(1, 1, 1, 1, 1, ""); + System.out.println(codeAttr instanceof AttributeInfo); + AttributeInfo codeAttr2 = new CodeAttr(1, 1, 1, 1, 1, ""); + System.out.println(codeAttr2 instanceof CodeAttr); + } + + +} 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 4b4f8d807f..c4fad12ff6 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 @@ -14,12 +14,15 @@ import org.xukai.jvm.constant.NameAndTypeInfo; import org.xukai.jvm.constant.NullConstantInfo; import org.xukai.jvm.constant.UTF8Info; +import org.xukai.jvm.field.Field; import org.xukai.jvm.loader.ByteCodeIterator; import org.xukai.jvm.loader.ClassFileLoader; import org.xukai.jvm.loader.ClassFileParser; +import org.xukai.jvm.method.Method; import org.xukai.jvm.util.Util; import java.util.Arrays; +import java.util.List; public class ClassFileloaderTest { @@ -118,10 +121,6 @@ private ClassFile parse(byte[] bytes){ int major_version = iter.nextToInt(2); System.out.println(minor_version + "_" + major_version); classFile.setMajorVersion(major_version); - - - - return null; } @@ -231,6 +230,79 @@ public void testClassIndex(){ Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); } + + + /** + * 下面是第三次JVM课应实现的测试用例 + */ + @Test + public void testReadFields(){ + + List<Field> fields = clzFile.getFields(); + Assert.assertEquals(2, fields.size()); + { + Field f = fields.get(0); + Assert.assertEquals("name:Ljava/lang/String;", f.toString()); + } + { + Field f = fields.get(1); + Assert.assertEquals("age:I", f.toString()); + } + } + @Test + public void testMethods(){ + + List<Method> methods = clzFile.getMethods(); + ConstantPool pool = clzFile.getConstantPool(); + + { + Method m = methods.get(0); + assertMethodEquals(pool,m, + "<init>", + "(Ljava/lang/String;I)V", + "2ab7000c2a2bb5000f2a1cb50011b1"); + + } + { + Method m = methods.get(1); + assertMethodEquals(pool,m, + "setName", + "(Ljava/lang/String;)V", + "2a2bb5000fb1"); + + } + { + Method m = methods.get(2); + assertMethodEquals(pool,m, + "setAge", + "(I)V", + "2a1bb50011b1"); + } + { + Method m = methods.get(3); + assertMethodEquals(pool,m, + "sayHello", + "()V", + "b2001c1222b60024b1"); + + } + { + Method m = methods.get(4); + assertMethodEquals(pool,m, + "main", + "([Ljava/lang/String;)V", + "bb000159122b101db7002d4c2bb6002fb1"); + } + } + + private void assertMethodEquals(ConstantPool pool,Method m , String expectedName, String expectedDesc,String expectedCode){ + String methodName = pool.getUTF8String(m.getNameIndex()); + String methodDesc = pool.getUTF8String(m.getDescriptorIndex()); + String code = m.getCodeAttr().getCode(); + Assert.assertEquals(expectedName, methodName); + Assert.assertEquals(expectedDesc, methodDesc); + Assert.assertEquals(expectedCode, code); + } From 04242e92cbbd6f02e440fdd44ab33a5042afdb9b Mon Sep 17 00:00:00 2001 From: ZhaoHongxin <zhaohongxin621@126.com> Date: Sun, 16 Apr 2017 23:59:06 +0800 Subject: [PATCH 275/287] =?UTF-8?q?jvm=E7=AC=AC=E4=B8=89=E6=AC=A1=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/com/coding/basic/ArrayList.java | 18 +-- .../mini-jvm/src/com/coding/basic/List.java | 6 +- .../src/com/coding/basic/stack/Stack.java | 42 +++++++ .../src/com/coding/basic/stack/StackUtil.java | 108 ++++++++++++++++++ .../com/coding/basic/stack/StackUtilTest.java | 61 ++++++++++ .../coding/basic/stack/expr/InfixExpr.java | 74 ++++++++++++ .../basic/stack/expr/InfixExprTest.java | 54 +++++++++ 7 files changed, 351 insertions(+), 12 deletions(-) create mode 100644 group05/1094051862/mini-jvm/src/com/coding/basic/stack/Stack.java create mode 100644 group05/1094051862/mini-jvm/src/com/coding/basic/stack/StackUtil.java create mode 100644 group05/1094051862/mini-jvm/src/com/coding/basic/stack/StackUtilTest.java create mode 100644 group05/1094051862/mini-jvm/src/com/coding/basic/stack/expr/InfixExpr.java create mode 100644 group05/1094051862/mini-jvm/src/com/coding/basic/stack/expr/InfixExprTest.java diff --git a/group05/1094051862/mini-jvm/src/com/coding/basic/ArrayList.java b/group05/1094051862/mini-jvm/src/com/coding/basic/ArrayList.java index 2e837dd195..3a08432511 100644 --- a/group05/1094051862/mini-jvm/src/com/coding/basic/ArrayList.java +++ b/group05/1094051862/mini-jvm/src/com/coding/basic/ArrayList.java @@ -2,7 +2,7 @@ import java.util.Arrays; -public class ArrayList implements List { +public class ArrayList<T> implements List<T> { private int size = 0; @@ -13,7 +13,7 @@ private void increaseArray() { Object[] newData = Arrays.copyOf(elementData, elementData.length + increaseSize); elementData = newData; } - public void add(Object o){ + public void add(T o){ if (size == elementData.length) { increaseArray(); elementData[size++] = o; @@ -21,28 +21,28 @@ public void add(Object o){ elementData[size++] = o; } } - public void add(int index, Object o){ + public void add(int index, T o){ if (index < 0 || index > size) { System.out.println("错误提示:index > size || index < 0"); return; } - Object temp; + T temp; for (int i = index; i < size; i++) { - temp = elementData[i]; + temp = (T) elementData[i]; elementData[i] = o; o = temp; } elementData[size ++] = o; } - public Object get(int index){ + public T get(int index){ if (index < 0 || index > size ){ return null; } - return elementData[index]; + return (T) elementData[index]; } - public Object remove(int index){ + public T remove(int index){ if (index < 0 || index > size ){ return null; } @@ -52,7 +52,7 @@ public Object remove(int index){ } elementData[size-1] = null; size --; - return result; + return (T) result; } public int size(){ diff --git a/group05/1094051862/mini-jvm/src/com/coding/basic/List.java b/group05/1094051862/mini-jvm/src/com/coding/basic/List.java index 0a09990083..c52c1aef0e 100644 --- a/group05/1094051862/mini-jvm/src/com/coding/basic/List.java +++ b/group05/1094051862/mini-jvm/src/com/coding/basic/List.java @@ -1,8 +1,8 @@ package com.coding.basic; -public interface List { - public void add(Object o); - public void add(int index, Object o); +public interface List<T> { + public void add(T t); + public void add(int index, T t); public Object get(int index); public Object remove(int index); public int size(); diff --git a/group05/1094051862/mini-jvm/src/com/coding/basic/stack/Stack.java b/group05/1094051862/mini-jvm/src/com/coding/basic/stack/Stack.java new file mode 100644 index 0000000000..5abd9499d5 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coding/basic/stack/Stack.java @@ -0,0 +1,42 @@ +package com.coding.basic.stack; + +import com.coding.basic.ArrayList; +import com.coding.basic.List; + +public class Stack<T> { + private List elementData = new ArrayList(); + private int size = 0; + public void push(Object o){ + elementData.add(o); + size ++; + } + + public Object pop(){ + if (size == 0) + return null; + return elementData.remove(--size); + } + + public Object peek(){ + if (size == 0) + return null; + return elementData.get(size - 1); + } + public boolean isEmpty(){ + return size == 0; + } + public int size(){ + return size; + } + public String toString() { + StringBuffer join = new StringBuffer("["); + for(int i = 0; i < size; i++) { + join.append(elementData.get(i)); + if (i != size - 1) { + join.append(","); + } + } + join.append("]"); + return join.toString(); + } +} diff --git a/group05/1094051862/mini-jvm/src/com/coding/basic/stack/StackUtil.java b/group05/1094051862/mini-jvm/src/com/coding/basic/stack/StackUtil.java new file mode 100644 index 0000000000..cdb09886fa --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coding/basic/stack/StackUtil.java @@ -0,0 +1,108 @@ +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) { + if (s == null || s.size() == 0) { + return; + } + Stack s1 = new Stack(); + Stack s2 = new Stack(); + + reverseTo(s, s1); + reverseTo(s1, s2); + reverseTo(s2, s); + } + + private static void reverseTo(Stack s, Stack s1) { + while(!s.isEmpty()) { + s1.push(s.pop()); + } + } + + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s,Object o) { + if (o == null || s == null || s.size() == 0) { + return; + } + Stack temp = new Stack(); + reverseTo(s,temp); + while(!temp.isEmpty()) { + if (temp.peek().equals(o)) { + temp.pop(); + continue; + } + s.push(temp.pop()); + } + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * @param len + * @return + */ + public static Object[] getTop(Stack s,int len) { + if (len <= 0 || s == null || s.size() < len) { + return null; + } + Object[] objs = new Object[len]; + for(int i = 0; i < len; i++) { + objs[i] = s.pop(); + } + for(int i = len-1; i >= 0; i--) { + s.push(objs[i]); + } + return objs; + } + /** + * 字符串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[] c = s.toCharArray(); + Stack tag = new Stack(); + for (int i = 0; i < c.length; i++) { + switch(c[i]) { + case '(': + case '[': + case '{': + tag.push(c[i]); + break; + case ')': + if (tag.isEmpty() || '(' != (char)tag.pop()) { + return false; + } + break; + case '}': + if (tag.isEmpty() || '{' != (char)tag.pop()) { + return false; + } + break; + case ']': + if (tag.isEmpty() || '[' != (char)tag.pop()) { + return false; + } + break; + } + } + if (!tag.isEmpty()) { + return false; + } + return true; + } + +} diff --git a/group05/1094051862/mini-jvm/src/com/coding/basic/stack/StackUtilTest.java b/group05/1094051862/mini-jvm/src/com/coding/basic/stack/StackUtilTest.java new file mode 100644 index 0000000000..31c0d72dc1 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coding/basic/stack/StackUtilTest.java @@ -0,0 +1,61 @@ +package com.coding.basic.stack; + +import static org.junit.Assert.*; + +import org.apache.commons.lang3.ArrayUtils; +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); + System.out.println(stack.toString()); + StackUtil.reverse(stack); + System.out.println(stack.toString()); + } + + @Test + public void testRemove() { + Stack stack = new Stack(); + stack.push(1); + stack.push(2); + stack.push(3); + stack.push(4); + stack.push(5); + System.out.println(stack.toString()); + StackUtil.remove(stack, 5); + System.out.println(stack.toString()); + StackUtil.remove(stack, 2); + System.out.println(stack.toString()); + } + + @Test + public void testGetTop() { + Stack stack = new Stack(); + stack.push(1); + stack.push(2); + stack.push(3); + stack.push(4); + stack.push(5); + System.out.println(stack.toString()); + Object[] top = StackUtil.getTop(stack, 3); + System.out.println(ArrayUtils.toString(top, null)); + System.out.println(stack.toString()); + } + + @Test + public void testIsValidPairs() { + String str = "sdf{sdf[sdf]sdfsdff}"; + String str2 = "[sdf(sdf{sdf]}sdf)"; + Assert.assertTrue(StackUtil.isValidPairs(str)); + Assert.assertTrue(!StackUtil.isValidPairs(str2)); + } + +} diff --git a/group05/1094051862/mini-jvm/src/com/coding/basic/stack/expr/InfixExpr.java b/group05/1094051862/mini-jvm/src/com/coding/basic/stack/expr/InfixExpr.java new file mode 100644 index 0000000000..dc51c6adf3 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coding/basic/stack/expr/InfixExpr.java @@ -0,0 +1,74 @@ +package com.coding.basic.stack.expr; + +import java.util.List; + +import com.coding.basic.stack.Stack; +import com.coding.basic.stack.StackUtil; + +public class InfixExpr { + String expr = null; + + public InfixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + + TokenParser parser = new TokenParser(); + List<Token> tokens = parser.parse(expr); + + Stack<Token> opStack = new Stack(); + Stack<Float> numStack = new Stack(); + + for (Token t : tokens) { + if (t.isOperator()) { + if (opStack.isEmpty()) { + opStack.push(t); + } else { + Token topOperator = (Token) opStack.peek(); + if (t.comparePriority(topOperator) >= 0) { + opStack.push(t); + } else { + Float f1 = (Float) numStack.pop(); + Float f2 = (Float) numStack.pop(); + numStack.push(calculate(topOperator.getValue(), f2, f1)); + opStack.pop(); + opStack.push(t); + } + } + } else if (t.isDigit()) { + numStack.push(Float.valueOf(t.getValue())); + } + } + /*StackUtil.reverse(numStack); + StackUtil.reverse(opStack);*/ + while (!opStack.isEmpty()) { + Float f1 = (Float) numStack.pop(); + Float f2 = (Float) numStack.pop(); + Token opr = (Token) opStack.pop(); + numStack.push(calculate(opr.getValue(), f2, f1)); + } + return (Float) numStack.pop(); + //return 0.0f; + } + + private Float calculate(String op, Float f1, Float f2) { + System.out.println(f1 + "=====" +f2); + switch (op) { + case "*": + System.out.println(" * "); + return f1 * f2; + case "/": + System.out.println("/"); + return f1 / f2; + case "+": + System.out.println("+"); + return f1 + f2; + case "-": + System.out.println("-"); + return f1 - f2; + } + return 0.0f; + } + +} diff --git a/group05/1094051862/mini-jvm/src/com/coding/basic/stack/expr/InfixExprTest.java b/group05/1094051862/mini-jvm/src/com/coding/basic/stack/expr/InfixExprTest.java new file mode 100644 index 0000000000..a6c3d24012 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coding/basic/stack/expr/InfixExprTest.java @@ -0,0 +1,54 @@ +package com.coding.basic.stack.expr; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class InfixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + //InfixExpr expr = new InfixExpr("300*20+12*5-20/4"); + { + InfixExpr expr = new InfixExpr("2+3*4+5"); + Assert.assertEquals(19.0, expr.evaluate(), 0.001f); + } + { + InfixExpr expr = new InfixExpr("3*20+12*5-40/2"); + Assert.assertEquals(100.0, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("3*20/2"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("20/2*3"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("10-30+50"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + } + @Test + public void test0001() { + InfixExpr expr = new InfixExpr("2+3*4+5"); + String s = "23+3*4+5"; + new TokenParser().parse(s); + } + +} From 057d50683c921e6096693586a9456f1af1aae88a Mon Sep 17 00:00:00 2001 From: ZhaoHongxin <zhaohongxin621@126.com> Date: Sun, 16 Apr 2017 23:59:43 +0800 Subject: [PATCH 276/287] add token.java --- .../com/coding/basic/stack/expr/Token.java | 61 +++++++++++++++++++ .../coding/basic/stack/expr/TokenParser.java | 52 ++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 group05/1094051862/mini-jvm/src/com/coding/basic/stack/expr/Token.java create mode 100644 group05/1094051862/mini-jvm/src/com/coding/basic/stack/expr/TokenParser.java diff --git a/group05/1094051862/mini-jvm/src/com/coding/basic/stack/expr/Token.java b/group05/1094051862/mini-jvm/src/com/coding/basic/stack/expr/Token.java new file mode 100644 index 0000000000..b8abf39546 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coding/basic/stack/expr/Token.java @@ -0,0 +1,61 @@ +package com.coding.basic.stack.expr; + +public class Token { + + public static final int OPRATOR = 0; + public static final int NUMBER = 1; + + private int signal; + private String value; + + public Token(int signal, String digit) { + this.signal = signal; + this.value = digit; + } + + public boolean isOperator() { + return this.signal == Token.OPRATOR; + } + + public boolean isDigit() { + return this.signal == Token.NUMBER; + } + + public int getSignal() { + return signal; + } + + public void setSignal(int signal) { + this.signal = signal; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public int comparePriority(Token topOperator) { + int topOptrPriority = 0; + int optPriority = 0; + if (topOperator.getValue().indexOf('*')>=0 || topOperator.getValue().indexOf('/')>=0) { + topOptrPriority = 1; + } + if (topOperator.getValue().indexOf('+')>=0 || topOperator.getValue().indexOf('-')>=0) { + topOptrPriority = 0; + } + if (this.getValue().indexOf('+')>=0 || this.getValue().indexOf('-')>=0) { + optPriority = 0; + } + if (this.getValue().indexOf('*')>=0 || this.getValue().indexOf('/')>=0) { + optPriority = 1; + } + + + return optPriority - topOptrPriority; + } + + +} diff --git a/group05/1094051862/mini-jvm/src/com/coding/basic/stack/expr/TokenParser.java b/group05/1094051862/mini-jvm/src/com/coding/basic/stack/expr/TokenParser.java new file mode 100644 index 0000000000..447894d7f4 --- /dev/null +++ b/group05/1094051862/mini-jvm/src/com/coding/basic/stack/expr/TokenParser.java @@ -0,0 +1,52 @@ +package com.coding.basic.stack.expr; + +import java.util.ArrayList; +import java.util.List; + + + +public class TokenParser { + + public List<Token> parse(String expr) { + + List<Token> tokens = new ArrayList<Token>(); + int i = 0; + while (i < expr.length()) { + char c = expr.charAt(i); + if (charIsOperator(c)) { + Token t = new Token(Token.OPRATOR, String.valueOf(c)); + tokens.add(t); + i ++; + } else if (charIsDigit(c)) { + int nextOperatorIndex = indexOfNextOperator(i,expr); + String value = expr.substring(i, nextOperatorIndex); + Token t = new Token(Token.NUMBER, value); + tokens.add(t); + i = nextOperatorIndex; + } + System.out.println(c); + } + + return tokens; + } + + private int indexOfNextOperator(int nowIndex, String expr) { + for (int i = nowIndex; i < expr.length(); i++) { + char c = expr.charAt(i); + if (charIsOperator(c)) { + return i; + } + } + return expr.length();//如果后面没有操作符,返回字符串长度,用于截取数字 + } + + private boolean charIsDigit(char c) { + return c>='0' && c<='9'; + } + + private boolean charIsOperator(char c) { + + return c=='+' || c=='-' || c=='*' || c=='/'; + } + +} From 5c9b6dd851f0ff7c1f221558bee08fc24b482c28 Mon Sep 17 00:00:00 2001 From: johnChnia <zhouqiang847@gmail.com> Date: Mon, 17 Apr 2017 04:01:15 +0800 Subject: [PATCH 277/287] =?UTF-8?q?=E5=AE=8C=E6=88=90jvm=E7=AC=AC=E4=B8=80?= =?UTF-8?q?=E5=91=A8=E6=89=80=E6=9C=89=E4=BD=9C=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/jvm/loader/ClassFileLoader.java | 57 +++++++++++++ .../src/main/java/jvm/loader/Directory.java | 81 ++++++++++++++++++ .../java/jvm/test/ClassFileloaderTest.java | 83 +++++++++++++++++++ .../src/main/java/jvm/test/EmployeeV1.java | 31 +++++++ 4 files changed, 252 insertions(+) create mode 100644 group24/315863321/src/main/java/jvm/loader/ClassFileLoader.java create mode 100644 group24/315863321/src/main/java/jvm/loader/Directory.java create mode 100644 group24/315863321/src/main/java/jvm/test/ClassFileloaderTest.java create mode 100644 group24/315863321/src/main/java/jvm/test/EmployeeV1.java diff --git a/group24/315863321/src/main/java/jvm/loader/ClassFileLoader.java b/group24/315863321/src/main/java/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..a300edafc7 --- /dev/null +++ b/group24/315863321/src/main/java/jvm/loader/ClassFileLoader.java @@ -0,0 +1,57 @@ +package jvm.loader; + + +import com.johnChnia.coding2017.basic.ArrayList; +import com.johnChnia.coding2017.basic.List; + +import java.io.*; + +/** + * @// TODO: 2017/4/20 改成 try... with...resource + * @// TODO: 2017/4/20 close inputstream + * @// TODO: 2017/4/20 修改TreeInfo直接返回File + */ +public class ClassFileLoader { + + private List<String> clzPaths = new ArrayList<String>(); + + public byte[] readBinaryCode(String className) { + for (int i = 0; i < clzPaths.size(); i++) { + // 找到指定类文件 + Directory.TreeInfo treeInfo = Directory.walk(clzPaths.get(i), className); + if (treeInfo.files.size() > 0) { + try { + FileInputStream fis = new FileInputStream(treeInfo.files.get(0)); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); // 自动增长 + byte[] buff = new byte[1024]; + int len; + while ((len = fis.read(buff)) != -1) { + bos.write(buff, 0, len); + } + return bos.toByteArray(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + return null; + + } + + + public void addClassPath(String path) { + clzPaths.add(path); + } + + + public String getClassPath() { + StringBuilder sb = new StringBuilder(); + for (int index = 0; index < clzPaths.size(); index++) { + sb.append(clzPaths.get(index)); + sb.append(";"); + } + return sb.toString().substring(0, sb.length() - 1); + } + + +} diff --git a/group24/315863321/src/main/java/jvm/loader/Directory.java b/group24/315863321/src/main/java/jvm/loader/Directory.java new file mode 100644 index 0000000000..98f239434d --- /dev/null +++ b/group24/315863321/src/main/java/jvm/loader/Directory.java @@ -0,0 +1,81 @@ +package jvm.loader; + +import java.io.File; +import java.io.FilenameFilter; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.regex.Pattern; + +/** + * Created by john on 2017/4/17. + * + * @// TODO: 2017/4/20 实现 List.addAll(), list implements Iterable + */ +public final class Directory { + + public static File[] local(File dir, final String regex) { + return dir.listFiles(new FilenameFilter() { // 文件过滤接口 + private Pattern pattern = Pattern.compile(regex); + + @Override + public boolean accept(File dir, String name) { + return pattern.matcher(new File(name).getName()).matches(); + } + }); + } + + public static File[] local(String path, final String regex) { + return local(new File(path), regex); + } + + public static class TreeInfo implements Iterable<File> { + public List<File> files = new ArrayList<>(); + public List<File> dirs = new ArrayList<>(); + + @Override + public Iterator<File> iterator() { + return files.iterator(); + } + + public void addAll(TreeInfo other) { + files.addAll(other.files); + dirs.addAll(other.dirs); + } + + @Override + public String toString() { + return "dirs: " + dirs + + "\n\nfiles: " + files; + } + } + + public static TreeInfo walk(String start, String regex) { + return recuresDirs(new File(start), regex); + } + + public static TreeInfo walk(File start, String regex) { + return recuresDirs(start, regex); + } + + public static TreeInfo walk(File start) { + return recuresDirs(start, ".*");// 全部 + } + + public static TreeInfo walk(String start) { + return recuresDirs(new File(start), ".*");// 全部 + } + + public static TreeInfo recuresDirs(File startDir, String regex) { + TreeInfo result = new TreeInfo(); + for (File item : startDir.listFiles()) { + if (item.isDirectory()) { + result.dirs.add(item); + result.addAll(recuresDirs(item, regex)); + } else if (item.getName().matches(regex)) + result.files.add(item); + } + return result; + } + +} \ No newline at end of file diff --git a/group24/315863321/src/main/java/jvm/test/ClassFileloaderTest.java b/group24/315863321/src/main/java/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..70d400cb28 --- /dev/null +++ b/group24/315863321/src/main/java/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,83 @@ +package jvm.test; + +import 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 = "/Users/john/Documents/mygit/coding2017/group24/315863321/target/classes/jvm"; + static String path2 = "/Users/john/Documents"; + + + @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.class"; + + byte[] byteCodes = loader.readBinaryCode(className); + + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + Assert.assertEquals(1026, byteCodes.length); + + } + + + @Test + public void testMagicNumber() { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "EmployeeV1.class"; + 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/group24/315863321/src/main/java/jvm/test/EmployeeV1.java b/group24/315863321/src/main/java/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..3fbdcef7bf --- /dev/null +++ b/group24/315863321/src/main/java/jvm/test/EmployeeV1.java @@ -0,0 +1,31 @@ +package 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 71922774789ed183d8348dc0d898f22db5d26286 Mon Sep 17 00:00:00 2001 From: onlyliuxin <14703250@qq.com> Date: Mon, 17 Apr 2017 09:57:55 +0800 Subject: [PATCH 278/287] refactor --- .../src/com/coding/basic/Queue.java | 19 --- .../com/coding/basic/queue/CircleQueue.java | 5 + .../src/com/coding/basic/queue/Josephus.java | 33 ++++ .../com/coding/basic/queue/JosephusTest.java | 27 +++ .../src/com/coding/basic/queue/Queue.java | 61 +++++++ .../basic/queue/QueueWithTwoStacks.java | 54 ++++++ .../coding/basic/stack/expr/InfixExpr.java | 66 +++++++- .../basic/stack/expr/InfixExprTest.java | 4 + .../basic/stack/expr/InfixToPostfix.java | 52 ++++++ .../coding/basic/stack/expr/PostfixExpr.java | 46 ++++++ .../basic/stack/expr/PostfixExprTest.java | 41 +++++ .../coding/basic/stack/expr/PrefixExpr.java | 52 ++++++ .../basic/stack/expr/PrefixExprTest.java | 45 +++++ .../com/coding/basic/stack/expr/Token.java | 50 ++++++ .../coding/basic/stack/expr/TokenParser.java | 57 +++++++ .../basic/stack/expr/TokenParserTest.java | 41 +++++ .../src/com/coderising/jvm/attr/CodeAttr.java | 29 ++-- .../src/com/coderising/jvm/clz/ClassFile.java | 32 +++- .../src/com/coderising/jvm/cmd/BiPushCmd.java | 23 +++ .../coderising/jvm/cmd/ByteCodeCommand.java | 128 +++++++++++++++ .../com/coderising/jvm/cmd/CommandParser.java | 155 ++++++++++++++++++ .../com/coderising/jvm/cmd/GetFieldCmd.java | 22 +++ .../coderising/jvm/cmd/GetStaticFieldCmd.java | 23 +++ .../coderising/jvm/cmd/InvokeSpecialCmd.java | 23 +++ .../coderising/jvm/cmd/InvokeVirtualCmd.java | 22 +++ .../src/com/coderising/jvm/cmd/LdcCmd.java | 29 ++++ .../com/coderising/jvm/cmd/NewObjectCmd.java | 19 +++ .../com/coderising/jvm/cmd/NoOperandCmd.java | 23 +++ .../com/coderising/jvm/cmd/OneOperandCmd.java | 27 +++ .../com/coderising/jvm/cmd/PutFieldCmd.java | 19 +++ .../com/coderising/jvm/cmd/TwoOperandCmd.java | 67 ++++++++ .../coderising/jvm/constant/ClassInfo.java | 4 + .../coderising/jvm/constant/ConstantInfo.java | 11 ++ .../coderising/jvm/constant/ConstantPool.java | 4 +- .../coderising/jvm/constant/FieldRefInfo.java | 4 + .../jvm/constant/MethodRefInfo.java | 5 + .../jvm/constant/NameAndTypeInfo.java | 6 + .../jvm/constant/NullConstantInfo.java | 4 + .../coderising/jvm/constant/StringInfo.java | 6 + .../com/coderising/jvm/constant/UTF8Info.java | 5 + .../src/com/coderising/jvm/method/Method.java | 7 + .../jvm/print/ClassFilePrinter.java | 54 ++++++ .../jvm/print/ConstantPoolPrinter.java | 83 ++++++++++ .../jvm/print/ConstantPoolPrinterBad.java | 40 +++++ .../jvm/test/ClassFileloaderTest.java | 79 ++++++++- 45 files changed, 1566 insertions(+), 40 deletions(-) delete mode 100644 liuxin/data-structure/src/com/coding/basic/Queue.java create mode 100644 liuxin/data-structure/src/com/coding/basic/queue/CircleQueue.java create mode 100644 liuxin/data-structure/src/com/coding/basic/queue/Josephus.java create mode 100644 liuxin/data-structure/src/com/coding/basic/queue/JosephusTest.java create mode 100644 liuxin/data-structure/src/com/coding/basic/queue/Queue.java create mode 100644 liuxin/data-structure/src/com/coding/basic/queue/QueueWithTwoStacks.java create mode 100644 liuxin/data-structure/src/com/coding/basic/stack/expr/InfixToPostfix.java create mode 100644 liuxin/data-structure/src/com/coding/basic/stack/expr/PostfixExpr.java create mode 100644 liuxin/data-structure/src/com/coding/basic/stack/expr/PostfixExprTest.java create mode 100644 liuxin/data-structure/src/com/coding/basic/stack/expr/PrefixExpr.java create mode 100644 liuxin/data-structure/src/com/coding/basic/stack/expr/PrefixExprTest.java create mode 100644 liuxin/data-structure/src/com/coding/basic/stack/expr/Token.java create mode 100644 liuxin/data-structure/src/com/coding/basic/stack/expr/TokenParser.java create mode 100644 liuxin/data-structure/src/com/coding/basic/stack/expr/TokenParserTest.java create mode 100644 liuxin/mini-jvm/src/com/coderising/jvm/cmd/BiPushCmd.java create mode 100644 liuxin/mini-jvm/src/com/coderising/jvm/cmd/ByteCodeCommand.java create mode 100644 liuxin/mini-jvm/src/com/coderising/jvm/cmd/CommandParser.java create mode 100644 liuxin/mini-jvm/src/com/coderising/jvm/cmd/GetFieldCmd.java create mode 100644 liuxin/mini-jvm/src/com/coderising/jvm/cmd/GetStaticFieldCmd.java create mode 100644 liuxin/mini-jvm/src/com/coderising/jvm/cmd/InvokeSpecialCmd.java create mode 100644 liuxin/mini-jvm/src/com/coderising/jvm/cmd/InvokeVirtualCmd.java create mode 100644 liuxin/mini-jvm/src/com/coderising/jvm/cmd/LdcCmd.java create mode 100644 liuxin/mini-jvm/src/com/coderising/jvm/cmd/NewObjectCmd.java create mode 100644 liuxin/mini-jvm/src/com/coderising/jvm/cmd/NoOperandCmd.java create mode 100644 liuxin/mini-jvm/src/com/coderising/jvm/cmd/OneOperandCmd.java create mode 100644 liuxin/mini-jvm/src/com/coderising/jvm/cmd/PutFieldCmd.java create mode 100644 liuxin/mini-jvm/src/com/coderising/jvm/cmd/TwoOperandCmd.java create mode 100644 liuxin/mini-jvm/src/com/coderising/jvm/print/ClassFilePrinter.java create mode 100644 liuxin/mini-jvm/src/com/coderising/jvm/print/ConstantPoolPrinter.java create mode 100644 liuxin/mini-jvm/src/com/coderising/jvm/print/ConstantPoolPrinterBad.java diff --git a/liuxin/data-structure/src/com/coding/basic/Queue.java b/liuxin/data-structure/src/com/coding/basic/Queue.java deleted file mode 100644 index 36e516e266..0000000000 --- a/liuxin/data-structure/src/com/coding/basic/Queue.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.coding.basic; - -public class Queue { - - public void enQueue(Object o){ - } - - public Object deQueue(){ - return null; - } - - public boolean isEmpty(){ - return false; - } - - public int size(){ - return -1; - } -} diff --git a/liuxin/data-structure/src/com/coding/basic/queue/CircleQueue.java b/liuxin/data-structure/src/com/coding/basic/queue/CircleQueue.java new file mode 100644 index 0000000000..ff94d5e21a --- /dev/null +++ b/liuxin/data-structure/src/com/coding/basic/queue/CircleQueue.java @@ -0,0 +1,5 @@ +package com.coding.basic.queue; + +public class CircleQueue { + +} diff --git a/liuxin/data-structure/src/com/coding/basic/queue/Josephus.java b/liuxin/data-structure/src/com/coding/basic/queue/Josephus.java new file mode 100644 index 0000000000..e42cfd4af2 --- /dev/null +++ b/liuxin/data-structure/src/com/coding/basic/queue/Josephus.java @@ -0,0 +1,33 @@ +package com.coding.basic.queue; + +import java.util.ArrayList; +import java.util.List; + +/** + * 用Queue来实现Josephus问题 + * 在这个古老的问题当中, N个深陷绝境的人一致同意用这种方式减少生存人数: N个人围成一圈(位置记为0到N-1), 并且从第一个人报数, 报到M的人会被杀死, 知道最后一个人留下来 + * @author liuxin + * + */ +public class Josephus { + + public static List<Integer> execute(int n, int m){ + + Queue<Integer> queue = new Queue<Integer>(); + for (int i = 0; i < n; i++){ + queue.enQueue(i); + } + + List<Integer> result = new ArrayList<Integer>(); + + while (!queue.isEmpty()) { + for (int i = 0; i < m-1; i++){ + queue.enQueue(queue.deQueue()); + } + result.add(queue.deQueue()); + + } + return result; + } + +} diff --git a/liuxin/data-structure/src/com/coding/basic/queue/JosephusTest.java b/liuxin/data-structure/src/com/coding/basic/queue/JosephusTest.java new file mode 100644 index 0000000000..7f0f2a9078 --- /dev/null +++ b/liuxin/data-structure/src/com/coding/basic/queue/JosephusTest.java @@ -0,0 +1,27 @@ +package com.coding.basic.queue; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + + +public class JosephusTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testExecute() { + + Assert.assertEquals("[1, 3, 5, 0, 4, 2, 6]", Josephus.execute(7, 2).toString()); + + } + +} diff --git a/liuxin/data-structure/src/com/coding/basic/queue/Queue.java b/liuxin/data-structure/src/com/coding/basic/queue/Queue.java new file mode 100644 index 0000000000..1430d84f7c --- /dev/null +++ b/liuxin/data-structure/src/com/coding/basic/queue/Queue.java @@ -0,0 +1,61 @@ +package com.coding.basic.queue; + +import java.util.NoSuchElementException; + +public class Queue<E> { + private Node<E> first; + private Node<E> last; + private int size; + + + private static class Node<E> { + private E item; + private Node<E> next; + } + + + public Queue() { + first = null; + last = null; + size = 0; + } + + + public boolean isEmpty() { + return first == null; + } + + public int size() { + return size; + } + + + + public void enQueue(E data) { + Node<E> oldlast = last; + last = new Node<E>(); + last.item = data; + last.next = null; + if (isEmpty()) { + first = last; + } + else{ + oldlast.next = last; + } + size++; + } + + public E deQueue() { + if (isEmpty()) { + throw new NoSuchElementException("Queue underflow"); + } + E item = first.item; + first = first.next; + size--; + if (isEmpty()) { + last = null; + } + return item; + } + +} diff --git a/liuxin/data-structure/src/com/coding/basic/queue/QueueWithTwoStacks.java b/liuxin/data-structure/src/com/coding/basic/queue/QueueWithTwoStacks.java new file mode 100644 index 0000000000..cc895d7358 --- /dev/null +++ b/liuxin/data-structure/src/com/coding/basic/queue/QueueWithTwoStacks.java @@ -0,0 +1,54 @@ +package com.coding.basic.queue; + +import java.util.NoSuchElementException; +import java.util.Stack; + +public class QueueWithTwoStacks<E> { + private Stack<E> stack1; + private Stack<E> stack2; + + + public QueueWithTwoStacks() { + stack1 = new Stack<E>(); + stack2 = new Stack<E>(); + } + + + private void moveStack1ToStack2() { + while (!stack1.isEmpty()){ + stack2.push(stack1.pop()); + } + + } + + + public boolean isEmpty() { + return stack1.isEmpty() && stack2.isEmpty(); + } + + + + public int size() { + return stack1.size() + stack2.size(); + } + + + + public void enQueue(E item) { + stack1.push(item); + } + + public E deQueue() { + if (isEmpty()) { + throw new NoSuchElementException("Queue is empty"); + } + if (stack2.isEmpty()) { + moveStack1ToStack2(); + } + + return stack2.pop(); + } + + + } + diff --git a/liuxin/data-structure/src/com/coding/basic/stack/expr/InfixExpr.java b/liuxin/data-structure/src/com/coding/basic/stack/expr/InfixExpr.java index 0a145ff047..201b932ce9 100644 --- a/liuxin/data-structure/src/com/coding/basic/stack/expr/InfixExpr.java +++ b/liuxin/data-structure/src/com/coding/basic/stack/expr/InfixExpr.java @@ -1,5 +1,9 @@ package com.coding.basic.stack.expr; +import java.util.List; +import java.util.Stack; + + public class InfixExpr { String expr = null; @@ -7,11 +11,67 @@ public InfixExpr(String expr) { this.expr = expr; } - public float evaluate() { + public float evaluate() { + + + TokenParser parser = new TokenParser(); + List<Token> tokens = parser.parse(this.expr); + + + Stack<Token> opStack = new Stack<>(); + Stack<Float> numStack = new Stack<>(); - return 0.0f; + for(Token token : tokens){ + + if (token.isOperator()){ + + if(opStack.isEmpty()){ + + opStack.push(token); + } else{ + + while(!opStack.isEmpty() + && !token.hasHigherPriority(opStack.peek())){ + Token prevOperator = opStack.pop(); + Float f2 = numStack.pop(); + Float f1 = numStack.pop(); + Float result = calculate(prevOperator.toString(), f1,f2); + numStack.push(result); + + } + opStack.push(token); + } + } + if(token.isNumber()){ + numStack.push(new Float(token.getIntValue())); + } + } + + while(!opStack.isEmpty()){ + Token token = opStack.pop(); + Float f2 = numStack.pop(); + Float f1 = numStack.pop(); + numStack.push(calculate(token.toString(), f1,f2)); + } + + + return numStack.pop().floatValue(); + } + private Float calculate(String op, Float f1, Float f2){ + if(op.equals("+")){ + return f1+f2; + } + if(op.equals("-")){ + return f1-f2; + } + if(op.equals("*")){ + return f1*f2; + } + if(op.equals("/")){ + return f1/f2; + } + throw new RuntimeException(op + " is not supported"); } - diff --git a/liuxin/data-structure/src/com/coding/basic/stack/expr/InfixExprTest.java b/liuxin/data-structure/src/com/coding/basic/stack/expr/InfixExprTest.java index 92d130cddd..5a49f6ce20 100644 --- a/liuxin/data-structure/src/com/coding/basic/stack/expr/InfixExprTest.java +++ b/liuxin/data-structure/src/com/coding/basic/stack/expr/InfixExprTest.java @@ -42,6 +42,10 @@ public void testEvaluate() { InfixExpr expr = new InfixExpr("10-30+50"); Assert.assertEquals(30, expr.evaluate(), 0.001f); } + { + InfixExpr expr = new InfixExpr("10-2*3+50"); + Assert.assertEquals(54, expr.evaluate(), 0.001f); + } } diff --git a/liuxin/data-structure/src/com/coding/basic/stack/expr/InfixToPostfix.java b/liuxin/data-structure/src/com/coding/basic/stack/expr/InfixToPostfix.java new file mode 100644 index 0000000000..ea86ef155f --- /dev/null +++ b/liuxin/data-structure/src/com/coding/basic/stack/expr/InfixToPostfix.java @@ -0,0 +1,52 @@ +package com.coding.basic.stack.expr; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +public class InfixToPostfix { + + public static List<Token> convert(String expr) { + + TokenParser parser = new TokenParser(); + List<Token> tokens = parser.parse(expr); + + Stack<Token> s = new Stack<Token>(); + List<Token> result = new ArrayList<Token>(); + + for(Token token : tokens){ + if(token.isOperator()){ + if(token.toString().equals("*") || token.toString().equals("/")){ + + while (!s.empty() + && !s.peek().toString().equals("+") + && !s.peek().toString().equals("-")) { + + result.add(s.pop()); + + } + + s.push(token); + } + if(token.toString().equals("+") || token.toString().equals("-")){ + while (!s.empty() ) { + result.add(s.pop()); + } + s.push(token); + } + } + if(token.isNumber()){ + result.add(token); + } + } + + return result; + } + + public static void main(String[] args){ + List<Token> tokens = convert("10+20*2"); + System.out.println(tokens); + + } + +} diff --git a/liuxin/data-structure/src/com/coding/basic/stack/expr/PostfixExpr.java b/liuxin/data-structure/src/com/coding/basic/stack/expr/PostfixExpr.java new file mode 100644 index 0000000000..d87a314fb4 --- /dev/null +++ b/liuxin/data-structure/src/com/coding/basic/stack/expr/PostfixExpr.java @@ -0,0 +1,46 @@ +package com.coding.basic.stack.expr; + +import java.util.List; +import java.util.Stack; + +public class PostfixExpr { +String expr = null; + + public PostfixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + TokenParser parser = new TokenParser(); + List<Token> tokens = parser.parse(this.expr); + + + Stack<Float> numStack = new Stack<>(); + for(Token token : tokens){ + if(token.isNumber()){ + numStack.push(new Float(token.getIntValue())); + } else{ + Float f2 = numStack.pop(); + Float f1 = numStack.pop(); + numStack.push(calculate(token.toString(),f1,f2)); + } + } + return numStack.pop().floatValue(); + } + + private Float calculate(String op, Float f1, Float f2){ + if(op.equals("+")){ + return f1+f2; + } + if(op.equals("-")){ + return f1-f2; + } + if(op.equals("*")){ + return f1*f2; + } + if(op.equals("/")){ + return f1/f2; + } + throw new RuntimeException(op + " is not supported"); + } +} diff --git a/liuxin/data-structure/src/com/coding/basic/stack/expr/PostfixExprTest.java b/liuxin/data-structure/src/com/coding/basic/stack/expr/PostfixExprTest.java new file mode 100644 index 0000000000..3de5f12291 --- /dev/null +++ b/liuxin/data-structure/src/com/coding/basic/stack/expr/PostfixExprTest.java @@ -0,0 +1,41 @@ +package com.coding.basic.stack.expr; + + + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + + +public class PostfixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + { + PostfixExpr expr = new PostfixExpr("6 5 2 3 + 8 * + 3 + *"); + Assert.assertEquals(288, expr.evaluate(),0.0f); + } + { + //9+(3-1)*3+10/2 + PostfixExpr expr = new PostfixExpr("9 3 1-3*+ 10 2/+"); + Assert.assertEquals(20, expr.evaluate(),0.0f); + } + + { + //10-2*3+50 + PostfixExpr expr = new PostfixExpr("10 2 3 * - 50 +"); + Assert.assertEquals(54, expr.evaluate(),0.0f); + } + } + +} diff --git a/liuxin/data-structure/src/com/coding/basic/stack/expr/PrefixExpr.java b/liuxin/data-structure/src/com/coding/basic/stack/expr/PrefixExpr.java new file mode 100644 index 0000000000..e30b1d16ad --- /dev/null +++ b/liuxin/data-structure/src/com/coding/basic/stack/expr/PrefixExpr.java @@ -0,0 +1,52 @@ +package com.coding.basic.stack.expr; + +import java.util.List; +import java.util.Stack; + +public class PrefixExpr { + String expr = null; + + public PrefixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + TokenParser parser = new TokenParser(); + List<Token> tokens = parser.parse(this.expr); + + Stack<Token> exprStack = new Stack<>(); + Stack<Float> numStack = new Stack<>(); + for(Token token : tokens){ + exprStack.push(token); + } + + while(!exprStack.isEmpty()){ + Token t = exprStack.pop(); + if(t.isNumber()){ + numStack.push(new Float(t.getIntValue())); + }else{ + Float f1 = numStack.pop(); + Float f2 = numStack.pop(); + numStack.push(calculate(t.toString(),f1,f2)); + + } + } + return numStack.pop().floatValue(); + } + + private Float calculate(String op, Float f1, Float f2){ + if(op.equals("+")){ + return f1+f2; + } + if(op.equals("-")){ + return f1-f2; + } + if(op.equals("*")){ + return f1*f2; + } + if(op.equals("/")){ + return f1/f2; + } + throw new RuntimeException(op + " is not supported"); + } +} diff --git a/liuxin/data-structure/src/com/coding/basic/stack/expr/PrefixExprTest.java b/liuxin/data-structure/src/com/coding/basic/stack/expr/PrefixExprTest.java new file mode 100644 index 0000000000..b617dbcc93 --- /dev/null +++ b/liuxin/data-structure/src/com/coding/basic/stack/expr/PrefixExprTest.java @@ -0,0 +1,45 @@ +package com.coding.basic.stack.expr; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class PrefixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + { + // 2*3+4*5 + PrefixExpr expr = new PrefixExpr("+ * 2 3* 4 5"); + Assert.assertEquals(26, expr.evaluate(),0.001f); + } + { + // 4*2 + 6+9*2/3 -8 + PrefixExpr expr = new PrefixExpr("-++6/*2 9 3 * 4 2 8"); + Assert.assertEquals(12, expr.evaluate(),0.001f); + } + { + //(3+4)*5-6 + PrefixExpr expr = new PrefixExpr("- * + 3 4 5 6"); + Assert.assertEquals(29, expr.evaluate(),0.001f); + } + { + //1+((2+3)*4)-5 + PrefixExpr expr = new PrefixExpr("- + 1 * + 2 3 4 5"); + Assert.assertEquals(16, expr.evaluate(),0.001f); + } + + + } + +} diff --git a/liuxin/data-structure/src/com/coding/basic/stack/expr/Token.java b/liuxin/data-structure/src/com/coding/basic/stack/expr/Token.java new file mode 100644 index 0000000000..115c6de3c6 --- /dev/null +++ b/liuxin/data-structure/src/com/coding/basic/stack/expr/Token.java @@ -0,0 +1,50 @@ +package com.coding.basic.stack.expr; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +class Token { + public static final List<String> OPERATORS = Arrays.asList("+", "-", "*", "/"); + private static final Map<String,Integer> priorities = new HashMap<>(); + static { + priorities.put("+", 1); + priorities.put("-", 1); + priorities.put("*", 2); + priorities.put("/", 2); + } + static final int OPERATOR = 1; + static final int NUMBER = 2; + String value; + int type; + public Token(int type, String value){ + this.type = type; + this.value = value; + } + + public boolean isNumber() { + return type == NUMBER; + } + + public boolean isOperator() { + return type == OPERATOR; + } + + public int getIntValue() { + return Integer.valueOf(value).intValue(); + } + public String toString(){ + return value; + } + + public boolean hasHigherPriority(Token t){ + if(!this.isOperator() && !t.isOperator()){ + throw new RuntimeException("numbers can't compare priority"); + } + return priorities.get(this.value) - priorities.get(t.value) > 0; + } + + + +} \ No newline at end of file diff --git a/liuxin/data-structure/src/com/coding/basic/stack/expr/TokenParser.java b/liuxin/data-structure/src/com/coding/basic/stack/expr/TokenParser.java new file mode 100644 index 0000000000..592449846a --- /dev/null +++ b/liuxin/data-structure/src/com/coding/basic/stack/expr/TokenParser.java @@ -0,0 +1,57 @@ +package com.coding.basic.stack.expr; + +import java.util.ArrayList; +import java.util.List; + +public class TokenParser { + + + public List<Token> parse(String expr) { + List<Token> tokens = new ArrayList<>(); + + int i = 0; + + while (i < expr.length()) { + + char c = expr.charAt(i); + + if (isOperator(c)) { + + Token t = new Token(Token.OPERATOR, String.valueOf(c)); + tokens.add(t); + i++; + + } else if (Character.isDigit(c)) { + + int nextOperatorIndex = indexOfNextOperator(i, expr); + String value = expr.substring(i, nextOperatorIndex); + Token t = new Token(Token.NUMBER, value); + tokens.add(t); + i = nextOperatorIndex; + + } else{ + System.out.println("char :["+c+"] is not number or operator,ignore"); + i++; + } + + } + return tokens; + } + + private int indexOfNextOperator(int i, String expr) { + + while (Character.isDigit(expr.charAt(i))) { + i++; + if (i == expr.length()) { + break; + } + } + return i; + + } + + private boolean isOperator(char c) { + String sc = String.valueOf(c); + return Token.OPERATORS.contains(sc); + } +} diff --git a/liuxin/data-structure/src/com/coding/basic/stack/expr/TokenParserTest.java b/liuxin/data-structure/src/com/coding/basic/stack/expr/TokenParserTest.java new file mode 100644 index 0000000000..b0bcd30f78 --- /dev/null +++ b/liuxin/data-structure/src/com/coding/basic/stack/expr/TokenParserTest.java @@ -0,0 +1,41 @@ +package com.coding.basic.stack.expr; + +import static org.junit.Assert.*; + +import java.util.List; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class TokenParserTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void test() { + + TokenParser parser = new TokenParser(); + List<Token> tokens = parser.parse("300*20+12*5-20/4"); + + Assert.assertEquals(300, tokens.get(0).getIntValue()); + Assert.assertEquals("*", tokens.get(1).toString()); + Assert.assertEquals(20, tokens.get(2).getIntValue()); + Assert.assertEquals("+", tokens.get(3).toString()); + Assert.assertEquals(12, tokens.get(4).getIntValue()); + Assert.assertEquals("*", tokens.get(5).toString()); + Assert.assertEquals(5, tokens.get(6).getIntValue()); + Assert.assertEquals("-", tokens.get(7).toString()); + Assert.assertEquals(20, tokens.get(8).getIntValue()); + Assert.assertEquals("/", tokens.get(9).toString()); + Assert.assertEquals(4, tokens.get(10).getIntValue()); + } + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java b/liuxin/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java index e00a6a6d49..c2343e8590 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java @@ -1,6 +1,8 @@ package com.coderising.jvm.attr; import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.cmd.ByteCodeCommand; +import com.coderising.jvm.cmd.CommandParser; import com.coderising.jvm.constant.ConstantPool; import com.coderising.jvm.loader.ByteCodeIterator; @@ -14,21 +16,21 @@ public String getCode() { return code; } - //private ByteCodeCommand[] cmds ; - //public ByteCodeCommand[] getCmds() { - // return cmds; - //} + private ByteCodeCommand[] cmds ; + public ByteCodeCommand[] getCmds() { + return cmds; + } private LineNumberTable lineNumTable; private LocalVariableTable localVarTable; private StackMapTable stackMapTable; - public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen,String code /*ByteCodeCommand[] cmds*/) { + public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen,String code ,ByteCodeCommand[] cmds) { super(attrNameIndex, attrLen); this.maxStack = maxStack; this.maxLocals = maxLocals; this.codeLen = codeLen; this.code = code; - //this.cmds = cmds; + this.cmds = cmds; } public void setLineNumberTable(LineNumberTable t) { @@ -39,7 +41,7 @@ public void setLocalVariableTable(LocalVariableTable t) { this.localVarTable = t; } -public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ + public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ int attrNameIndex = iter.nextU2ToInt(); int attrLen = iter.nextU4ToInt(); @@ -47,13 +49,12 @@ public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ int maxLocals = iter.nextU2ToInt(); int codeLen = iter.nextU4ToInt(); - String code = iter.nextUxToHexString(codeLen); + String code = iter.nextUxToHexString(codeLen); - System.out.println(code); - //ByteCodeCommand[] cmds = ByteCodeCommand.parse(clzFile,code); + ByteCodeCommand[] cmds = CommandParser.parse(clzFile,code); - CodeAttr codeAttr = new CodeAttr(attrNameIndex,attrLen, maxStack,maxLocals,codeLen,code); + CodeAttr codeAttr = new CodeAttr(attrNameIndex,attrLen, maxStack,maxLocals,codeLen,code,cmds); int exceptionTableLen = iter.nextU2ToInt(); //TODO 处理exception @@ -99,10 +100,10 @@ else if (AttributeInfo.STACK_MAP_TABLE.equalsIgnoreCase(subAttrName)){ public String toString(ConstantPool pool){ StringBuilder buffer = new StringBuilder(); - buffer.append("Code:").append(code).append("\n"); - /*for(int i=0;i<cmds.length;i++){ + //buffer.append("Code:").append(code).append("\n"); + for(int i=0;i<cmds.length;i++){ buffer.append(cmds[i].toString(pool)).append("\n"); - }*/ + } buffer.append("\n"); buffer.append(this.lineNumTable.toString()); buffer.append(this.localVarTable.toString(pool)); diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java b/liuxin/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java index c21a0988e5..f91b9e48f4 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java @@ -80,13 +80,41 @@ public void print(){ } - private String getClassName(){ + public String getClassName(){ int thisClassIndex = this.clzIndex.getThisClassIndex(); ClassInfo thisClass = (ClassInfo)this.getConstantPool().getConstantInfo(thisClassIndex); return thisClass.getClassName(); } - private String getSuperClassName(){ + public String getSuperClassName(){ ClassInfo superClass = (ClassInfo)this.getConstantPool().getConstantInfo(this.clzIndex.getSuperClassIndex()); return superClass.getClassName(); } + + public Method getMethod(String methodName, String paramAndReturnType){ + + for(Method m :methods){ + + int nameIndex = m.getNameIndex(); + int descriptionIndex = m.getDescriptorIndex(); + + String name = this.getConstantPool().getUTF8String(nameIndex); + String desc = this.getConstantPool().getUTF8String(descriptionIndex); + if(name.equals(methodName) && desc.equals(paramAndReturnType)){ + return m; + } + } + return null; + } + public Method getMainMethod(){ + for(Method m :methods){ + int nameIndex = m.getNameIndex(); + int descIndex = m.getDescriptorIndex(); + String name = this.getConstantPool().getUTF8String(nameIndex); + String desc = this.getConstantPool().getUTF8String(descIndex); + if(name.equals("main") && desc.equals("([Ljava/lang/String;)V")){ + return m; + } + } + return null; + } } diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/BiPushCmd.java b/liuxin/mini-jvm/src/com/coderising/jvm/cmd/BiPushCmd.java new file mode 100644 index 0000000000..8c15e1bd44 --- /dev/null +++ b/liuxin/mini-jvm/src/com/coderising/jvm/cmd/BiPushCmd.java @@ -0,0 +1,23 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantInfo; +import com.coderising.jvm.constant.ConstantPool; + + +public class BiPushCmd extends OneOperandCmd { + + public BiPushCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + + } + + @Override + public String toString(ConstantPool pool) { + + return this.getOffset()+": "+ this.getOpCode()+" " + this.getReadableCodeText() + " " + this.getOperand(); + } + + + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/ByteCodeCommand.java b/liuxin/mini-jvm/src/com/coderising/jvm/cmd/ByteCodeCommand.java new file mode 100644 index 0000000000..85f6f637d4 --- /dev/null +++ b/liuxin/mini-jvm/src/com/coderising/jvm/cmd/ByteCodeCommand.java @@ -0,0 +1,128 @@ +package com.coderising.jvm.cmd; + +import java.util.HashMap; +import java.util.Map; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantInfo; +import com.coderising.jvm.constant.ConstantPool; + + +public abstract class ByteCodeCommand { + + String opCode; + ClassFile clzFile; + private int offset; + + private static Map<String,String> codeMap = new HashMap<String,String>(); + + static{ + codeMap.put("01", "aconst_null"); + + codeMap.put("BB", "new"); + codeMap.put("37", "lstore"); + codeMap.put("B7", "invokespecial"); + codeMap.put("B6", "invokevirtual"); + codeMap.put("B4", "getfield"); + codeMap.put("B5", "putfield"); + codeMap.put("B2", "getstatic"); + + codeMap.put("2A", "aload_0"); + codeMap.put("2B", "aload_1"); + codeMap.put("2C", "aload_2"); + + codeMap.put("10", "bipush"); + codeMap.put("15", "iload"); + codeMap.put("1A", "iload_0"); + codeMap.put("1B", "iload_1"); + codeMap.put("1C", "iload_2"); + codeMap.put("1D", "iload_3"); + + codeMap.put("25", "fload_3"); + + codeMap.put("1E", "lload_0"); + + codeMap.put("24", "fload_2"); + codeMap.put("4C", "astore_1"); + + codeMap.put("A2", "if_icmp_ge"); + codeMap.put("A4", "if_icmple"); + + codeMap.put("A7", "goto"); + + codeMap.put("B1", "return"); + codeMap.put("AC", "ireturn"); + codeMap.put("AE", "freturn"); + + codeMap.put("03", "iconst_0"); + codeMap.put("04", "iconst_1"); + + codeMap.put("3C", "istore_1"); + codeMap.put("3D", "istore_2"); + + codeMap.put("59", "dup"); + + codeMap.put("60", "iadd"); + codeMap.put("84", "iinc"); + + codeMap.put("12", "ldc"); + } + + + + + + protected ByteCodeCommand(ClassFile clzFile, String opCode){ + this.clzFile = clzFile; + this.opCode = opCode; + } + + protected ClassFile getClassFile() { + return clzFile; + } + + public int getOffset() { + return offset; + } + + public void setOffset(int offset) { + this.offset = offset; + } + protected ConstantInfo getConstantInfo(int index){ + return this.getClassFile().getConstantPool().getConstantInfo(index); + } + + protected ConstantPool getConstantPool(){ + return this.getClassFile().getConstantPool(); + } + + + + public String getOpCode() { + return opCode; + } + + public abstract int getLength(); + + + + + public String toString(){ + + StringBuffer buffer = new StringBuffer(); + buffer.append(this.opCode); + + return buffer.toString(); + } + public abstract String toString(ConstantPool pool); + + public String getReadableCodeText(){ + String txt = codeMap.get(opCode); + if(txt == null){ + return opCode; + } + return txt; + } + + //public abstract void execute(StackFrame frame,FrameResult result); +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/CommandParser.java b/liuxin/mini-jvm/src/com/coderising/jvm/cmd/CommandParser.java new file mode 100644 index 0000000000..0dd0573ae5 --- /dev/null +++ b/liuxin/mini-jvm/src/com/coderising/jvm/cmd/CommandParser.java @@ -0,0 +1,155 @@ +package com.coderising.jvm.cmd; + +import java.util.ArrayList; +import java.util.List; + +import com.coderising.jvm.clz.ClassFile; + +public class CommandParser { + + public static final String aconst_null = "01"; + public static final String new_object = "BB"; + public static final String lstore = "37"; + public static final String invokespecial = "B7"; + public static final String invokevirtual = "B6"; + public static final String getfield = "B4"; + public static final String putfield = "B5"; + public static final String getstatic = "B2"; + public static final String ldc = "12"; + public static final String dup = "59"; + public static final String bipush = "10"; + public static final String aload_0 = "2A"; + public static final String aload_1 = "2B"; + public static final String aload_2 = "2C"; + public static final String iload = "15"; + public static final String iload_1 = "1B"; + public static final String iload_2 = "1C"; + public static final String iload_3 = "1D"; + public static final String fload_3 = "25"; + + public static final String voidreturn = "B1"; + public static final String ireturn = "AC"; + public static final String freturn = "AE"; + + public static final String astore_1 = "4C"; + public static final String if_icmp_ge = "A2"; + public static final String if_icmple = "A4"; + public static final String goto_no_condition = "A7"; + public static final String iconst_0 = "03"; + public static final String iconst_1 = "04"; + public static final String istore_1 = "3C"; + public static final String istore_2 = "3D"; + public static final String iadd = "60"; + public static final String iinc = "84"; + + public static ByteCodeCommand[] parse(ClassFile clzFile, String codes) { + + if ((codes == null) || (codes.length() == 0) || (codes.length() % 2) != 0) { + throw new RuntimeException("the orignal code is not correct"); + + } + + codes = codes.toUpperCase(); + + CommandIterator iter = new CommandIterator(codes); + List<ByteCodeCommand> cmds = new ArrayList<ByteCodeCommand>(); + + while (iter.hasNext()) { + String opCode = iter.next2CharAsString(); + + if (new_object.equals(opCode)) { + NewObjectCmd cmd = new NewObjectCmd(clzFile, opCode); + + cmd.setOprand1(iter.next2CharAsInt()); + cmd.setOprand2(iter.next2CharAsInt()); + + cmds.add(cmd); + } else if (invokespecial.equals(opCode)) { + InvokeSpecialCmd cmd = new InvokeSpecialCmd(clzFile, opCode); + cmd.setOprand1(iter.next2CharAsInt()); + cmd.setOprand2(iter.next2CharAsInt()); + // System.out.println( cmd.toString(clzFile.getConstPool())); + cmds.add(cmd); + } else if (invokevirtual.equals(opCode)) { + InvokeVirtualCmd cmd = new InvokeVirtualCmd(clzFile, opCode); + cmd.setOprand1(iter.next2CharAsInt()); + cmd.setOprand2(iter.next2CharAsInt()); + + cmds.add(cmd); + } else if (getfield.equals(opCode)) { + GetFieldCmd cmd = new GetFieldCmd(clzFile, opCode); + cmd.setOprand1(iter.next2CharAsInt()); + cmd.setOprand2(iter.next2CharAsInt()); + cmds.add(cmd); + } else if (getstatic.equals(opCode)) { + GetStaticFieldCmd cmd = new GetStaticFieldCmd(clzFile, opCode); + cmd.setOprand1(iter.next2CharAsInt()); + cmd.setOprand2(iter.next2CharAsInt()); + cmds.add(cmd); + } else if (putfield.equals(opCode)) { + PutFieldCmd cmd = new PutFieldCmd(clzFile, opCode); + cmd.setOprand1(iter.next2CharAsInt()); + cmd.setOprand2(iter.next2CharAsInt()); + cmds.add(cmd); + } else if (ldc.equals(opCode)) { + LdcCmd cmd = new LdcCmd(clzFile, opCode); + cmd.setOperand(iter.next2CharAsInt()); + cmds.add(cmd); + } else if (bipush.equals(opCode)) { + BiPushCmd cmd = new BiPushCmd(clzFile, opCode); + cmd.setOperand(iter.next2CharAsInt()); + cmds.add(cmd); + } else if (dup.equals(opCode) || aload_0.equals(opCode) || aload_1.equals(opCode) || aload_2.equals(opCode) + || iload_1.equals(opCode) || iload_2.equals(opCode) || iload_3.equals(opCode) + || fload_3.equals(opCode) || voidreturn.equals(opCode) || astore_1.equals(opCode)) { + + NoOperandCmd cmd = new NoOperandCmd(clzFile, opCode); + cmds.add(cmd); + } else { + throw new RuntimeException("Sorry, the java instruction " + opCode + " has not been implemented"); + } + + } + + calcuateOffset(cmds); + + ByteCodeCommand[] result = new ByteCodeCommand[cmds.size()]; + cmds.toArray(result); + return result; + } + + private static void calcuateOffset(List<ByteCodeCommand> cmds) { + + int offset = 0; + for (ByteCodeCommand cmd : cmds) { + cmd.setOffset(offset); + offset += cmd.getLength(); + } + + } + + private static class CommandIterator { + String codes = null; + int pos = 0; + + CommandIterator(String codes) { + this.codes = codes; + } + + public boolean hasNext() { + return pos < this.codes.length(); + } + + public String next2CharAsString() { + String result = codes.substring(pos, pos + 2); + pos += 2; + return result; + } + + public int next2CharAsInt() { + String s = this.next2CharAsString(); + return Integer.valueOf(s, 16).intValue(); + } + + } +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/GetFieldCmd.java b/liuxin/mini-jvm/src/com/coderising/jvm/cmd/GetFieldCmd.java new file mode 100644 index 0000000000..4d989d6cbb --- /dev/null +++ b/liuxin/mini-jvm/src/com/coderising/jvm/cmd/GetFieldCmd.java @@ -0,0 +1,22 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; + + +public class GetFieldCmd extends TwoOperandCmd { + + public GetFieldCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsField(pool); + } + + + + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/GetStaticFieldCmd.java b/liuxin/mini-jvm/src/com/coderising/jvm/cmd/GetStaticFieldCmd.java new file mode 100644 index 0000000000..9fb13677eb --- /dev/null +++ b/liuxin/mini-jvm/src/com/coderising/jvm/cmd/GetStaticFieldCmd.java @@ -0,0 +1,23 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.FieldRefInfo; +import com.coderising.jvm.constant.UTF8Info; + + +public class GetStaticFieldCmd extends TwoOperandCmd { + + public GetStaticFieldCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsField(pool); + } + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/InvokeSpecialCmd.java b/liuxin/mini-jvm/src/com/coderising/jvm/cmd/InvokeSpecialCmd.java new file mode 100644 index 0000000000..5ac3454be7 --- /dev/null +++ b/liuxin/mini-jvm/src/com/coderising/jvm/cmd/InvokeSpecialCmd.java @@ -0,0 +1,23 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.MethodRefInfo; + + +public class InvokeSpecialCmd extends TwoOperandCmd { + + public InvokeSpecialCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsMethod(pool); + } + + + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/InvokeVirtualCmd.java b/liuxin/mini-jvm/src/com/coderising/jvm/cmd/InvokeVirtualCmd.java new file mode 100644 index 0000000000..303a64b4c7 --- /dev/null +++ b/liuxin/mini-jvm/src/com/coderising/jvm/cmd/InvokeVirtualCmd.java @@ -0,0 +1,22 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; + + +public class InvokeVirtualCmd extends TwoOperandCmd { + + public InvokeVirtualCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsMethod(pool); + } + + + + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/LdcCmd.java b/liuxin/mini-jvm/src/com/coderising/jvm/cmd/LdcCmd.java new file mode 100644 index 0000000000..00f9a5a699 --- /dev/null +++ b/liuxin/mini-jvm/src/com/coderising/jvm/cmd/LdcCmd.java @@ -0,0 +1,29 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantInfo; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.StringInfo; + +public class LdcCmd extends OneOperandCmd { + + public LdcCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + ConstantInfo info = (ConstantInfo)pool.getConstantInfo(this.getOperand()); + + String value = "TBD"; + if(info instanceof StringInfo){ + StringInfo strInfo = (StringInfo)info; + value = strInfo.toString(); + } + + return this.getOffset()+":"+this.getOpCode()+" " + this.getReadableCodeText() + " "+ value; + + } + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/NewObjectCmd.java b/liuxin/mini-jvm/src/com/coderising/jvm/cmd/NewObjectCmd.java new file mode 100644 index 0000000000..a43c8bd964 --- /dev/null +++ b/liuxin/mini-jvm/src/com/coderising/jvm/cmd/NewObjectCmd.java @@ -0,0 +1,19 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; + +public class NewObjectCmd extends TwoOperandCmd{ + + public NewObjectCmd(ClassFile clzFile, String opCode){ + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsClassInfo(pool); + } + + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/NoOperandCmd.java b/liuxin/mini-jvm/src/com/coderising/jvm/cmd/NoOperandCmd.java new file mode 100644 index 0000000000..92e5c4f3f1 --- /dev/null +++ b/liuxin/mini-jvm/src/com/coderising/jvm/cmd/NoOperandCmd.java @@ -0,0 +1,23 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; + +public class NoOperandCmd extends ByteCodeCommand{ + + public NoOperandCmd(ClassFile clzFile, String opCode) { + super(clzFile, opCode); + } + + @Override + public String toString(ConstantPool pool) { + return this.getOffset()+":" +this.getOpCode() + " "+ this.getReadableCodeText(); + } + + + + public int getLength(){ + return 1; + } + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/OneOperandCmd.java b/liuxin/mini-jvm/src/com/coderising/jvm/cmd/OneOperandCmd.java new file mode 100644 index 0000000000..6b1b8c284c --- /dev/null +++ b/liuxin/mini-jvm/src/com/coderising/jvm/cmd/OneOperandCmd.java @@ -0,0 +1,27 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; + +public abstract class OneOperandCmd extends ByteCodeCommand { + + private int operand; + + public OneOperandCmd(ClassFile clzFile,String opCode) { + super(clzFile, opCode); + + } + public int getOperand() { + + return this.operand; + } + + public void setOperand(int oprand1) { + this.operand = oprand1; + + } + public int getLength(){ + return 2; + } + + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/PutFieldCmd.java b/liuxin/mini-jvm/src/com/coderising/jvm/cmd/PutFieldCmd.java new file mode 100644 index 0000000000..00b29e1fbc --- /dev/null +++ b/liuxin/mini-jvm/src/com/coderising/jvm/cmd/PutFieldCmd.java @@ -0,0 +1,19 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; + +public class PutFieldCmd extends TwoOperandCmd { + + public PutFieldCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsField(pool); + } + + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/TwoOperandCmd.java b/liuxin/mini-jvm/src/com/coderising/jvm/cmd/TwoOperandCmd.java new file mode 100644 index 0000000000..334eec9f98 --- /dev/null +++ b/liuxin/mini-jvm/src/com/coderising/jvm/cmd/TwoOperandCmd.java @@ -0,0 +1,67 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +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; + +public abstract class TwoOperandCmd extends ByteCodeCommand{ + + int oprand1 = -1; + int oprand2 = -1; + + public int getOprand1() { + return oprand1; + } + + public void setOprand1(int oprand1) { + this.oprand1 = oprand1; + } + + public void setOprand2(int oprand2) { + this.oprand2 = oprand2; + } + + public int getOprand2() { + return oprand2; + } + + public TwoOperandCmd(ClassFile clzFile,String opCode) { + super(clzFile, opCode); + } + + public int getIndex(){ + int oprand1 = this.getOprand1(); + int oprand2 = this.getOprand2(); + int index = oprand1 << 8 | oprand2; + return index; + } + + protected String getOperandAsClassInfo(ConstantPool pool){ + int index = getIndex(); + String codeTxt = getReadableCodeText(); + ClassInfo info = (ClassInfo)pool.getConstantInfo(index); + return this.getOffset()+":"+this.getOpCode()+" "+ codeTxt +" "+ info.getClassName(); + } + + protected String getOperandAsMethod(ConstantPool pool){ + int index = getIndex(); + String codeTxt = getReadableCodeText(); + ConstantInfo constInfo = this.getConstantInfo(index); + MethodRefInfo info = (MethodRefInfo)this.getConstantInfo(index); + return this.getOffset()+":"+this.getOpCode()+" " + codeTxt +" "+ info.toString(); + } + + protected String getOperandAsField(ConstantPool pool){ + int index = getIndex(); + + String codeTxt = getReadableCodeText(); + FieldRefInfo info = (FieldRefInfo)this.getConstantInfo(index); + return this.getOffset()+":"+this.getOpCode()+" " + codeTxt +" "+ info.toString(); + } + public int getLength(){ + return 3; + } +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/constant/ClassInfo.java b/liuxin/mini-jvm/src/com/coderising/jvm/constant/ClassInfo.java index aea9048ea4..c8e65ff493 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/constant/ClassInfo.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/constant/ClassInfo.java @@ -21,4 +21,8 @@ public String getClassName() { UTF8Info utf8Info = (UTF8Info)constantPool.getConstantInfo(index); return utf8Info.getValue(); } + @Override + public void accept(Visitor visitor) { + visitor.visitClassInfo(this); + } } diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/constant/ConstantInfo.java b/liuxin/mini-jvm/src/com/coderising/jvm/constant/ConstantInfo.java index 466b072244..88353df2d3 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/constant/ConstantInfo.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/constant/ConstantInfo.java @@ -26,4 +26,15 @@ public ConstantInfo getConstantInfo(int index){ return this.constantPool.getConstantInfo(index); } + public abstract void accept(Visitor visitor); + + public static interface Visitor{ + public void visitClassInfo(ClassInfo info); + public void visitFieldRef(FieldRefInfo info); + public void visitMethodRef(MethodRefInfo info); + public void visitNameAndType(NameAndTypeInfo info); + public void visitString(StringInfo info); + public void visistUTF8(UTF8Info info); + + } } diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/constant/ConstantPool.java b/liuxin/mini-jvm/src/com/coderising/jvm/constant/ConstantPool.java index 86c0445695..7130eb3a9f 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/constant/ConstantPool.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/constant/ConstantPool.java @@ -23,7 +23,9 @@ public ConstantInfo getConstantInfo(int index){ public String getUTF8String(int index){ return ((UTF8Info)this.constantInfos.get(index)).getValue(); } - public Object getSize() { + public int getSize() { return this.constantInfos.size() -1; } + + } diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/constant/FieldRefInfo.java b/liuxin/mini-jvm/src/com/coderising/jvm/constant/FieldRefInfo.java index 65475e194c..7ae71396ef 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/constant/FieldRefInfo.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/constant/FieldRefInfo.java @@ -51,4 +51,8 @@ public String getFieldType(){ NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); return typeInfo.getTypeInfo(); } + @Override + public void accept(Visitor visitor) { + visitor.visitFieldRef(this); + } } diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/constant/MethodRefInfo.java b/liuxin/mini-jvm/src/com/coderising/jvm/constant/MethodRefInfo.java index 7f05870020..036e6d9055 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/constant/MethodRefInfo.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/constant/MethodRefInfo.java @@ -49,6 +49,11 @@ public String getParamAndReturnType(){ NameAndTypeInfo typeInfo = (NameAndTypeInfo)pool.getConstantInfo(this.getNameAndTypeIndex()); return typeInfo.getTypeInfo(); } + + @Override + public void accept(Visitor visitor) { + visitor.visitMethodRef(this); + } diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/constant/NameAndTypeInfo.java b/liuxin/mini-jvm/src/com/coderising/jvm/constant/NameAndTypeInfo.java index 402f9dec86..5cbbba6033 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/constant/NameAndTypeInfo.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/constant/NameAndTypeInfo.java @@ -42,4 +42,10 @@ public String getTypeInfo(){ public String toString(){ return "(" + getName() + "," + getTypeInfo()+")"; } + + @Override + public void accept(Visitor visitor) { + visitor.visitNameAndType(this); + + } } diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/constant/NullConstantInfo.java b/liuxin/mini-jvm/src/com/coderising/jvm/constant/NullConstantInfo.java index 936736016f..41e0fd7e7a 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/constant/NullConstantInfo.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/constant/NullConstantInfo.java @@ -9,5 +9,9 @@ public NullConstantInfo(){ public int getType() { return -1; } + @Override + public void accept(Visitor visitor) { + + } } diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/constant/StringInfo.java b/liuxin/mini-jvm/src/com/coderising/jvm/constant/StringInfo.java index f1f8eb4ed4..6bfcb47273 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/constant/StringInfo.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/constant/StringInfo.java @@ -22,5 +22,11 @@ public void setIndex(int index) { public String toString(){ return this.getConstantPool().getUTF8String(index); } + + @Override + public void accept(Visitor visitor) { + visitor.visitString(this); + + } } diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/constant/UTF8Info.java b/liuxin/mini-jvm/src/com/coderising/jvm/constant/UTF8Info.java index 5cac9f04f7..7db88a939e 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/constant/UTF8Info.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/constant/UTF8Info.java @@ -26,6 +26,11 @@ public String getValue() { public void setValue(String value) { this.value = value; } + @Override + public void accept(Visitor visitor) { + visitor.visistUTF8(this); + + } diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/method/Method.java b/liuxin/mini-jvm/src/com/coderising/jvm/method/Method.java index 6821b2137d..74f5ae8c16 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/method/Method.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/method/Method.java @@ -1,6 +1,7 @@ package com.coderising.jvm.method; import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.cmd.ByteCodeCommand; import com.coderising.jvm.attr.AttributeInfo; import com.coderising.jvm.attr.CodeAttr; import com.coderising.jvm.constant.ConstantPool; @@ -38,6 +39,8 @@ public CodeAttr getCodeAttr() { public void setCodeAttr(CodeAttr code) { this.codeAttr = code; } + + public Method(ClassFile clzFile,int accessFlag, int nameIndex, int descriptorIndex) { this.clzFile = clzFile; @@ -93,4 +96,8 @@ public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ return m ; } + + public ByteCodeCommand[] getCmds() { + return this.getCodeAttr().getCmds(); + } } diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/print/ClassFilePrinter.java b/liuxin/mini-jvm/src/com/coderising/jvm/print/ClassFilePrinter.java new file mode 100644 index 0000000000..d1579dba28 --- /dev/null +++ b/liuxin/mini-jvm/src/com/coderising/jvm/print/ClassFilePrinter.java @@ -0,0 +1,54 @@ +package com.coderising.jvm.print; + +import com.coderising.jvm.clz.ClassFile; +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.StringInfo; +import com.coderising.jvm.constant.UTF8Info; +import com.coderising.jvm.loader.ClassFileLoader; + +public class ClassFilePrinter { + ClassFile clzFile = null; + public ClassFilePrinter(ClassFile clzFile){ + this.clzFile = clzFile; + } + + public void print(){ + + if(clzFile.getAccessFlag().isPublicClass()){ + System.out.println("Access flag : public "); + } + System.out.println("Class Name:"+ clzFile.getClassName()); + + System.out.println("Super Class Name:"+ clzFile.getSuperClassName()); + + System.out.println("minor version:" + clzFile.getMinorVersion()); + + System.out.println("major version:" + clzFile.getMinorVersion()); + + ConstantPoolPrinter cnstPoolPrinter = new ConstantPoolPrinter(clzFile.getConstantPool()); + cnstPoolPrinter.print(); + + + + + } + + public static void main(String[] args){ + String path = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\mini-jvm\\bin"; + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path); + String className = "com.coderising.jvm.test.EmployeeV1"; + + ClassFile clzFile = loader.loadClass(className); + + ClassFilePrinter printer = new ClassFilePrinter(clzFile); + + printer.print(); + } +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/print/ConstantPoolPrinter.java b/liuxin/mini-jvm/src/com/coderising/jvm/print/ConstantPoolPrinter.java new file mode 100644 index 0000000000..923c2270c5 --- /dev/null +++ b/liuxin/mini-jvm/src/com/coderising/jvm/print/ConstantPoolPrinter.java @@ -0,0 +1,83 @@ +package com.coderising.jvm.print; + +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.StringInfo; +import com.coderising.jvm.constant.UTF8Info; + +public class ConstantPoolPrinter { + ConstantPool pool; + ConstantPoolPrinter(ConstantPool pool){ + this.pool = pool; + } + public void print(){ + + System.out.println("Constant Pool:"); + + ConstantInfo.Visitor visitor = new ConstantInfo.Visitor() { + + @Override + public void visitString(StringInfo info) { + StringBuilder buffer = new StringBuilder(); + buffer.append("String #").append(info.getIndex()); + System.out.println(buffer); + + } + + @Override + public void visitNameAndType(NameAndTypeInfo info) { + StringBuilder buffer = new StringBuilder(); + buffer.append("NameAndType #").append(info.getIndex1()).append(":#") + .append(info.getIndex2()); + System.out.println(buffer); + + } + + @Override + public void visitMethodRef(MethodRefInfo info) { + StringBuilder buffer = new StringBuilder(); + buffer.append("MethodRef #").append(info.getClassInfoIndex()).append(".#") + .append(info.getNameAndTypeIndex()); + System.out.println(buffer); + + } + + @Override + public void visitFieldRef(FieldRefInfo info) { + StringBuilder buffer = new StringBuilder(); + buffer.append("FieldRef #").append(info.getClassInfoIndex()).append(".#") + .append(info.getNameAndTypeIndex()); + System.out.println(buffer); + + } + + @Override + public void visitClassInfo(ClassInfo info) { + StringBuilder buffer = new StringBuilder(); + buffer.append("Class #").append(info.getUtf8Index()) + .append(" ").append(info.getClassName()); + + System.out.println(buffer); + + } + + @Override + public void visistUTF8(UTF8Info info) { + StringBuilder buffer = new StringBuilder(); + buffer.append("UTF8 ").append(info.getValue()); + System.out.println(buffer); + + } + }; + + for(int i=1; i<=pool.getSize(); i++){ + ConstantInfo constantInfo = pool.getConstantInfo(i); + System.out.print("#"+i+"="); + constantInfo.accept(visitor); + } + } +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/print/ConstantPoolPrinterBad.java b/liuxin/mini-jvm/src/com/coderising/jvm/print/ConstantPoolPrinterBad.java new file mode 100644 index 0000000000..c674b23e00 --- /dev/null +++ b/liuxin/mini-jvm/src/com/coderising/jvm/print/ConstantPoolPrinterBad.java @@ -0,0 +1,40 @@ +package com.coderising.jvm.print; + +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantInfo; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.UTF8Info; + +public class ConstantPoolPrinterBad { + ConstantPool pool; + ConstantPoolPrinterBad(ConstantPool pool){ + this.pool = pool; + } + public void print(){ + + System.out.println("Constant Pool:"); + + for(int i=1; i<=pool.getSize(); i++){ + ConstantInfo cnstInfo = pool.getConstantInfo(i); + + System.out.print("#"+i+"="); + if(cnstInfo instanceof ClassInfo){ + ClassInfo info = (ClassInfo)cnstInfo; + // Class #2 com/coderising/jvm/test/EmployeeV1 + StringBuilder buffer = new StringBuilder(); + buffer.append("Class #").append(info.getUtf8Index()) + .append(" ").append(info.getClassName()); + + System.out.println(buffer); + } + if(cnstInfo instanceof UTF8Info){ + //UTF8 com/coderising/jvm/test/EmployeeV1 + UTF8Info info = (UTF8Info)cnstInfo; + StringBuilder buffer = new StringBuilder(); + buffer.append("UTF8 ").append(info.getValue()); + System.out.println(buffer); + } + //其他的if else + } + } +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java b/liuxin/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java index c29ff5181f..b26dd457d8 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java +++ b/liuxin/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -9,6 +9,10 @@ import com.coderising.jvm.clz.ClassFile; import com.coderising.jvm.clz.ClassIndex; +import com.coderising.jvm.cmd.BiPushCmd; +import com.coderising.jvm.cmd.ByteCodeCommand; +import com.coderising.jvm.cmd.OneOperandCmd; +import com.coderising.jvm.cmd.TwoOperandCmd; import com.coderising.jvm.constant.ClassInfo; import com.coderising.jvm.constant.ConstantPool; import com.coderising.jvm.constant.MethodRefInfo; @@ -37,7 +41,7 @@ public class ClassFileloaderTest { String className = "com.coderising.jvm.test.EmployeeV1"; clzFile = loader.loadClass(className); - clzFile.print(); + } @@ -272,6 +276,79 @@ private void assertMethodEquals(ConstantPool pool,Method m , String expectedName Assert.assertEquals(expectedDesc, methodDesc); Assert.assertEquals(expectedCode, code); } + + @Test + public void testByteCodeCommand(){ + { + Method initMethod = this.clzFile.getMethod("<init>", "(Ljava/lang/String;I)V"); + ByteCodeCommand [] cmds = initMethod.getCmds(); + + assertOpCodeEquals("0: aload_0", cmds[0]); + assertOpCodeEquals("1: invokespecial #12", cmds[1]); + assertOpCodeEquals("4: aload_0", cmds[2]); + assertOpCodeEquals("5: aload_1", cmds[3]); + assertOpCodeEquals("6: putfield #15", cmds[4]); + assertOpCodeEquals("9: aload_0", cmds[5]); + assertOpCodeEquals("10: iload_2", cmds[6]); + assertOpCodeEquals("11: putfield #17", cmds[7]); + assertOpCodeEquals("14: return", cmds[8]); + } + + { + Method setNameMethod = this.clzFile.getMethod("setName", "(Ljava/lang/String;)V"); + ByteCodeCommand [] cmds = setNameMethod.getCmds(); + + assertOpCodeEquals("0: aload_0", cmds[0]); + assertOpCodeEquals("1: aload_1", cmds[1]); + assertOpCodeEquals("2: putfield #15", cmds[2]); + assertOpCodeEquals("5: return", cmds[3]); + + } + + { + Method sayHelloMethod = this.clzFile.getMethod("sayHello", "()V"); + ByteCodeCommand [] cmds = sayHelloMethod.getCmds(); + + assertOpCodeEquals("0: getstatic #28", cmds[0]); + assertOpCodeEquals("3: ldc #34", cmds[1]); + assertOpCodeEquals("5: invokevirtual #36", cmds[2]); + assertOpCodeEquals("8: return", cmds[3]); + + } + + { + Method mainMethod = this.clzFile.getMainMethod(); + + ByteCodeCommand [] cmds = mainMethod.getCmds(); + + assertOpCodeEquals("0: new #1", cmds[0]); + assertOpCodeEquals("3: dup", cmds[1]); + assertOpCodeEquals("4: ldc #43", cmds[2]); + assertOpCodeEquals("6: bipush 29", cmds[3]); + assertOpCodeEquals("8: invokespecial #45", cmds[4]); + assertOpCodeEquals("11: astore_1", cmds[5]); + assertOpCodeEquals("12: aload_1", cmds[6]); + assertOpCodeEquals("13: invokevirtual #47", cmds[7]); + assertOpCodeEquals("16: return", cmds[8]); + } + + } + private void assertOpCodeEquals(String expected, ByteCodeCommand cmd){ + + String acctual = cmd.getOffset()+": "+cmd.getReadableCodeText(); + + if(cmd instanceof OneOperandCmd){ + if(cmd instanceof BiPushCmd){ + acctual += " " + ((OneOperandCmd)cmd).getOperand(); + } else{ + acctual += " #" + ((OneOperandCmd)cmd).getOperand(); + } + } + if(cmd instanceof TwoOperandCmd){ + acctual += " #" + ((TwoOperandCmd)cmd).getIndex(); + } + Assert.assertEquals(expected, acctual); + } } From 47ceb3a7a335b3c3dfe73a5a554ab615b9dd813a Mon Sep 17 00:00:00 2001 From: onlyliuxin <14703250@qq.com> Date: Mon, 17 Apr 2017 10:07:45 +0800 Subject: [PATCH 279/287] remove file --- LLP/task1.html | 71 -------------------------------------------------- 1 file changed, 71 deletions(-) delete mode 100644 LLP/task1.html diff --git a/LLP/task1.html b/LLP/task1.html deleted file mode 100644 index 9b3352fa07..0000000000 --- a/LLP/task1.html +++ /dev/null @@ -1,71 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title>task1</title> -</head> -<body> - <h1>第一个任务</h1> - <h2>第一个任务</h2> - <h3>第一个任务</h3> - <h4>第一个任务</h4> - <h5>第一个任务</h5> - <h6>第一个任务</h6> - <p>这里就是一段文段,可以长也可以短,它还具有属性</p> - <em>备注一下</em> - <u>再来个下划线吧</u> - <ul> - <li>第一个</li> - <li>第二个</li> - <li>第三个</li> - <li>第四个</li> - </ul> - <ol> - <li>第1个</li> - <li>第2个</li> - <li>第3个</li> - <li>第4个</li> - </ol> - <strong>再来个强壮一下吧</strong> - <form> - <label>姓名:</label> - <input type="text" name="" /> - <label>普通按钮:</label> - <input type="button" value="确定" name="" /> - <label>提交按钮:</label> - <input type="submit" name="" /> - <label>重置:</label> - <input type="reset" name="" /> - <label>密码:</label> - <input type="password" name="" /> - <label>单选按钮:</label> - <input type="radio" name="" /> - <label>复选框:</label> - <input type="checkbox" name="" /> - <label>插入图片:</label> - <input type="image" name="" src="https://gss0.baidu.com/9rkZbzqaKgQUohGko9WTAnF6hhy/mms-res/fed/ife/ife_tutor/htmlcss.ec85cad580b3bfce.jpg" /> - <label>上传按钮:</label> - <input type="file" name="" /> - - - </form> - <form> - <label>选择你所在的城市</label> - <select> - <option>广西壮族自治区</option> - <option>2222</option> - <option>3333</option> - <option>4444</option> - <option>5555</option> - - </select> - <label>写下你的留言:</label> - <textarea rows="5" cols="80"></textarea> - - </form> - <dl> - <dt>可以作为标题,也可以放图片</dt> - <dd>放详细介绍</dd> - <dd>放详细介绍</dd> - </dl> -</body> -</html> \ No newline at end of file From a1e97c15840f3491895ccfc555c12f98b0f6d920 Mon Sep 17 00:00:00 2001 From: onlyliuxin <14703250@qq.com> Date: Mon, 17 Apr 2017 10:25:09 +0800 Subject: [PATCH 280/287] =?UTF-8?q?=E6=8A=8A=E4=BD=9C=E4=B8=9A=E5=92=8C?= =?UTF-8?q?=E7=AD=94=E6=A1=88=E5=88=86=E5=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../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 .../src/com/coderising/litestruts/Struts.java | 0 .../com/coderising/litestruts/StrutsTest.java | 0 .../src/com/coderising/litestruts/View.java | 0 .../src/com/coding/basic/BinaryTreeNode.java | 0 .../src/com/coding/basic/Iterator.java | 0 .../src/com/coding/basic/List.java | 0 .../src/com/coding/basic/array/ArrayList.java | 0 .../src/com/coding/basic/array/ArrayUtil.java | 0 .../coding/basic/linklist/LRUPageFrame.java | 0 .../basic/linklist/LRUPageFrameTest.java | 0 .../com/coding/basic/linklist/LinkedList.java | 0 .../com/coding/basic/queue/CircleQueue.java | 10 +- .../src/com/coding/basic/queue/Josephus.java | 66 ++-- .../com/coding/basic/queue/JosephusTest.java | 54 +-- .../src/com/coding/basic/queue/Queue.java | 122 +++---- .../basic/queue/QueueWithTwoStacks.java | 108 +++--- .../src/com/coding/basic/stack/Stack.java | 48 +-- .../src/com/coding/basic/stack/StackUtil.java | 336 +++++++++--------- .../com/coding/basic/stack/StackUtilTest.java | 172 ++++----- .../coding/basic/stack/expr/InfixExpr.java | 156 ++++---- .../basic/stack/expr/InfixExprTest.java | 104 +++--- .../basic/stack/expr/InfixToPostfix.java | 104 +++--- .../coding/basic/stack/expr/PostfixExpr.java | 92 ++--- .../basic/stack/expr/PostfixExprTest.java | 82 ++--- .../coding/basic/stack/expr/PrefixExpr.java | 104 +++--- .../basic/stack/expr/PrefixExprTest.java | 90 ++--- .../com/coding/basic/stack/expr/Token.java | 98 ++--- .../coding/basic/stack/expr/TokenParser.java | 114 +++--- .../basic/stack/expr/TokenParserTest.java | 82 ++--- .../coderising/download/DownloadThread.java | 20 ++ .../coderising/download/FileDownloader.java | 73 ++++ .../download/FileDownloaderTest.java | 59 +++ .../coderising/download/api/Connection.java | 23 ++ .../download/api/ConnectionException.java | 5 + .../download/api/ConnectionManager.java | 10 + .../download/api/DownloadListener.java | 5 + .../download/impl/ConnectionImpl.java | 27 ++ .../download/impl/ConnectionManagerImpl.java | 15 + .../coderising/litestruts/LoginAction.java | 39 ++ .../src/com/coderising/litestruts/Struts.java | 34 ++ .../com/coderising/litestruts/StrutsTest.java | 43 +++ .../src/com/coderising/litestruts/View.java | 23 ++ .../src/com/coding/basic/BinaryTreeNode.java | 32 ++ .../src/com/coding/basic/Iterator.java | 7 + .../assignment/src/com/coding/basic/List.java | 9 + .../src/com/coding/basic/array/ArrayList.java | 35 ++ .../src/com/coding/basic/array/ArrayUtil.java | 96 +++++ .../coding/basic/linklist/LRUPageFrame.java | 57 +++ .../basic/linklist/LRUPageFrameTest.java | 34 ++ .../com/coding/basic/linklist/LinkedList.java | 125 +++++++ .../com/coding/basic/queue/CircleQueue.java | 5 + .../src/com/coding/basic/queue/Josephus.java | 19 + .../com/coding/basic/queue/JosephusTest.java | 27 ++ .../src/com/coding/basic/queue/Queue.java | 61 ++++ .../basic/queue/QueueWithTwoStacks.java | 40 +++ .../src/com/coding/basic/stack/Stack.java | 24 ++ .../src/com/coding/basic/stack/StackUtil.java | 48 +++ .../com/coding/basic/stack/StackUtilTest.java | 65 ++++ .../coding/basic/stack/expr/InfixExpr.java | 15 + .../basic/stack/expr/InfixExprTest.java | 52 +++ .../basic/stack/expr/InfixToPostfix.java | 14 + .../coding/basic/stack/expr/PostfixExpr.java | 18 + .../basic/stack/expr/PostfixExprTest.java | 41 +++ .../coding/basic/stack/expr/PrefixExpr.java | 18 + .../basic/stack/expr/PrefixExprTest.java | 45 +++ .../com/coding/basic/stack/expr/Token.java | 50 +++ .../coding/basic/stack/expr/TokenParser.java | 57 +++ .../basic/stack/expr/TokenParserTest.java | 41 +++ 78 files changed, 2382 insertions(+), 971 deletions(-) rename liuxin/data-structure/{ => answer}/src/com/coderising/download/DownloadThread.java (100%) rename liuxin/data-structure/{ => answer}/src/com/coderising/download/FileDownloader.java (100%) rename liuxin/data-structure/{ => answer}/src/com/coderising/download/FileDownloaderTest.java (100%) rename liuxin/data-structure/{ => answer}/src/com/coderising/download/api/Connection.java (100%) rename liuxin/data-structure/{ => answer}/src/com/coderising/download/api/ConnectionException.java (100%) rename liuxin/data-structure/{ => answer}/src/com/coderising/download/api/ConnectionManager.java (100%) rename liuxin/data-structure/{ => answer}/src/com/coderising/download/api/DownloadListener.java (100%) rename liuxin/data-structure/{ => answer}/src/com/coderising/download/impl/ConnectionImpl.java (100%) rename liuxin/data-structure/{ => answer}/src/com/coderising/download/impl/ConnectionManagerImpl.java (100%) rename liuxin/data-structure/{ => answer}/src/com/coderising/litestruts/LoginAction.java (100%) rename liuxin/data-structure/{ => answer}/src/com/coderising/litestruts/Struts.java (100%) rename liuxin/data-structure/{ => answer}/src/com/coderising/litestruts/StrutsTest.java (100%) rename liuxin/data-structure/{ => answer}/src/com/coderising/litestruts/View.java (100%) rename liuxin/data-structure/{ => answer}/src/com/coding/basic/BinaryTreeNode.java (100%) rename liuxin/data-structure/{ => answer}/src/com/coding/basic/Iterator.java (100%) rename liuxin/data-structure/{ => answer}/src/com/coding/basic/List.java (100%) rename liuxin/data-structure/{ => answer}/src/com/coding/basic/array/ArrayList.java (100%) rename liuxin/data-structure/{ => answer}/src/com/coding/basic/array/ArrayUtil.java (100%) rename liuxin/data-structure/{ => answer}/src/com/coding/basic/linklist/LRUPageFrame.java (100%) rename liuxin/data-structure/{ => answer}/src/com/coding/basic/linklist/LRUPageFrameTest.java (100%) rename liuxin/data-structure/{ => answer}/src/com/coding/basic/linklist/LinkedList.java (100%) rename liuxin/data-structure/{ => answer}/src/com/coding/basic/queue/CircleQueue.java (92%) rename liuxin/data-structure/{ => answer}/src/com/coding/basic/queue/Josephus.java (96%) rename liuxin/data-structure/{ => answer}/src/com/coding/basic/queue/JosephusTest.java (93%) rename liuxin/data-structure/{ => answer}/src/com/coding/basic/queue/Queue.java (94%) rename liuxin/data-structure/{ => answer}/src/com/coding/basic/queue/QueueWithTwoStacks.java (94%) rename liuxin/data-structure/{ => answer}/src/com/coding/basic/stack/Stack.java (93%) rename liuxin/data-structure/{ => answer}/src/com/coding/basic/stack/StackUtil.java (95%) rename liuxin/data-structure/{ => answer}/src/com/coding/basic/stack/StackUtilTest.java (95%) rename liuxin/data-structure/{ => answer}/src/com/coding/basic/stack/expr/InfixExpr.java (95%) rename liuxin/data-structure/{ => answer}/src/com/coding/basic/stack/expr/InfixExprTest.java (95%) rename liuxin/data-structure/{ => answer}/src/com/coding/basic/stack/expr/InfixToPostfix.java (95%) rename liuxin/data-structure/{ => answer}/src/com/coding/basic/stack/expr/PostfixExpr.java (95%) rename liuxin/data-structure/{ => answer}/src/com/coding/basic/stack/expr/PostfixExprTest.java (94%) rename liuxin/data-structure/{ => answer}/src/com/coding/basic/stack/expr/PrefixExpr.java (95%) rename liuxin/data-structure/{ => answer}/src/com/coding/basic/stack/expr/PrefixExprTest.java (95%) rename liuxin/data-structure/{ => answer}/src/com/coding/basic/stack/expr/Token.java (95%) rename liuxin/data-structure/{ => answer}/src/com/coding/basic/stack/expr/TokenParser.java (94%) rename liuxin/data-structure/{ => answer}/src/com/coding/basic/stack/expr/TokenParserTest.java (96%) create mode 100644 liuxin/data-structure/assignment/src/com/coderising/download/DownloadThread.java create mode 100644 liuxin/data-structure/assignment/src/com/coderising/download/FileDownloader.java create mode 100644 liuxin/data-structure/assignment/src/com/coderising/download/FileDownloaderTest.java create mode 100644 liuxin/data-structure/assignment/src/com/coderising/download/api/Connection.java create mode 100644 liuxin/data-structure/assignment/src/com/coderising/download/api/ConnectionException.java create mode 100644 liuxin/data-structure/assignment/src/com/coderising/download/api/ConnectionManager.java create mode 100644 liuxin/data-structure/assignment/src/com/coderising/download/api/DownloadListener.java create mode 100644 liuxin/data-structure/assignment/src/com/coderising/download/impl/ConnectionImpl.java create mode 100644 liuxin/data-structure/assignment/src/com/coderising/download/impl/ConnectionManagerImpl.java create mode 100644 liuxin/data-structure/assignment/src/com/coderising/litestruts/LoginAction.java create mode 100644 liuxin/data-structure/assignment/src/com/coderising/litestruts/Struts.java create mode 100644 liuxin/data-structure/assignment/src/com/coderising/litestruts/StrutsTest.java create mode 100644 liuxin/data-structure/assignment/src/com/coderising/litestruts/View.java create mode 100644 liuxin/data-structure/assignment/src/com/coding/basic/BinaryTreeNode.java create mode 100644 liuxin/data-structure/assignment/src/com/coding/basic/Iterator.java create mode 100644 liuxin/data-structure/assignment/src/com/coding/basic/List.java create mode 100644 liuxin/data-structure/assignment/src/com/coding/basic/array/ArrayList.java create mode 100644 liuxin/data-structure/assignment/src/com/coding/basic/array/ArrayUtil.java create mode 100644 liuxin/data-structure/assignment/src/com/coding/basic/linklist/LRUPageFrame.java create mode 100644 liuxin/data-structure/assignment/src/com/coding/basic/linklist/LRUPageFrameTest.java create mode 100644 liuxin/data-structure/assignment/src/com/coding/basic/linklist/LinkedList.java create mode 100644 liuxin/data-structure/assignment/src/com/coding/basic/queue/CircleQueue.java create mode 100644 liuxin/data-structure/assignment/src/com/coding/basic/queue/Josephus.java create mode 100644 liuxin/data-structure/assignment/src/com/coding/basic/queue/JosephusTest.java create mode 100644 liuxin/data-structure/assignment/src/com/coding/basic/queue/Queue.java create mode 100644 liuxin/data-structure/assignment/src/com/coding/basic/queue/QueueWithTwoStacks.java create mode 100644 liuxin/data-structure/assignment/src/com/coding/basic/stack/Stack.java create mode 100644 liuxin/data-structure/assignment/src/com/coding/basic/stack/StackUtil.java create mode 100644 liuxin/data-structure/assignment/src/com/coding/basic/stack/StackUtilTest.java create mode 100644 liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/InfixExpr.java create mode 100644 liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/InfixExprTest.java create mode 100644 liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/InfixToPostfix.java create mode 100644 liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/PostfixExpr.java create mode 100644 liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/PostfixExprTest.java create mode 100644 liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/PrefixExpr.java create mode 100644 liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/PrefixExprTest.java create mode 100644 liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/Token.java create mode 100644 liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/TokenParser.java create mode 100644 liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/TokenParserTest.java diff --git a/liuxin/data-structure/src/com/coderising/download/DownloadThread.java b/liuxin/data-structure/answer/src/com/coderising/download/DownloadThread.java similarity index 100% rename from liuxin/data-structure/src/com/coderising/download/DownloadThread.java rename to liuxin/data-structure/answer/src/com/coderising/download/DownloadThread.java diff --git a/liuxin/data-structure/src/com/coderising/download/FileDownloader.java b/liuxin/data-structure/answer/src/com/coderising/download/FileDownloader.java similarity index 100% rename from liuxin/data-structure/src/com/coderising/download/FileDownloader.java rename to liuxin/data-structure/answer/src/com/coderising/download/FileDownloader.java diff --git a/liuxin/data-structure/src/com/coderising/download/FileDownloaderTest.java b/liuxin/data-structure/answer/src/com/coderising/download/FileDownloaderTest.java similarity index 100% rename from liuxin/data-structure/src/com/coderising/download/FileDownloaderTest.java rename to liuxin/data-structure/answer/src/com/coderising/download/FileDownloaderTest.java diff --git a/liuxin/data-structure/src/com/coderising/download/api/Connection.java b/liuxin/data-structure/answer/src/com/coderising/download/api/Connection.java similarity index 100% rename from liuxin/data-structure/src/com/coderising/download/api/Connection.java rename to liuxin/data-structure/answer/src/com/coderising/download/api/Connection.java diff --git a/liuxin/data-structure/src/com/coderising/download/api/ConnectionException.java b/liuxin/data-structure/answer/src/com/coderising/download/api/ConnectionException.java similarity index 100% rename from liuxin/data-structure/src/com/coderising/download/api/ConnectionException.java rename to liuxin/data-structure/answer/src/com/coderising/download/api/ConnectionException.java diff --git a/liuxin/data-structure/src/com/coderising/download/api/ConnectionManager.java b/liuxin/data-structure/answer/src/com/coderising/download/api/ConnectionManager.java similarity index 100% rename from liuxin/data-structure/src/com/coderising/download/api/ConnectionManager.java rename to liuxin/data-structure/answer/src/com/coderising/download/api/ConnectionManager.java diff --git a/liuxin/data-structure/src/com/coderising/download/api/DownloadListener.java b/liuxin/data-structure/answer/src/com/coderising/download/api/DownloadListener.java similarity index 100% rename from liuxin/data-structure/src/com/coderising/download/api/DownloadListener.java rename to liuxin/data-structure/answer/src/com/coderising/download/api/DownloadListener.java diff --git a/liuxin/data-structure/src/com/coderising/download/impl/ConnectionImpl.java b/liuxin/data-structure/answer/src/com/coderising/download/impl/ConnectionImpl.java similarity index 100% rename from liuxin/data-structure/src/com/coderising/download/impl/ConnectionImpl.java rename to liuxin/data-structure/answer/src/com/coderising/download/impl/ConnectionImpl.java diff --git a/liuxin/data-structure/src/com/coderising/download/impl/ConnectionManagerImpl.java b/liuxin/data-structure/answer/src/com/coderising/download/impl/ConnectionManagerImpl.java similarity index 100% rename from liuxin/data-structure/src/com/coderising/download/impl/ConnectionManagerImpl.java rename to liuxin/data-structure/answer/src/com/coderising/download/impl/ConnectionManagerImpl.java diff --git a/liuxin/data-structure/src/com/coderising/litestruts/LoginAction.java b/liuxin/data-structure/answer/src/com/coderising/litestruts/LoginAction.java similarity index 100% rename from liuxin/data-structure/src/com/coderising/litestruts/LoginAction.java rename to liuxin/data-structure/answer/src/com/coderising/litestruts/LoginAction.java diff --git a/liuxin/data-structure/src/com/coderising/litestruts/Struts.java b/liuxin/data-structure/answer/src/com/coderising/litestruts/Struts.java similarity index 100% rename from liuxin/data-structure/src/com/coderising/litestruts/Struts.java rename to liuxin/data-structure/answer/src/com/coderising/litestruts/Struts.java diff --git a/liuxin/data-structure/src/com/coderising/litestruts/StrutsTest.java b/liuxin/data-structure/answer/src/com/coderising/litestruts/StrutsTest.java similarity index 100% rename from liuxin/data-structure/src/com/coderising/litestruts/StrutsTest.java rename to liuxin/data-structure/answer/src/com/coderising/litestruts/StrutsTest.java diff --git a/liuxin/data-structure/src/com/coderising/litestruts/View.java b/liuxin/data-structure/answer/src/com/coderising/litestruts/View.java similarity index 100% rename from liuxin/data-structure/src/com/coderising/litestruts/View.java rename to liuxin/data-structure/answer/src/com/coderising/litestruts/View.java diff --git a/liuxin/data-structure/src/com/coding/basic/BinaryTreeNode.java b/liuxin/data-structure/answer/src/com/coding/basic/BinaryTreeNode.java similarity index 100% rename from liuxin/data-structure/src/com/coding/basic/BinaryTreeNode.java rename to liuxin/data-structure/answer/src/com/coding/basic/BinaryTreeNode.java diff --git a/liuxin/data-structure/src/com/coding/basic/Iterator.java b/liuxin/data-structure/answer/src/com/coding/basic/Iterator.java similarity index 100% rename from liuxin/data-structure/src/com/coding/basic/Iterator.java rename to liuxin/data-structure/answer/src/com/coding/basic/Iterator.java diff --git a/liuxin/data-structure/src/com/coding/basic/List.java b/liuxin/data-structure/answer/src/com/coding/basic/List.java similarity index 100% rename from liuxin/data-structure/src/com/coding/basic/List.java rename to liuxin/data-structure/answer/src/com/coding/basic/List.java diff --git a/liuxin/data-structure/src/com/coding/basic/array/ArrayList.java b/liuxin/data-structure/answer/src/com/coding/basic/array/ArrayList.java similarity index 100% rename from liuxin/data-structure/src/com/coding/basic/array/ArrayList.java rename to liuxin/data-structure/answer/src/com/coding/basic/array/ArrayList.java diff --git a/liuxin/data-structure/src/com/coding/basic/array/ArrayUtil.java b/liuxin/data-structure/answer/src/com/coding/basic/array/ArrayUtil.java similarity index 100% rename from liuxin/data-structure/src/com/coding/basic/array/ArrayUtil.java rename to liuxin/data-structure/answer/src/com/coding/basic/array/ArrayUtil.java diff --git a/liuxin/data-structure/src/com/coding/basic/linklist/LRUPageFrame.java b/liuxin/data-structure/answer/src/com/coding/basic/linklist/LRUPageFrame.java similarity index 100% rename from liuxin/data-structure/src/com/coding/basic/linklist/LRUPageFrame.java rename to liuxin/data-structure/answer/src/com/coding/basic/linklist/LRUPageFrame.java diff --git a/liuxin/data-structure/src/com/coding/basic/linklist/LRUPageFrameTest.java b/liuxin/data-structure/answer/src/com/coding/basic/linklist/LRUPageFrameTest.java similarity index 100% rename from liuxin/data-structure/src/com/coding/basic/linklist/LRUPageFrameTest.java rename to liuxin/data-structure/answer/src/com/coding/basic/linklist/LRUPageFrameTest.java diff --git a/liuxin/data-structure/src/com/coding/basic/linklist/LinkedList.java b/liuxin/data-structure/answer/src/com/coding/basic/linklist/LinkedList.java similarity index 100% rename from liuxin/data-structure/src/com/coding/basic/linklist/LinkedList.java rename to liuxin/data-structure/answer/src/com/coding/basic/linklist/LinkedList.java diff --git a/liuxin/data-structure/src/com/coding/basic/queue/CircleQueue.java b/liuxin/data-structure/answer/src/com/coding/basic/queue/CircleQueue.java similarity index 92% rename from liuxin/data-structure/src/com/coding/basic/queue/CircleQueue.java rename to liuxin/data-structure/answer/src/com/coding/basic/queue/CircleQueue.java index ff94d5e21a..1ac659da3d 100644 --- a/liuxin/data-structure/src/com/coding/basic/queue/CircleQueue.java +++ b/liuxin/data-structure/answer/src/com/coding/basic/queue/CircleQueue.java @@ -1,5 +1,5 @@ -package com.coding.basic.queue; - -public class CircleQueue { - -} +package com.coding.basic.queue; + +public class CircleQueue { + +} diff --git a/liuxin/data-structure/src/com/coding/basic/queue/Josephus.java b/liuxin/data-structure/answer/src/com/coding/basic/queue/Josephus.java similarity index 96% rename from liuxin/data-structure/src/com/coding/basic/queue/Josephus.java rename to liuxin/data-structure/answer/src/com/coding/basic/queue/Josephus.java index e42cfd4af2..1f06d9be93 100644 --- a/liuxin/data-structure/src/com/coding/basic/queue/Josephus.java +++ b/liuxin/data-structure/answer/src/com/coding/basic/queue/Josephus.java @@ -1,33 +1,33 @@ -package com.coding.basic.queue; - -import java.util.ArrayList; -import java.util.List; - -/** - * 用Queue来实现Josephus问题 - * 在这个古老的问题当中, N个深陷绝境的人一致同意用这种方式减少生存人数: N个人围成一圈(位置记为0到N-1), 并且从第一个人报数, 报到M的人会被杀死, 知道最后一个人留下来 - * @author liuxin - * - */ -public class Josephus { - - public static List<Integer> execute(int n, int m){ - - Queue<Integer> queue = new Queue<Integer>(); - for (int i = 0; i < n; i++){ - queue.enQueue(i); - } - - List<Integer> result = new ArrayList<Integer>(); - - while (!queue.isEmpty()) { - for (int i = 0; i < m-1; i++){ - queue.enQueue(queue.deQueue()); - } - result.add(queue.deQueue()); - - } - return result; - } - -} +package com.coding.basic.queue; + +import java.util.ArrayList; +import java.util.List; + +/** + * 用Queue来实现Josephus问题 + * 在这个古老的问题当中, N个深陷绝境的人一致同意用这种方式减少生存人数: N个人围成一圈(位置记为0到N-1), 并且从第一个人报数, 报到M的人会被杀死, 知道最后一个人留下来 + * @author liuxin + * + */ +public class Josephus { + + public static List<Integer> execute(int n, int m){ + + Queue<Integer> queue = new Queue<Integer>(); + for (int i = 0; i < n; i++){ + queue.enQueue(i); + } + + List<Integer> result = new ArrayList<Integer>(); + + while (!queue.isEmpty()) { + for (int i = 0; i < m-1; i++){ + queue.enQueue(queue.deQueue()); + } + result.add(queue.deQueue()); + + } + return result; + } + +} diff --git a/liuxin/data-structure/src/com/coding/basic/queue/JosephusTest.java b/liuxin/data-structure/answer/src/com/coding/basic/queue/JosephusTest.java similarity index 93% rename from liuxin/data-structure/src/com/coding/basic/queue/JosephusTest.java rename to liuxin/data-structure/answer/src/com/coding/basic/queue/JosephusTest.java index 7f0f2a9078..7d90318b51 100644 --- a/liuxin/data-structure/src/com/coding/basic/queue/JosephusTest.java +++ b/liuxin/data-structure/answer/src/com/coding/basic/queue/JosephusTest.java @@ -1,27 +1,27 @@ -package com.coding.basic.queue; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - - - -public class JosephusTest { - - @Before - public void setUp() throws Exception { - } - - @After - public void tearDown() throws Exception { - } - - @Test - public void testExecute() { - - Assert.assertEquals("[1, 3, 5, 0, 4, 2, 6]", Josephus.execute(7, 2).toString()); - - } - -} +package com.coding.basic.queue; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + + +public class JosephusTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testExecute() { + + Assert.assertEquals("[1, 3, 5, 0, 4, 2, 6]", Josephus.execute(7, 2).toString()); + + } + +} diff --git a/liuxin/data-structure/src/com/coding/basic/queue/Queue.java b/liuxin/data-structure/answer/src/com/coding/basic/queue/Queue.java similarity index 94% rename from liuxin/data-structure/src/com/coding/basic/queue/Queue.java rename to liuxin/data-structure/answer/src/com/coding/basic/queue/Queue.java index 1430d84f7c..c4c4b7325e 100644 --- a/liuxin/data-structure/src/com/coding/basic/queue/Queue.java +++ b/liuxin/data-structure/answer/src/com/coding/basic/queue/Queue.java @@ -1,61 +1,61 @@ -package com.coding.basic.queue; - -import java.util.NoSuchElementException; - -public class Queue<E> { - private Node<E> first; - private Node<E> last; - private int size; - - - private static class Node<E> { - private E item; - private Node<E> next; - } - - - public Queue() { - first = null; - last = null; - size = 0; - } - - - public boolean isEmpty() { - return first == null; - } - - public int size() { - return size; - } - - - - public void enQueue(E data) { - Node<E> oldlast = last; - last = new Node<E>(); - last.item = data; - last.next = null; - if (isEmpty()) { - first = last; - } - else{ - oldlast.next = last; - } - size++; - } - - public E deQueue() { - if (isEmpty()) { - throw new NoSuchElementException("Queue underflow"); - } - E item = first.item; - first = first.next; - size--; - if (isEmpty()) { - last = null; - } - return item; - } - -} +package com.coding.basic.queue; + +import java.util.NoSuchElementException; + +public class Queue<E> { + private Node<E> first; + private Node<E> last; + private int size; + + + private static class Node<E> { + private E item; + private Node<E> next; + } + + + public Queue() { + first = null; + last = null; + size = 0; + } + + + public boolean isEmpty() { + return first == null; + } + + public int size() { + return size; + } + + + + public void enQueue(E data) { + Node<E> oldlast = last; + last = new Node<E>(); + last.item = data; + last.next = null; + if (isEmpty()) { + first = last; + } + else{ + oldlast.next = last; + } + size++; + } + + public E deQueue() { + if (isEmpty()) { + throw new NoSuchElementException("Queue underflow"); + } + E item = first.item; + first = first.next; + size--; + if (isEmpty()) { + last = null; + } + return item; + } + +} diff --git a/liuxin/data-structure/src/com/coding/basic/queue/QueueWithTwoStacks.java b/liuxin/data-structure/answer/src/com/coding/basic/queue/QueueWithTwoStacks.java similarity index 94% rename from liuxin/data-structure/src/com/coding/basic/queue/QueueWithTwoStacks.java rename to liuxin/data-structure/answer/src/com/coding/basic/queue/QueueWithTwoStacks.java index cc895d7358..d986c98bd6 100644 --- a/liuxin/data-structure/src/com/coding/basic/queue/QueueWithTwoStacks.java +++ b/liuxin/data-structure/answer/src/com/coding/basic/queue/QueueWithTwoStacks.java @@ -1,54 +1,54 @@ -package com.coding.basic.queue; - -import java.util.NoSuchElementException; -import java.util.Stack; - -public class QueueWithTwoStacks<E> { - private Stack<E> stack1; - private Stack<E> stack2; - - - public QueueWithTwoStacks() { - stack1 = new Stack<E>(); - stack2 = new Stack<E>(); - } - - - private void moveStack1ToStack2() { - while (!stack1.isEmpty()){ - stack2.push(stack1.pop()); - } - - } - - - public boolean isEmpty() { - return stack1.isEmpty() && stack2.isEmpty(); - } - - - - public int size() { - return stack1.size() + stack2.size(); - } - - - - public void enQueue(E item) { - stack1.push(item); - } - - public E deQueue() { - if (isEmpty()) { - throw new NoSuchElementException("Queue is empty"); - } - if (stack2.isEmpty()) { - moveStack1ToStack2(); - } - - return stack2.pop(); - } - - - } - +package com.coding.basic.queue; + +import java.util.NoSuchElementException; +import java.util.Stack; + +public class QueueWithTwoStacks<E> { + private Stack<E> stack1; + private Stack<E> stack2; + + + public QueueWithTwoStacks() { + stack1 = new Stack<E>(); + stack2 = new Stack<E>(); + } + + + private void moveStack1ToStack2() { + while (!stack1.isEmpty()){ + stack2.push(stack1.pop()); + } + + } + + + public boolean isEmpty() { + return stack1.isEmpty() && stack2.isEmpty(); + } + + + + public int size() { + return stack1.size() + stack2.size(); + } + + + + public void enQueue(E item) { + stack1.push(item); + } + + public E deQueue() { + if (isEmpty()) { + throw new NoSuchElementException("Queue is empty"); + } + if (stack2.isEmpty()) { + moveStack1ToStack2(); + } + + return stack2.pop(); + } + + + } + diff --git a/liuxin/data-structure/src/com/coding/basic/stack/Stack.java b/liuxin/data-structure/answer/src/com/coding/basic/stack/Stack.java similarity index 93% rename from liuxin/data-structure/src/com/coding/basic/stack/Stack.java rename to liuxin/data-structure/answer/src/com/coding/basic/stack/Stack.java index 4f4b9af52e..fedb243604 100644 --- a/liuxin/data-structure/src/com/coding/basic/stack/Stack.java +++ b/liuxin/data-structure/answer/src/com/coding/basic/stack/Stack.java @@ -1,24 +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; - } -} +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/liuxin/data-structure/src/com/coding/basic/stack/StackUtil.java b/liuxin/data-structure/answer/src/com/coding/basic/stack/StackUtil.java similarity index 95% rename from liuxin/data-structure/src/com/coding/basic/stack/StackUtil.java rename to liuxin/data-structure/answer/src/com/coding/basic/stack/StackUtil.java index 5f4236e875..7c86d22fe7 100644 --- a/liuxin/data-structure/src/com/coding/basic/stack/StackUtil.java +++ b/liuxin/data-structure/answer/src/com/coding/basic/stack/StackUtil.java @@ -1,168 +1,168 @@ -package com.coding.basic.stack; -import java.util.Stack; -public class StackUtil { - - public static void bad_reverse(Stack<Integer> s) { - if(s == null || s.isEmpty()){ - return; - } - Stack<Integer> tmpStack = new Stack(); - while(!s.isEmpty()){ - tmpStack.push(s.pop()); - } - - s = tmpStack; - - } - - - - public static void reverse_247565311(Stack<Integer> s){ - if(s == null || s.isEmpty()) { - return; - } - - int size = s.size(); - Stack<Integer> tmpStack = new Stack<Integer>(); - - for(int i=0;i<size;i++){ - Integer top = s.pop(); - while(s.size()>i){ - tmpStack.push(s.pop()); - } - s.push(top); - while(tmpStack.size()>0){ - s.push(tmpStack.pop()); - } - } - } - - - - /** - * 假设栈中的元素是Integer, 从栈顶到栈底是 : 5,4,3,2,1 调用该方法后, 元素次序变为: 1,2,3,4,5 - * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 - */ - public static void reverse(Stack<Integer> s) { - if(s == null || s.isEmpty()){ - return; - } - - Stack<Integer> tmp = new Stack<Integer>(); - while(!s.isEmpty()){ - tmp.push(s.pop()); - } - while(!tmp.isEmpty()){ - Integer top = tmp.pop(); - addToBottom(s,top); - } - - - } - public static void addToBottom(Stack<Integer> s, Integer value){ - if(s.isEmpty()){ - s.push(value); - } else{ - Integer top = s.pop(); - addToBottom(s,value); - s.push(top); - } - - } - /** - * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 - * - * @param o - */ - public static void remove(Stack s,Object o) { - if(s == null || s.isEmpty()){ - return; - } - Stack tmpStack = new Stack(); - - while(!s.isEmpty()){ - Object value = s.pop(); - if(!value.equals(o)){ - tmpStack.push(value); - } - } - - while(!tmpStack.isEmpty()){ - s.push(tmpStack.pop()); - } - } - - /** - * 从栈顶取得len个元素, 原来的栈中元素保持不变 - * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 - * @param len - * @return - */ - public static Object[] getTop(Stack s,int len) { - - if(s == null || s.isEmpty() || s.size()<len || len <=0 ){ - return null; - } - - Stack tmpStack = new Stack(); - int i = 0; - Object[] result = new Object[len]; - while(!s.isEmpty()){ - Object value = s.pop(); - tmpStack.push(value); - result[i++] = value; - if(i == len){ - break; - } - } - while(!tmpStack.isEmpty()){ - s.push(tmpStack.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){ - - Stack<Character> stack = new Stack(); - for(int i=0;i<s.length();i++){ - char c = s.charAt(i); - - if(c == '(' || c =='[' || c == '{'){ - - stack.push(c); - - } else if( c == ')'){ - - char topChar = stack.pop(); - if(topChar != '('){ - return false; - } - - } else if( c == ']'){ - - char topChar = stack.pop(); - if(topChar != '['){ - return false; - } - - } else if( c == '}'){ - - char topChar = stack.pop(); - if(topChar != '{'){ - return false; - } - - } - } - return stack.size() == 0; - } - - -} +package com.coding.basic.stack; +import java.util.Stack; +public class StackUtil { + + public static void bad_reverse(Stack<Integer> s) { + if(s == null || s.isEmpty()){ + return; + } + Stack<Integer> tmpStack = new Stack(); + while(!s.isEmpty()){ + tmpStack.push(s.pop()); + } + + s = tmpStack; + + } + + + + public static void reverse_247565311(Stack<Integer> s){ + if(s == null || s.isEmpty()) { + return; + } + + int size = s.size(); + Stack<Integer> tmpStack = new Stack<Integer>(); + + for(int i=0;i<size;i++){ + Integer top = s.pop(); + while(s.size()>i){ + tmpStack.push(s.pop()); + } + s.push(top); + while(tmpStack.size()>0){ + s.push(tmpStack.pop()); + } + } + } + + + + /** + * 假设栈中的元素是Integer, 从栈顶到栈底是 : 5,4,3,2,1 调用该方法后, 元素次序变为: 1,2,3,4,5 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + */ + public static void reverse(Stack<Integer> s) { + if(s == null || s.isEmpty()){ + return; + } + + Stack<Integer> tmp = new Stack<Integer>(); + while(!s.isEmpty()){ + tmp.push(s.pop()); + } + while(!tmp.isEmpty()){ + Integer top = tmp.pop(); + addToBottom(s,top); + } + + + } + public static void addToBottom(Stack<Integer> s, Integer value){ + if(s.isEmpty()){ + s.push(value); + } else{ + Integer top = s.pop(); + addToBottom(s,value); + s.push(top); + } + + } + /** + * 删除栈中的某个元素 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * + * @param o + */ + public static void remove(Stack s,Object o) { + if(s == null || s.isEmpty()){ + return; + } + Stack tmpStack = new Stack(); + + while(!s.isEmpty()){ + Object value = s.pop(); + if(!value.equals(o)){ + tmpStack.push(value); + } + } + + while(!tmpStack.isEmpty()){ + s.push(tmpStack.pop()); + } + } + + /** + * 从栈顶取得len个元素, 原来的栈中元素保持不变 + * 注意:只能使用Stack的基本操作,即push,pop,peek,isEmpty, 可以使用另外一个栈来辅助 + * @param len + * @return + */ + public static Object[] getTop(Stack s,int len) { + + if(s == null || s.isEmpty() || s.size()<len || len <=0 ){ + return null; + } + + Stack tmpStack = new Stack(); + int i = 0; + Object[] result = new Object[len]; + while(!s.isEmpty()){ + Object value = s.pop(); + tmpStack.push(value); + result[i++] = value; + if(i == len){ + break; + } + } + while(!tmpStack.isEmpty()){ + s.push(tmpStack.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){ + + Stack<Character> stack = new Stack(); + for(int i=0;i<s.length();i++){ + char c = s.charAt(i); + + if(c == '(' || c =='[' || c == '{'){ + + stack.push(c); + + } else if( c == ')'){ + + char topChar = stack.pop(); + if(topChar != '('){ + return false; + } + + } else if( c == ']'){ + + char topChar = stack.pop(); + if(topChar != '['){ + return false; + } + + } else if( c == '}'){ + + char topChar = stack.pop(); + if(topChar != '{'){ + return false; + } + + } + } + return stack.size() == 0; + } + + +} diff --git a/liuxin/data-structure/src/com/coding/basic/stack/StackUtilTest.java b/liuxin/data-structure/answer/src/com/coding/basic/stack/StackUtilTest.java similarity index 95% rename from liuxin/data-structure/src/com/coding/basic/stack/StackUtilTest.java rename to liuxin/data-structure/answer/src/com/coding/basic/stack/StackUtilTest.java index d70302d7a1..ae0210ff47 100644 --- a/liuxin/data-structure/src/com/coding/basic/stack/StackUtilTest.java +++ b/liuxin/data-structure/answer/src/com/coding/basic/stack/StackUtilTest.java @@ -1,86 +1,86 @@ -package com.coding.basic.stack; - -import java.util.Stack; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -public class StackUtilTest { - - @Before - public void setUp() throws Exception { - } - - @After - public void tearDown() throws Exception { - } - - @Test - public void testAddToBottom() { - Stack<Integer> s = new Stack(); - s.push(1); - s.push(2); - s.push(3); - - StackUtil.addToBottom(s, 0); - - Assert.assertEquals("[0, 1, 2, 3]", s.toString()); - - } - @Test - public void testReverse() { - Stack<Integer> s = new Stack(); - s.push(1); - s.push(2); - s.push(3); - s.push(4); - s.push(5); - Assert.assertEquals("[1, 2, 3, 4, 5]", s.toString()); - StackUtil.reverse(s); - Assert.assertEquals("[5, 4, 3, 2, 1]", s.toString()); - } - @Test - public void testReverse_247565311() { - Stack<Integer> s = new Stack(); - s.push(1); - s.push(2); - s.push(3); - - Assert.assertEquals("[1, 2, 3]", s.toString()); - StackUtil.reverse_247565311(s); - Assert.assertEquals("[3, 2, 1]", s.toString()); - } - @Test - public void testRemove() { - Stack<Integer> s = new Stack(); - s.push(1); - s.push(2); - s.push(3); - StackUtil.remove(s, 2); - Assert.assertEquals("[1, 3]", s.toString()); - } - - @Test - public void testGetTop() { - Stack<Integer> s = new Stack(); - s.push(1); - s.push(2); - s.push(3); - s.push(4); - s.push(5); - { - Object[] values = StackUtil.getTop(s, 3); - Assert.assertEquals(5, values[0]); - Assert.assertEquals(4, values[1]); - Assert.assertEquals(3, values[2]); - } - } - - @Test - public void testIsValidPairs() { - Assert.assertTrue(StackUtil.isValidPairs("([e{d}f])")); - Assert.assertFalse(StackUtil.isValidPairs("([b{x]y})")); - } - -} +package com.coding.basic.stack; + +import java.util.Stack; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +public class StackUtilTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testAddToBottom() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + + StackUtil.addToBottom(s, 0); + + Assert.assertEquals("[0, 1, 2, 3]", s.toString()); + + } + @Test + public void testReverse() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + Assert.assertEquals("[1, 2, 3, 4, 5]", s.toString()); + StackUtil.reverse(s); + Assert.assertEquals("[5, 4, 3, 2, 1]", s.toString()); + } + @Test + public void testReverse_247565311() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + + Assert.assertEquals("[1, 2, 3]", s.toString()); + StackUtil.reverse_247565311(s); + Assert.assertEquals("[3, 2, 1]", s.toString()); + } + @Test + public void testRemove() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + StackUtil.remove(s, 2); + Assert.assertEquals("[1, 3]", s.toString()); + } + + @Test + public void testGetTop() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + { + Object[] values = StackUtil.getTop(s, 3); + Assert.assertEquals(5, values[0]); + Assert.assertEquals(4, values[1]); + Assert.assertEquals(3, values[2]); + } + } + + @Test + public void testIsValidPairs() { + Assert.assertTrue(StackUtil.isValidPairs("([e{d}f])")); + Assert.assertFalse(StackUtil.isValidPairs("([b{x]y})")); + } + +} diff --git a/liuxin/data-structure/src/com/coding/basic/stack/expr/InfixExpr.java b/liuxin/data-structure/answer/src/com/coding/basic/stack/expr/InfixExpr.java similarity index 95% rename from liuxin/data-structure/src/com/coding/basic/stack/expr/InfixExpr.java rename to liuxin/data-structure/answer/src/com/coding/basic/stack/expr/InfixExpr.java index 201b932ce9..08918c490c 100644 --- a/liuxin/data-structure/src/com/coding/basic/stack/expr/InfixExpr.java +++ b/liuxin/data-structure/answer/src/com/coding/basic/stack/expr/InfixExpr.java @@ -1,78 +1,78 @@ -package com.coding.basic.stack.expr; - -import java.util.List; -import java.util.Stack; - - -public class InfixExpr { - String expr = null; - - public InfixExpr(String expr) { - this.expr = expr; - } - - public float evaluate() { - - - TokenParser parser = new TokenParser(); - List<Token> tokens = parser.parse(this.expr); - - - Stack<Token> opStack = new Stack<>(); - Stack<Float> numStack = new Stack<>(); - - for(Token token : tokens){ - - if (token.isOperator()){ - - if(opStack.isEmpty()){ - - opStack.push(token); - } else{ - - while(!opStack.isEmpty() - && !token.hasHigherPriority(opStack.peek())){ - Token prevOperator = opStack.pop(); - Float f2 = numStack.pop(); - Float f1 = numStack.pop(); - Float result = calculate(prevOperator.toString(), f1,f2); - numStack.push(result); - - } - opStack.push(token); - } - } - if(token.isNumber()){ - numStack.push(new Float(token.getIntValue())); - } - } - - while(!opStack.isEmpty()){ - Token token = opStack.pop(); - Float f2 = numStack.pop(); - Float f1 = numStack.pop(); - numStack.push(calculate(token.toString(), f1,f2)); - } - - - return numStack.pop().floatValue(); - } - private Float calculate(String op, Float f1, Float f2){ - if(op.equals("+")){ - return f1+f2; - } - if(op.equals("-")){ - return f1-f2; - } - if(op.equals("*")){ - return f1*f2; - } - if(op.equals("/")){ - return f1/f2; - } - throw new RuntimeException(op + " is not supported"); - } - - - -} +package com.coding.basic.stack.expr; + +import java.util.List; +import java.util.Stack; + + +public class InfixExpr { + String expr = null; + + public InfixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + + + TokenParser parser = new TokenParser(); + List<Token> tokens = parser.parse(this.expr); + + + Stack<Token> opStack = new Stack<>(); + Stack<Float> numStack = new Stack<>(); + + for(Token token : tokens){ + + if (token.isOperator()){ + + if(opStack.isEmpty()){ + + opStack.push(token); + } else{ + + while(!opStack.isEmpty() + && !token.hasHigherPriority(opStack.peek())){ + Token prevOperator = opStack.pop(); + Float f2 = numStack.pop(); + Float f1 = numStack.pop(); + Float result = calculate(prevOperator.toString(), f1,f2); + numStack.push(result); + + } + opStack.push(token); + } + } + if(token.isNumber()){ + numStack.push(new Float(token.getIntValue())); + } + } + + while(!opStack.isEmpty()){ + Token token = opStack.pop(); + Float f2 = numStack.pop(); + Float f1 = numStack.pop(); + numStack.push(calculate(token.toString(), f1,f2)); + } + + + return numStack.pop().floatValue(); + } + private Float calculate(String op, Float f1, Float f2){ + if(op.equals("+")){ + return f1+f2; + } + if(op.equals("-")){ + return f1-f2; + } + if(op.equals("*")){ + return f1*f2; + } + if(op.equals("/")){ + return f1/f2; + } + throw new RuntimeException(op + " is not supported"); + } + + + +} diff --git a/liuxin/data-structure/src/com/coding/basic/stack/expr/InfixExprTest.java b/liuxin/data-structure/answer/src/com/coding/basic/stack/expr/InfixExprTest.java similarity index 95% rename from liuxin/data-structure/src/com/coding/basic/stack/expr/InfixExprTest.java rename to liuxin/data-structure/answer/src/com/coding/basic/stack/expr/InfixExprTest.java index 5a49f6ce20..20e34e8852 100644 --- a/liuxin/data-structure/src/com/coding/basic/stack/expr/InfixExprTest.java +++ b/liuxin/data-structure/answer/src/com/coding/basic/stack/expr/InfixExprTest.java @@ -1,52 +1,52 @@ -package com.coding.basic.stack.expr; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - - -public class InfixExprTest { - - @Before - public void setUp() throws Exception { - } - - @After - public void tearDown() throws Exception { - } - - @Test - public void testEvaluate() { - //InfixExpr expr = new InfixExpr("300*20+12*5-20/4"); - { - InfixExpr expr = new InfixExpr("2+3*4+5"); - Assert.assertEquals(19.0, expr.evaluate(), 0.001f); - } - { - InfixExpr expr = new InfixExpr("3*20+12*5-40/2"); - Assert.assertEquals(100.0, expr.evaluate(), 0.001f); - } - - { - InfixExpr expr = new InfixExpr("3*20/2"); - Assert.assertEquals(30, expr.evaluate(), 0.001f); - } - - { - InfixExpr expr = new InfixExpr("20/2*3"); - Assert.assertEquals(30, expr.evaluate(), 0.001f); - } - - { - InfixExpr expr = new InfixExpr("10-30+50"); - Assert.assertEquals(30, expr.evaluate(), 0.001f); - } - { - InfixExpr expr = new InfixExpr("10-2*3+50"); - Assert.assertEquals(54, expr.evaluate(), 0.001f); - } - - } - -} +package com.coding.basic.stack.expr; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class InfixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + //InfixExpr expr = new InfixExpr("300*20+12*5-20/4"); + { + InfixExpr expr = new InfixExpr("2+3*4+5"); + Assert.assertEquals(19.0, expr.evaluate(), 0.001f); + } + { + InfixExpr expr = new InfixExpr("3*20+12*5-40/2"); + Assert.assertEquals(100.0, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("3*20/2"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("20/2*3"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("10-30+50"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + { + InfixExpr expr = new InfixExpr("10-2*3+50"); + Assert.assertEquals(54, expr.evaluate(), 0.001f); + } + + } + +} diff --git a/liuxin/data-structure/src/com/coding/basic/stack/expr/InfixToPostfix.java b/liuxin/data-structure/answer/src/com/coding/basic/stack/expr/InfixToPostfix.java similarity index 95% rename from liuxin/data-structure/src/com/coding/basic/stack/expr/InfixToPostfix.java rename to liuxin/data-structure/answer/src/com/coding/basic/stack/expr/InfixToPostfix.java index ea86ef155f..de040d1687 100644 --- a/liuxin/data-structure/src/com/coding/basic/stack/expr/InfixToPostfix.java +++ b/liuxin/data-structure/answer/src/com/coding/basic/stack/expr/InfixToPostfix.java @@ -1,52 +1,52 @@ -package com.coding.basic.stack.expr; - -import java.util.ArrayList; -import java.util.List; -import java.util.Stack; - -public class InfixToPostfix { - - public static List<Token> convert(String expr) { - - TokenParser parser = new TokenParser(); - List<Token> tokens = parser.parse(expr); - - Stack<Token> s = new Stack<Token>(); - List<Token> result = new ArrayList<Token>(); - - for(Token token : tokens){ - if(token.isOperator()){ - if(token.toString().equals("*") || token.toString().equals("/")){ - - while (!s.empty() - && !s.peek().toString().equals("+") - && !s.peek().toString().equals("-")) { - - result.add(s.pop()); - - } - - s.push(token); - } - if(token.toString().equals("+") || token.toString().equals("-")){ - while (!s.empty() ) { - result.add(s.pop()); - } - s.push(token); - } - } - if(token.isNumber()){ - result.add(token); - } - } - - return result; - } - - public static void main(String[] args){ - List<Token> tokens = convert("10+20*2"); - System.out.println(tokens); - - } - -} +package com.coding.basic.stack.expr; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +public class InfixToPostfix { + + public static List<Token> convert(String expr) { + + TokenParser parser = new TokenParser(); + List<Token> tokens = parser.parse(expr); + + Stack<Token> s = new Stack<Token>(); + List<Token> result = new ArrayList<Token>(); + + for(Token token : tokens){ + if(token.isOperator()){ + if(token.toString().equals("*") || token.toString().equals("/")){ + + while (!s.empty() + && !s.peek().toString().equals("+") + && !s.peek().toString().equals("-")) { + + result.add(s.pop()); + + } + + s.push(token); + } + if(token.toString().equals("+") || token.toString().equals("-")){ + while (!s.empty() ) { + result.add(s.pop()); + } + s.push(token); + } + } + if(token.isNumber()){ + result.add(token); + } + } + + return result; + } + + public static void main(String[] args){ + List<Token> tokens = convert("10+20*2"); + System.out.println(tokens); + + } + +} diff --git a/liuxin/data-structure/src/com/coding/basic/stack/expr/PostfixExpr.java b/liuxin/data-structure/answer/src/com/coding/basic/stack/expr/PostfixExpr.java similarity index 95% rename from liuxin/data-structure/src/com/coding/basic/stack/expr/PostfixExpr.java rename to liuxin/data-structure/answer/src/com/coding/basic/stack/expr/PostfixExpr.java index d87a314fb4..c54eb69e2a 100644 --- a/liuxin/data-structure/src/com/coding/basic/stack/expr/PostfixExpr.java +++ b/liuxin/data-structure/answer/src/com/coding/basic/stack/expr/PostfixExpr.java @@ -1,46 +1,46 @@ -package com.coding.basic.stack.expr; - -import java.util.List; -import java.util.Stack; - -public class PostfixExpr { -String expr = null; - - public PostfixExpr(String expr) { - this.expr = expr; - } - - public float evaluate() { - TokenParser parser = new TokenParser(); - List<Token> tokens = parser.parse(this.expr); - - - Stack<Float> numStack = new Stack<>(); - for(Token token : tokens){ - if(token.isNumber()){ - numStack.push(new Float(token.getIntValue())); - } else{ - Float f2 = numStack.pop(); - Float f1 = numStack.pop(); - numStack.push(calculate(token.toString(),f1,f2)); - } - } - return numStack.pop().floatValue(); - } - - private Float calculate(String op, Float f1, Float f2){ - if(op.equals("+")){ - return f1+f2; - } - if(op.equals("-")){ - return f1-f2; - } - if(op.equals("*")){ - return f1*f2; - } - if(op.equals("/")){ - return f1/f2; - } - throw new RuntimeException(op + " is not supported"); - } -} +package com.coding.basic.stack.expr; + +import java.util.List; +import java.util.Stack; + +public class PostfixExpr { +String expr = null; + + public PostfixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + TokenParser parser = new TokenParser(); + List<Token> tokens = parser.parse(this.expr); + + + Stack<Float> numStack = new Stack<>(); + for(Token token : tokens){ + if(token.isNumber()){ + numStack.push(new Float(token.getIntValue())); + } else{ + Float f2 = numStack.pop(); + Float f1 = numStack.pop(); + numStack.push(calculate(token.toString(),f1,f2)); + } + } + return numStack.pop().floatValue(); + } + + private Float calculate(String op, Float f1, Float f2){ + if(op.equals("+")){ + return f1+f2; + } + if(op.equals("-")){ + return f1-f2; + } + if(op.equals("*")){ + return f1*f2; + } + if(op.equals("/")){ + return f1/f2; + } + throw new RuntimeException(op + " is not supported"); + } +} diff --git a/liuxin/data-structure/src/com/coding/basic/stack/expr/PostfixExprTest.java b/liuxin/data-structure/answer/src/com/coding/basic/stack/expr/PostfixExprTest.java similarity index 94% rename from liuxin/data-structure/src/com/coding/basic/stack/expr/PostfixExprTest.java rename to liuxin/data-structure/answer/src/com/coding/basic/stack/expr/PostfixExprTest.java index 3de5f12291..c0435a2db5 100644 --- a/liuxin/data-structure/src/com/coding/basic/stack/expr/PostfixExprTest.java +++ b/liuxin/data-structure/answer/src/com/coding/basic/stack/expr/PostfixExprTest.java @@ -1,41 +1,41 @@ -package com.coding.basic.stack.expr; - - - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - - - -public class PostfixExprTest { - - @Before - public void setUp() throws Exception { - } - - @After - public void tearDown() throws Exception { - } - - @Test - public void testEvaluate() { - { - PostfixExpr expr = new PostfixExpr("6 5 2 3 + 8 * + 3 + *"); - Assert.assertEquals(288, expr.evaluate(),0.0f); - } - { - //9+(3-1)*3+10/2 - PostfixExpr expr = new PostfixExpr("9 3 1-3*+ 10 2/+"); - Assert.assertEquals(20, expr.evaluate(),0.0f); - } - - { - //10-2*3+50 - PostfixExpr expr = new PostfixExpr("10 2 3 * - 50 +"); - Assert.assertEquals(54, expr.evaluate(),0.0f); - } - } - -} +package com.coding.basic.stack.expr; + + + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + + +public class PostfixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + { + PostfixExpr expr = new PostfixExpr("6 5 2 3 + 8 * + 3 + *"); + Assert.assertEquals(288, expr.evaluate(),0.0f); + } + { + //9+(3-1)*3+10/2 + PostfixExpr expr = new PostfixExpr("9 3 1-3*+ 10 2/+"); + Assert.assertEquals(20, expr.evaluate(),0.0f); + } + + { + //10-2*3+50 + PostfixExpr expr = new PostfixExpr("10 2 3 * - 50 +"); + Assert.assertEquals(54, expr.evaluate(),0.0f); + } + } + +} diff --git a/liuxin/data-structure/src/com/coding/basic/stack/expr/PrefixExpr.java b/liuxin/data-structure/answer/src/com/coding/basic/stack/expr/PrefixExpr.java similarity index 95% rename from liuxin/data-structure/src/com/coding/basic/stack/expr/PrefixExpr.java rename to liuxin/data-structure/answer/src/com/coding/basic/stack/expr/PrefixExpr.java index e30b1d16ad..f811fd6d9a 100644 --- a/liuxin/data-structure/src/com/coding/basic/stack/expr/PrefixExpr.java +++ b/liuxin/data-structure/answer/src/com/coding/basic/stack/expr/PrefixExpr.java @@ -1,52 +1,52 @@ -package com.coding.basic.stack.expr; - -import java.util.List; -import java.util.Stack; - -public class PrefixExpr { - String expr = null; - - public PrefixExpr(String expr) { - this.expr = expr; - } - - public float evaluate() { - TokenParser parser = new TokenParser(); - List<Token> tokens = parser.parse(this.expr); - - Stack<Token> exprStack = new Stack<>(); - Stack<Float> numStack = new Stack<>(); - for(Token token : tokens){ - exprStack.push(token); - } - - while(!exprStack.isEmpty()){ - Token t = exprStack.pop(); - if(t.isNumber()){ - numStack.push(new Float(t.getIntValue())); - }else{ - Float f1 = numStack.pop(); - Float f2 = numStack.pop(); - numStack.push(calculate(t.toString(),f1,f2)); - - } - } - return numStack.pop().floatValue(); - } - - private Float calculate(String op, Float f1, Float f2){ - if(op.equals("+")){ - return f1+f2; - } - if(op.equals("-")){ - return f1-f2; - } - if(op.equals("*")){ - return f1*f2; - } - if(op.equals("/")){ - return f1/f2; - } - throw new RuntimeException(op + " is not supported"); - } -} +package com.coding.basic.stack.expr; + +import java.util.List; +import java.util.Stack; + +public class PrefixExpr { + String expr = null; + + public PrefixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + TokenParser parser = new TokenParser(); + List<Token> tokens = parser.parse(this.expr); + + Stack<Token> exprStack = new Stack<>(); + Stack<Float> numStack = new Stack<>(); + for(Token token : tokens){ + exprStack.push(token); + } + + while(!exprStack.isEmpty()){ + Token t = exprStack.pop(); + if(t.isNumber()){ + numStack.push(new Float(t.getIntValue())); + }else{ + Float f1 = numStack.pop(); + Float f2 = numStack.pop(); + numStack.push(calculate(t.toString(),f1,f2)); + + } + } + return numStack.pop().floatValue(); + } + + private Float calculate(String op, Float f1, Float f2){ + if(op.equals("+")){ + return f1+f2; + } + if(op.equals("-")){ + return f1-f2; + } + if(op.equals("*")){ + return f1*f2; + } + if(op.equals("/")){ + return f1/f2; + } + throw new RuntimeException(op + " is not supported"); + } +} diff --git a/liuxin/data-structure/src/com/coding/basic/stack/expr/PrefixExprTest.java b/liuxin/data-structure/answer/src/com/coding/basic/stack/expr/PrefixExprTest.java similarity index 95% rename from liuxin/data-structure/src/com/coding/basic/stack/expr/PrefixExprTest.java rename to liuxin/data-structure/answer/src/com/coding/basic/stack/expr/PrefixExprTest.java index b617dbcc93..5cec210e75 100644 --- a/liuxin/data-structure/src/com/coding/basic/stack/expr/PrefixExprTest.java +++ b/liuxin/data-structure/answer/src/com/coding/basic/stack/expr/PrefixExprTest.java @@ -1,45 +1,45 @@ -package com.coding.basic.stack.expr; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - - -public class PrefixExprTest { - - @Before - public void setUp() throws Exception { - } - - @After - public void tearDown() throws Exception { - } - - @Test - public void testEvaluate() { - { - // 2*3+4*5 - PrefixExpr expr = new PrefixExpr("+ * 2 3* 4 5"); - Assert.assertEquals(26, expr.evaluate(),0.001f); - } - { - // 4*2 + 6+9*2/3 -8 - PrefixExpr expr = new PrefixExpr("-++6/*2 9 3 * 4 2 8"); - Assert.assertEquals(12, expr.evaluate(),0.001f); - } - { - //(3+4)*5-6 - PrefixExpr expr = new PrefixExpr("- * + 3 4 5 6"); - Assert.assertEquals(29, expr.evaluate(),0.001f); - } - { - //1+((2+3)*4)-5 - PrefixExpr expr = new PrefixExpr("- + 1 * + 2 3 4 5"); - Assert.assertEquals(16, expr.evaluate(),0.001f); - } - - - } - -} +package com.coding.basic.stack.expr; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class PrefixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + { + // 2*3+4*5 + PrefixExpr expr = new PrefixExpr("+ * 2 3* 4 5"); + Assert.assertEquals(26, expr.evaluate(),0.001f); + } + { + // 4*2 + 6+9*2/3 -8 + PrefixExpr expr = new PrefixExpr("-++6/*2 9 3 * 4 2 8"); + Assert.assertEquals(12, expr.evaluate(),0.001f); + } + { + //(3+4)*5-6 + PrefixExpr expr = new PrefixExpr("- * + 3 4 5 6"); + Assert.assertEquals(29, expr.evaluate(),0.001f); + } + { + //1+((2+3)*4)-5 + PrefixExpr expr = new PrefixExpr("- + 1 * + 2 3 4 5"); + Assert.assertEquals(16, expr.evaluate(),0.001f); + } + + + } + +} diff --git a/liuxin/data-structure/src/com/coding/basic/stack/expr/Token.java b/liuxin/data-structure/answer/src/com/coding/basic/stack/expr/Token.java similarity index 95% rename from liuxin/data-structure/src/com/coding/basic/stack/expr/Token.java rename to liuxin/data-structure/answer/src/com/coding/basic/stack/expr/Token.java index 115c6de3c6..8579743fe9 100644 --- a/liuxin/data-structure/src/com/coding/basic/stack/expr/Token.java +++ b/liuxin/data-structure/answer/src/com/coding/basic/stack/expr/Token.java @@ -1,50 +1,50 @@ -package com.coding.basic.stack.expr; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -class Token { - public static final List<String> OPERATORS = Arrays.asList("+", "-", "*", "/"); - private static final Map<String,Integer> priorities = new HashMap<>(); - static { - priorities.put("+", 1); - priorities.put("-", 1); - priorities.put("*", 2); - priorities.put("/", 2); - } - static final int OPERATOR = 1; - static final int NUMBER = 2; - String value; - int type; - public Token(int type, String value){ - this.type = type; - this.value = value; - } - - public boolean isNumber() { - return type == NUMBER; - } - - public boolean isOperator() { - return type == OPERATOR; - } - - public int getIntValue() { - return Integer.valueOf(value).intValue(); - } - public String toString(){ - return value; - } - - public boolean hasHigherPriority(Token t){ - if(!this.isOperator() && !t.isOperator()){ - throw new RuntimeException("numbers can't compare priority"); - } - return priorities.get(this.value) - priorities.get(t.value) > 0; - } - - - +package com.coding.basic.stack.expr; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +class Token { + public static final List<String> OPERATORS = Arrays.asList("+", "-", "*", "/"); + private static final Map<String,Integer> priorities = new HashMap<>(); + static { + priorities.put("+", 1); + priorities.put("-", 1); + priorities.put("*", 2); + priorities.put("/", 2); + } + static final int OPERATOR = 1; + static final int NUMBER = 2; + String value; + int type; + public Token(int type, String value){ + this.type = type; + this.value = value; + } + + public boolean isNumber() { + return type == NUMBER; + } + + public boolean isOperator() { + return type == OPERATOR; + } + + public int getIntValue() { + return Integer.valueOf(value).intValue(); + } + public String toString(){ + return value; + } + + public boolean hasHigherPriority(Token t){ + if(!this.isOperator() && !t.isOperator()){ + throw new RuntimeException("numbers can't compare priority"); + } + return priorities.get(this.value) - priorities.get(t.value) > 0; + } + + + } \ No newline at end of file diff --git a/liuxin/data-structure/src/com/coding/basic/stack/expr/TokenParser.java b/liuxin/data-structure/answer/src/com/coding/basic/stack/expr/TokenParser.java similarity index 94% rename from liuxin/data-structure/src/com/coding/basic/stack/expr/TokenParser.java rename to liuxin/data-structure/answer/src/com/coding/basic/stack/expr/TokenParser.java index 592449846a..d3b0f167e1 100644 --- a/liuxin/data-structure/src/com/coding/basic/stack/expr/TokenParser.java +++ b/liuxin/data-structure/answer/src/com/coding/basic/stack/expr/TokenParser.java @@ -1,57 +1,57 @@ -package com.coding.basic.stack.expr; - -import java.util.ArrayList; -import java.util.List; - -public class TokenParser { - - - public List<Token> parse(String expr) { - List<Token> tokens = new ArrayList<>(); - - int i = 0; - - while (i < expr.length()) { - - char c = expr.charAt(i); - - if (isOperator(c)) { - - Token t = new Token(Token.OPERATOR, String.valueOf(c)); - tokens.add(t); - i++; - - } else if (Character.isDigit(c)) { - - int nextOperatorIndex = indexOfNextOperator(i, expr); - String value = expr.substring(i, nextOperatorIndex); - Token t = new Token(Token.NUMBER, value); - tokens.add(t); - i = nextOperatorIndex; - - } else{ - System.out.println("char :["+c+"] is not number or operator,ignore"); - i++; - } - - } - return tokens; - } - - private int indexOfNextOperator(int i, String expr) { - - while (Character.isDigit(expr.charAt(i))) { - i++; - if (i == expr.length()) { - break; - } - } - return i; - - } - - private boolean isOperator(char c) { - String sc = String.valueOf(c); - return Token.OPERATORS.contains(sc); - } -} +package com.coding.basic.stack.expr; + +import java.util.ArrayList; +import java.util.List; + +public class TokenParser { + + + public List<Token> parse(String expr) { + List<Token> tokens = new ArrayList<>(); + + int i = 0; + + while (i < expr.length()) { + + char c = expr.charAt(i); + + if (isOperator(c)) { + + Token t = new Token(Token.OPERATOR, String.valueOf(c)); + tokens.add(t); + i++; + + } else if (Character.isDigit(c)) { + + int nextOperatorIndex = indexOfNextOperator(i, expr); + String value = expr.substring(i, nextOperatorIndex); + Token t = new Token(Token.NUMBER, value); + tokens.add(t); + i = nextOperatorIndex; + + } else{ + System.out.println("char :["+c+"] is not number or operator,ignore"); + i++; + } + + } + return tokens; + } + + private int indexOfNextOperator(int i, String expr) { + + while (Character.isDigit(expr.charAt(i))) { + i++; + if (i == expr.length()) { + break; + } + } + return i; + + } + + private boolean isOperator(char c) { + String sc = String.valueOf(c); + return Token.OPERATORS.contains(sc); + } +} diff --git a/liuxin/data-structure/src/com/coding/basic/stack/expr/TokenParserTest.java b/liuxin/data-structure/answer/src/com/coding/basic/stack/expr/TokenParserTest.java similarity index 96% rename from liuxin/data-structure/src/com/coding/basic/stack/expr/TokenParserTest.java rename to liuxin/data-structure/answer/src/com/coding/basic/stack/expr/TokenParserTest.java index b0bcd30f78..399d3e857e 100644 --- a/liuxin/data-structure/src/com/coding/basic/stack/expr/TokenParserTest.java +++ b/liuxin/data-structure/answer/src/com/coding/basic/stack/expr/TokenParserTest.java @@ -1,41 +1,41 @@ -package com.coding.basic.stack.expr; - -import static org.junit.Assert.*; - -import java.util.List; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class TokenParserTest { - - @Before - public void setUp() throws Exception { - } - - @After - public void tearDown() throws Exception { - } - - @Test - public void test() { - - TokenParser parser = new TokenParser(); - List<Token> tokens = parser.parse("300*20+12*5-20/4"); - - Assert.assertEquals(300, tokens.get(0).getIntValue()); - Assert.assertEquals("*", tokens.get(1).toString()); - Assert.assertEquals(20, tokens.get(2).getIntValue()); - Assert.assertEquals("+", tokens.get(3).toString()); - Assert.assertEquals(12, tokens.get(4).getIntValue()); - Assert.assertEquals("*", tokens.get(5).toString()); - Assert.assertEquals(5, tokens.get(6).getIntValue()); - Assert.assertEquals("-", tokens.get(7).toString()); - Assert.assertEquals(20, tokens.get(8).getIntValue()); - Assert.assertEquals("/", tokens.get(9).toString()); - Assert.assertEquals(4, tokens.get(10).getIntValue()); - } - -} +package com.coding.basic.stack.expr; + +import static org.junit.Assert.*; + +import java.util.List; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class TokenParserTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void test() { + + TokenParser parser = new TokenParser(); + List<Token> tokens = parser.parse("300*20+12*5-20/4"); + + Assert.assertEquals(300, tokens.get(0).getIntValue()); + Assert.assertEquals("*", tokens.get(1).toString()); + Assert.assertEquals(20, tokens.get(2).getIntValue()); + Assert.assertEquals("+", tokens.get(3).toString()); + Assert.assertEquals(12, tokens.get(4).getIntValue()); + Assert.assertEquals("*", tokens.get(5).toString()); + Assert.assertEquals(5, tokens.get(6).getIntValue()); + Assert.assertEquals("-", tokens.get(7).toString()); + Assert.assertEquals(20, tokens.get(8).getIntValue()); + Assert.assertEquals("/", tokens.get(9).toString()); + Assert.assertEquals(4, tokens.get(10).getIntValue()); + } + +} diff --git a/liuxin/data-structure/assignment/src/com/coderising/download/DownloadThread.java b/liuxin/data-structure/assignment/src/com/coderising/download/DownloadThread.java new file mode 100644 index 0000000000..900a3ad358 --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coderising/download/DownloadThread.java @@ -0,0 +1,20 @@ +package com.coderising.download; + +import com.coderising.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/liuxin/data-structure/assignment/src/com/coderising/download/FileDownloader.java b/liuxin/data-structure/assignment/src/com/coderising/download/FileDownloader.java new file mode 100644 index 0000000000..c3c8a3f27d --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coderising/download/FileDownloader.java @@ -0,0 +1,73 @@ +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; + + +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/liuxin/data-structure/assignment/src/com/coderising/download/FileDownloaderTest.java b/liuxin/data-structure/assignment/src/com/coderising/download/FileDownloaderTest.java new file mode 100644 index 0000000000..4ff7f46ae0 --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coderising/download/FileDownloaderTest.java @@ -0,0 +1,59 @@ +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://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/liuxin/data-structure/assignment/src/com/coderising/download/api/Connection.java b/liuxin/data-structure/assignment/src/com/coderising/download/api/Connection.java new file mode 100644 index 0000000000..0957eaf7f4 --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coderising/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/liuxin/data-structure/assignment/src/com/coderising/download/api/ConnectionException.java b/liuxin/data-structure/assignment/src/com/coderising/download/api/ConnectionException.java new file mode 100644 index 0000000000..1551a80b3d --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coderising/download/api/ConnectionException.java @@ -0,0 +1,5 @@ +package com.coderising.download.api; + +public class ConnectionException extends Exception { + +} diff --git a/liuxin/data-structure/assignment/src/com/coderising/download/api/ConnectionManager.java b/liuxin/data-structure/assignment/src/com/coderising/download/api/ConnectionManager.java new file mode 100644 index 0000000000..ce045393b1 --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coderising/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/liuxin/data-structure/assignment/src/com/coderising/download/api/DownloadListener.java b/liuxin/data-structure/assignment/src/com/coderising/download/api/DownloadListener.java new file mode 100644 index 0000000000..bf9807b307 --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coderising/download/api/DownloadListener.java @@ -0,0 +1,5 @@ +package com.coderising.download.api; + +public interface DownloadListener { + public void notifyFinished(); +} diff --git a/liuxin/data-structure/assignment/src/com/coderising/download/impl/ConnectionImpl.java b/liuxin/data-structure/assignment/src/com/coderising/download/impl/ConnectionImpl.java new file mode 100644 index 0000000000..36a9d2ce15 --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coderising/download/impl/ConnectionImpl.java @@ -0,0 +1,27 @@ +package com.coderising.download.impl; + +import java.io.IOException; + +import com.coderising.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/liuxin/data-structure/assignment/src/com/coderising/download/impl/ConnectionManagerImpl.java b/liuxin/data-structure/assignment/src/com/coderising/download/impl/ConnectionManagerImpl.java new file mode 100644 index 0000000000..172371dd55 --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coderising/download/impl/ConnectionManagerImpl.java @@ -0,0 +1,15 @@ +package com.coderising.download.impl; + +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 null; + } + +} diff --git a/liuxin/data-structure/assignment/src/com/coderising/litestruts/LoginAction.java b/liuxin/data-structure/assignment/src/com/coderising/litestruts/LoginAction.java new file mode 100644 index 0000000000..dcdbe226ed --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coderising/litestruts/LoginAction.java @@ -0,0 +1,39 @@ +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/liuxin/data-structure/assignment/src/com/coderising/litestruts/Struts.java b/liuxin/data-structure/assignment/src/com/coderising/litestruts/Struts.java new file mode 100644 index 0000000000..85e2e22de3 --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coderising/litestruts/Struts.java @@ -0,0 +1,34 @@ +package com.coderising.litestruts; + +import java.util.Map; + + + +public class Struts { + + public static View runAction(String actionName, Map<String,String> 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中的 <result> 配置,以及execute的返回值, 确定哪一个jsp, + 放到View对象的jsp字段中。 + + */ + + return null; + } + +} diff --git a/liuxin/data-structure/assignment/src/com/coderising/litestruts/StrutsTest.java b/liuxin/data-structure/assignment/src/com/coderising/litestruts/StrutsTest.java new file mode 100644 index 0000000000..b8c81faf3c --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coderising/litestruts/StrutsTest.java @@ -0,0 +1,43 @@ +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<String,String> params = new HashMap<String,String>(); + 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<String,String> params = new HashMap<String,String>(); + 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/liuxin/data-structure/assignment/src/com/coderising/litestruts/View.java b/liuxin/data-structure/assignment/src/com/coderising/litestruts/View.java new file mode 100644 index 0000000000..07df2a5dab --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coderising/litestruts/View.java @@ -0,0 +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; + } +} diff --git a/liuxin/data-structure/assignment/src/com/coding/basic/BinaryTreeNode.java b/liuxin/data-structure/assignment/src/com/coding/basic/BinaryTreeNode.java new file mode 100644 index 0000000000..d7ac820192 --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coding/basic/BinaryTreeNode.java @@ -0,0 +1,32 @@ +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; + } + + public BinaryTreeNode insert(Object o){ + return null; + } + +} diff --git a/liuxin/data-structure/assignment/src/com/coding/basic/Iterator.java b/liuxin/data-structure/assignment/src/com/coding/basic/Iterator.java new file mode 100644 index 0000000000..06ef6311b2 --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coding/basic/Iterator.java @@ -0,0 +1,7 @@ +package com.coding.basic; + +public interface Iterator { + public boolean hasNext(); + public Object next(); + +} diff --git a/liuxin/data-structure/assignment/src/com/coding/basic/List.java b/liuxin/data-structure/assignment/src/com/coding/basic/List.java new file mode 100644 index 0000000000..10d13b5832 --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coding/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/liuxin/data-structure/assignment/src/com/coding/basic/array/ArrayList.java b/liuxin/data-structure/assignment/src/com/coding/basic/array/ArrayList.java new file mode 100644 index 0000000000..4576c016af --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coding/basic/array/ArrayList.java @@ -0,0 +1,35 @@ +package com.coding.basic.array; + +import com.coding.basic.Iterator; +import com.coding.basic.List; + +public class ArrayList implements List { + + private int size = 0; + + private Object[] elementData = new Object[100]; + + 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 Iterator iterator(){ + return null; + } + +} diff --git a/liuxin/data-structure/assignment/src/com/coding/basic/array/ArrayUtil.java b/liuxin/data-structure/assignment/src/com/coding/basic/array/ArrayUtil.java new file mode 100644 index 0000000000..45740e6d57 --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coding/basic/array/ArrayUtil.java @@ -0,0 +1,96 @@ +package com.coding.basic.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 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){ + return null; + } + + /** + * 给定两个已经排序好的整形数组, 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){ + return null; + } + /** + * 把一个已经存满数据的数组 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){ + return null; + } + + /** + * 斐波那契数列为: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){ + return null; + } + + /** + * 返回小于给定最大值max的所有素数数组 + * 例如max = 23, 返回的数组为[2,3,5,7,11,13,17,19] + * @param max + * @return + */ + public int[] getPrimes(int max){ + return null; + } + + /** + * 所谓“完数”, 是指这个数恰好等于它的因子之和,例如6=1+2+3 + * 给定一个最大值max, 返回一个数组, 数组中是小于max 的所有完数 + * @param max + * @return + */ + public int[] getPerfectNumbers(int max){ + return null; + } + + /** + * 用seperator 把数组 array给连接起来 + * 例如array= [3,8,9], seperator = "-" + * 则返回值为"3-8-9" + * @param array + * @param s + * @return + */ + public String join(int[] array, String seperator){ + return null; + } + + +} diff --git a/liuxin/data-structure/assignment/src/com/coding/basic/linklist/LRUPageFrame.java b/liuxin/data-structure/assignment/src/com/coding/basic/linklist/LRUPageFrame.java new file mode 100644 index 0000000000..994a241a3d --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coding/basic/linklist/LRUPageFrame.java @@ -0,0 +1,57 @@ +package com.coding.basic.linklist; + + +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 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/liuxin/data-structure/assignment/src/com/coding/basic/linklist/LRUPageFrameTest.java b/liuxin/data-structure/assignment/src/com/coding/basic/linklist/LRUPageFrameTest.java new file mode 100644 index 0000000000..7fd72fc2b4 --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coding/basic/linklist/LRUPageFrameTest.java @@ -0,0 +1,34 @@ +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()); + frame.access(5); + Assert.assertEquals("5,4,0", frame.toString()); + + } + +} diff --git a/liuxin/data-structure/assignment/src/com/coding/basic/linklist/LinkedList.java b/liuxin/data-structure/assignment/src/com/coding/basic/linklist/LinkedList.java new file mode 100644 index 0000000000..f4c7556a2e --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coding/basic/linklist/LinkedList.java @@ -0,0 +1,125 @@ +package com.coding.basic.linklist; + +import com.coding.basic.Iterator; +import com.coding.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/liuxin/data-structure/assignment/src/com/coding/basic/queue/CircleQueue.java b/liuxin/data-structure/assignment/src/com/coding/basic/queue/CircleQueue.java new file mode 100644 index 0000000000..1ac659da3d --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coding/basic/queue/CircleQueue.java @@ -0,0 +1,5 @@ +package com.coding.basic.queue; + +public class CircleQueue { + +} diff --git a/liuxin/data-structure/assignment/src/com/coding/basic/queue/Josephus.java b/liuxin/data-structure/assignment/src/com/coding/basic/queue/Josephus.java new file mode 100644 index 0000000000..d629d847f4 --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coding/basic/queue/Josephus.java @@ -0,0 +1,19 @@ +package com.coding.basic.queue; + +import java.util.ArrayList; +import java.util.List; + +/** + * 用Queue来实现Josephus问题 + * 在这个古老的问题当中, N个深陷绝境的人一致同意用这种方式减少生存人数: N个人围成一圈(位置记为0到N-1), 并且从第一个人报数, 报到M的人会被杀死, 知道最后一个人留下来 + * @author liuxin + * + */ +public class Josephus { + + public static List<Integer> execute(int n, int m){ + + return null; + } + +} diff --git a/liuxin/data-structure/assignment/src/com/coding/basic/queue/JosephusTest.java b/liuxin/data-structure/assignment/src/com/coding/basic/queue/JosephusTest.java new file mode 100644 index 0000000000..7d90318b51 --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coding/basic/queue/JosephusTest.java @@ -0,0 +1,27 @@ +package com.coding.basic.queue; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + + +public class JosephusTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testExecute() { + + Assert.assertEquals("[1, 3, 5, 0, 4, 2, 6]", Josephus.execute(7, 2).toString()); + + } + +} diff --git a/liuxin/data-structure/assignment/src/com/coding/basic/queue/Queue.java b/liuxin/data-structure/assignment/src/com/coding/basic/queue/Queue.java new file mode 100644 index 0000000000..c4c4b7325e --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coding/basic/queue/Queue.java @@ -0,0 +1,61 @@ +package com.coding.basic.queue; + +import java.util.NoSuchElementException; + +public class Queue<E> { + private Node<E> first; + private Node<E> last; + private int size; + + + private static class Node<E> { + private E item; + private Node<E> next; + } + + + public Queue() { + first = null; + last = null; + size = 0; + } + + + public boolean isEmpty() { + return first == null; + } + + public int size() { + return size; + } + + + + public void enQueue(E data) { + Node<E> oldlast = last; + last = new Node<E>(); + last.item = data; + last.next = null; + if (isEmpty()) { + first = last; + } + else{ + oldlast.next = last; + } + size++; + } + + public E deQueue() { + if (isEmpty()) { + throw new NoSuchElementException("Queue underflow"); + } + E item = first.item; + first = first.next; + size--; + if (isEmpty()) { + last = null; + } + return item; + } + +} diff --git a/liuxin/data-structure/assignment/src/com/coding/basic/queue/QueueWithTwoStacks.java b/liuxin/data-structure/assignment/src/com/coding/basic/queue/QueueWithTwoStacks.java new file mode 100644 index 0000000000..bbd4715ca6 --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coding/basic/queue/QueueWithTwoStacks.java @@ -0,0 +1,40 @@ +package com.coding.basic.queue; + +import java.util.Stack; + +public class QueueWithTwoStacks<E> { + private Stack<E> stack1; + private Stack<E> stack2; + + + public QueueWithTwoStacks() { + stack1 = new Stack<E>(); + stack2 = new Stack<E>(); + } + + + + + public boolean isEmpty() { + return false; + } + + + + public int size() { + return -1; + } + + + + public void enQueue(E item) { + + } + + public E deQueue() { + return null; + } + + + } + diff --git a/liuxin/data-structure/assignment/src/com/coding/basic/stack/Stack.java b/liuxin/data-structure/assignment/src/com/coding/basic/stack/Stack.java new file mode 100644 index 0000000000..fedb243604 --- /dev/null +++ b/liuxin/data-structure/assignment/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/liuxin/data-structure/assignment/src/com/coding/basic/stack/StackUtil.java b/liuxin/data-structure/assignment/src/com/coding/basic/stack/StackUtil.java new file mode 100644 index 0000000000..b0ec38161d --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coding/basic/stack/StackUtil.java @@ -0,0 +1,48 @@ +package com.coding.basic.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<Integer> 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; + } + + +} diff --git a/liuxin/data-structure/assignment/src/com/coding/basic/stack/StackUtilTest.java b/liuxin/data-structure/assignment/src/com/coding/basic/stack/StackUtilTest.java new file mode 100644 index 0000000000..76f2cb7668 --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coding/basic/stack/StackUtilTest.java @@ -0,0 +1,65 @@ +package com.coding.basic.stack; + +import java.util.Stack; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +public class StackUtilTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + + @Test + public void testReverse() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + Assert.assertEquals("[1, 2, 3, 4, 5]", s.toString()); + StackUtil.reverse(s); + Assert.assertEquals("[5, 4, 3, 2, 1]", s.toString()); + } + + @Test + public void testRemove() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + StackUtil.remove(s, 2); + Assert.assertEquals("[1, 3]", s.toString()); + } + + @Test + public void testGetTop() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + { + Object[] values = StackUtil.getTop(s, 3); + Assert.assertEquals(5, values[0]); + Assert.assertEquals(4, values[1]); + Assert.assertEquals(3, values[2]); + } + } + + @Test + public void testIsValidPairs() { + Assert.assertTrue(StackUtil.isValidPairs("([e{d}f])")); + Assert.assertFalse(StackUtil.isValidPairs("([b{x]y})")); + } + +} diff --git a/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/InfixExpr.java b/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/InfixExpr.java new file mode 100644 index 0000000000..ef85ff007f --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/InfixExpr.java @@ -0,0 +1,15 @@ +package com.coding.basic.stack.expr; + +public class InfixExpr { + String expr = null; + + public InfixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + return 0.0f; + } + + +} diff --git a/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/InfixExprTest.java b/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/InfixExprTest.java new file mode 100644 index 0000000000..20e34e8852 --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/InfixExprTest.java @@ -0,0 +1,52 @@ +package com.coding.basic.stack.expr; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class InfixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + //InfixExpr expr = new InfixExpr("300*20+12*5-20/4"); + { + InfixExpr expr = new InfixExpr("2+3*4+5"); + Assert.assertEquals(19.0, expr.evaluate(), 0.001f); + } + { + InfixExpr expr = new InfixExpr("3*20+12*5-40/2"); + Assert.assertEquals(100.0, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("3*20/2"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("20/2*3"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("10-30+50"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + { + InfixExpr expr = new InfixExpr("10-2*3+50"); + Assert.assertEquals(54, expr.evaluate(), 0.001f); + } + + } + +} diff --git a/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/InfixToPostfix.java b/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/InfixToPostfix.java new file mode 100644 index 0000000000..96a2194a67 --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/InfixToPostfix.java @@ -0,0 +1,14 @@ +package com.coding.basic.stack.expr; + +import java.util.List; + +public class InfixToPostfix { + + public static List<Token> convert(String expr) { + + return null; + } + + + +} diff --git a/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/PostfixExpr.java b/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/PostfixExpr.java new file mode 100644 index 0000000000..dcbb18be4b --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/PostfixExpr.java @@ -0,0 +1,18 @@ +package com.coding.basic.stack.expr; + +import java.util.List; +import java.util.Stack; + +public class PostfixExpr { +String expr = null; + + public PostfixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + return 0.0f; + } + + +} diff --git a/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/PostfixExprTest.java b/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/PostfixExprTest.java new file mode 100644 index 0000000000..c0435a2db5 --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/PostfixExprTest.java @@ -0,0 +1,41 @@ +package com.coding.basic.stack.expr; + + + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + + +public class PostfixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + { + PostfixExpr expr = new PostfixExpr("6 5 2 3 + 8 * + 3 + *"); + Assert.assertEquals(288, expr.evaluate(),0.0f); + } + { + //9+(3-1)*3+10/2 + PostfixExpr expr = new PostfixExpr("9 3 1-3*+ 10 2/+"); + Assert.assertEquals(20, expr.evaluate(),0.0f); + } + + { + //10-2*3+50 + PostfixExpr expr = new PostfixExpr("10 2 3 * - 50 +"); + Assert.assertEquals(54, expr.evaluate(),0.0f); + } + } + +} diff --git a/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/PrefixExpr.java b/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/PrefixExpr.java new file mode 100644 index 0000000000..956927e2df --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/PrefixExpr.java @@ -0,0 +1,18 @@ +package com.coding.basic.stack.expr; + +import java.util.List; +import java.util.Stack; + +public class PrefixExpr { + String expr = null; + + public PrefixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + return 0.0f; + } + + +} diff --git a/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/PrefixExprTest.java b/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/PrefixExprTest.java new file mode 100644 index 0000000000..5cec210e75 --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/PrefixExprTest.java @@ -0,0 +1,45 @@ +package com.coding.basic.stack.expr; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class PrefixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + { + // 2*3+4*5 + PrefixExpr expr = new PrefixExpr("+ * 2 3* 4 5"); + Assert.assertEquals(26, expr.evaluate(),0.001f); + } + { + // 4*2 + 6+9*2/3 -8 + PrefixExpr expr = new PrefixExpr("-++6/*2 9 3 * 4 2 8"); + Assert.assertEquals(12, expr.evaluate(),0.001f); + } + { + //(3+4)*5-6 + PrefixExpr expr = new PrefixExpr("- * + 3 4 5 6"); + Assert.assertEquals(29, expr.evaluate(),0.001f); + } + { + //1+((2+3)*4)-5 + PrefixExpr expr = new PrefixExpr("- + 1 * + 2 3 4 5"); + Assert.assertEquals(16, expr.evaluate(),0.001f); + } + + + } + +} diff --git a/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/Token.java b/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/Token.java new file mode 100644 index 0000000000..8579743fe9 --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/Token.java @@ -0,0 +1,50 @@ +package com.coding.basic.stack.expr; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +class Token { + public static final List<String> OPERATORS = Arrays.asList("+", "-", "*", "/"); + private static final Map<String,Integer> priorities = new HashMap<>(); + static { + priorities.put("+", 1); + priorities.put("-", 1); + priorities.put("*", 2); + priorities.put("/", 2); + } + static final int OPERATOR = 1; + static final int NUMBER = 2; + String value; + int type; + public Token(int type, String value){ + this.type = type; + this.value = value; + } + + public boolean isNumber() { + return type == NUMBER; + } + + public boolean isOperator() { + return type == OPERATOR; + } + + public int getIntValue() { + return Integer.valueOf(value).intValue(); + } + public String toString(){ + return value; + } + + public boolean hasHigherPriority(Token t){ + if(!this.isOperator() && !t.isOperator()){ + throw new RuntimeException("numbers can't compare priority"); + } + return priorities.get(this.value) - priorities.get(t.value) > 0; + } + + + +} \ No newline at end of file diff --git a/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/TokenParser.java b/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/TokenParser.java new file mode 100644 index 0000000000..d3b0f167e1 --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/TokenParser.java @@ -0,0 +1,57 @@ +package com.coding.basic.stack.expr; + +import java.util.ArrayList; +import java.util.List; + +public class TokenParser { + + + public List<Token> parse(String expr) { + List<Token> tokens = new ArrayList<>(); + + int i = 0; + + while (i < expr.length()) { + + char c = expr.charAt(i); + + if (isOperator(c)) { + + Token t = new Token(Token.OPERATOR, String.valueOf(c)); + tokens.add(t); + i++; + + } else if (Character.isDigit(c)) { + + int nextOperatorIndex = indexOfNextOperator(i, expr); + String value = expr.substring(i, nextOperatorIndex); + Token t = new Token(Token.NUMBER, value); + tokens.add(t); + i = nextOperatorIndex; + + } else{ + System.out.println("char :["+c+"] is not number or operator,ignore"); + i++; + } + + } + return tokens; + } + + private int indexOfNextOperator(int i, String expr) { + + while (Character.isDigit(expr.charAt(i))) { + i++; + if (i == expr.length()) { + break; + } + } + return i; + + } + + private boolean isOperator(char c) { + String sc = String.valueOf(c); + return Token.OPERATORS.contains(sc); + } +} diff --git a/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/TokenParserTest.java b/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/TokenParserTest.java new file mode 100644 index 0000000000..399d3e857e --- /dev/null +++ b/liuxin/data-structure/assignment/src/com/coding/basic/stack/expr/TokenParserTest.java @@ -0,0 +1,41 @@ +package com.coding.basic.stack.expr; + +import static org.junit.Assert.*; + +import java.util.List; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class TokenParserTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void test() { + + TokenParser parser = new TokenParser(); + List<Token> tokens = parser.parse("300*20+12*5-20/4"); + + Assert.assertEquals(300, tokens.get(0).getIntValue()); + Assert.assertEquals("*", tokens.get(1).toString()); + Assert.assertEquals(20, tokens.get(2).getIntValue()); + Assert.assertEquals("+", tokens.get(3).toString()); + Assert.assertEquals(12, tokens.get(4).getIntValue()); + Assert.assertEquals("*", tokens.get(5).toString()); + Assert.assertEquals(5, tokens.get(6).getIntValue()); + Assert.assertEquals("-", tokens.get(7).toString()); + Assert.assertEquals(20, tokens.get(8).getIntValue()); + Assert.assertEquals("/", tokens.get(9).toString()); + Assert.assertEquals(4, tokens.get(10).getIntValue()); + } + +} From a873760efc9201006ed4e24ecdfa403f82d020c6 Mon Sep 17 00:00:00 2001 From: onlyliuxin <14703250@qq.com> Date: Mon, 17 Apr 2017 10:35:46 +0800 Subject: [PATCH 281/287] =?UTF-8?q?=E6=8A=8A=E4=BB=A3=E7=A0=81=E5=92=8C?= =?UTF-8?q?=E4=BD=9C=E4=B8=9A=E5=88=86=E5=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coderising/jvm/attr/AttributeInfo.java | 38 +- .../src/com/coderising/jvm/attr/CodeAttr.java | 242 +++--- .../coderising/jvm/attr/LineNumberTable.java | 136 ++-- .../jvm/attr/LocalVariableItem.java | 78 +- .../jvm/attr/LocalVariableTable.java | 116 +-- .../coderising/jvm/attr/StackMapTable.java | 60 +- .../com/coderising/jvm/clz/AccessFlag.java | 0 .../src/com/coderising/jvm/clz/ClassFile.java | 240 +++--- .../com/coderising/jvm/clz/ClassIndex.java | 0 .../src/com/coderising/jvm/cmd/BiPushCmd.java | 46 +- .../coderising/jvm/cmd/ByteCodeCommand.java | 256 +++---- .../com/coderising/jvm/cmd/CommandParser.java | 310 ++++---- .../com/coderising/jvm/cmd/GetFieldCmd.java | 44 +- .../coderising/jvm/cmd/GetStaticFieldCmd.java | 46 +- .../coderising/jvm/cmd/InvokeSpecialCmd.java | 46 +- .../coderising/jvm/cmd/InvokeVirtualCmd.java | 44 +- .../src/com/coderising/jvm/cmd/LdcCmd.java | 58 +- .../com/coderising/jvm/cmd/NewObjectCmd.java | 38 +- .../com/coderising/jvm/cmd/NoOperandCmd.java | 46 +- .../com/coderising/jvm/cmd/OneOperandCmd.java | 54 +- .../com/coderising/jvm/cmd/PutFieldCmd.java | 38 +- .../com/coderising/jvm/cmd/TwoOperandCmd.java | 134 ++-- .../coderising/jvm/constant/ClassInfo.java | 0 .../coderising/jvm/constant/ConstantInfo.java | 0 .../coderising/jvm/constant/ConstantPool.java | 0 .../coderising/jvm/constant/FieldRefInfo.java | 0 .../jvm/constant/MethodRefInfo.java | 0 .../jvm/constant/NameAndTypeInfo.java | 0 .../jvm/constant/NullConstantInfo.java | 0 .../coderising/jvm/constant/StringInfo.java | 0 .../com/coderising/jvm/constant/UTF8Info.java | 0 .../src/com/coderising/jvm/field/Field.java | 100 +-- .../jvm/loader/ByteCodeIterator.java | 114 +-- .../jvm/loader/ClassFileLoader.java | 278 +++---- .../jvm/loader/ClassFileParser.java | 342 ++++----- .../src/com/coderising/jvm/method/Method.java | 206 ++--- .../jvm/print/ClassFilePrinter.java | 108 +-- .../jvm/print/ConstantPoolPrinter.java | 166 ++-- .../jvm/print/ConstantPoolPrinterBad.java | 80 +- .../jvm/test/ClassFileloaderTest.java | 708 +++++++++--------- .../com/coderising/jvm/test/EmployeeV1.java | 54 +- .../src/com/coderising/jvm/util/Util.java | 0 .../coderising/jvm/attr/AttributeInfo.java | 19 + .../src/com/coderising/jvm/attr/CodeAttr.java | 70 ++ .../coderising/jvm/attr/LineNumberTable.java | 55 ++ .../jvm/attr/LocalVariableItem.java | 39 + .../jvm/attr/LocalVariableTable.java | 42 ++ .../coderising/jvm/attr/StackMapTable.java | 30 + .../com/coderising/jvm/clz/AccessFlag.java | 25 + .../src/com/coderising/jvm/clz/ClassFile.java | 102 +++ .../com/coderising/jvm/clz/ClassIndex.java | 19 + .../src/com/coderising/jvm/cmd/BiPushCmd.java | 23 + .../coderising/jvm/cmd/ByteCodeCommand.java | 128 ++++ .../com/coderising/jvm/cmd/CommandParser.java | 85 +++ .../com/coderising/jvm/cmd/GetFieldCmd.java | 22 + .../coderising/jvm/cmd/GetStaticFieldCmd.java | 23 + .../coderising/jvm/cmd/InvokeSpecialCmd.java | 23 + .../coderising/jvm/cmd/InvokeVirtualCmd.java | 22 + .../src/com/coderising/jvm/cmd/LdcCmd.java | 29 + .../com/coderising/jvm/cmd/NewObjectCmd.java | 19 + .../com/coderising/jvm/cmd/NoOperandCmd.java | 23 + .../com/coderising/jvm/cmd/OneOperandCmd.java | 27 + .../com/coderising/jvm/cmd/PutFieldCmd.java | 19 + .../com/coderising/jvm/cmd/TwoOperandCmd.java | 67 ++ .../coderising/jvm/constant/ClassInfo.java | 28 + .../coderising/jvm/constant/ConstantInfo.java | 40 + .../coderising/jvm/constant/ConstantPool.java | 31 + .../coderising/jvm/constant/FieldRefInfo.java | 58 ++ .../jvm/constant/MethodRefInfo.java | 60 ++ .../jvm/constant/NameAndTypeInfo.java | 51 ++ .../jvm/constant/NullConstantInfo.java | 17 + .../coderising/jvm/constant/StringInfo.java | 32 + .../com/coderising/jvm/constant/UTF8Info.java | 37 + .../src/com/coderising/jvm/field/Field.java | 50 ++ .../jvm/loader/ByteCodeIterator.java | 57 ++ .../jvm/loader/ClassFileLoader.java | 140 ++++ .../jvm/loader/ClassFileParser.java | 62 ++ .../src/com/coderising/jvm/method/Method.java | 80 ++ .../jvm/print/ClassFilePrinter.java | 54 ++ .../jvm/print/ConstantPoolPrinter.java | 25 + .../jvm/test/ClassFileloaderTest.java | 354 +++++++++ .../com/coderising/jvm/test/EmployeeV1.java | 28 + .../src/com/coderising/jvm/util/Util.java | 24 + 83 files changed, 4252 insertions(+), 2113 deletions(-) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/attr/AttributeInfo.java (96%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/attr/CodeAttr.java (96%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/attr/LineNumberTable.java (95%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/attr/LocalVariableItem.java (95%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/attr/LocalVariableTable.java (96%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/attr/StackMapTable.java (95%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/clz/AccessFlag.java (100%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/clz/ClassFile.java (96%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/clz/ClassIndex.java (100%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/cmd/BiPushCmd.java (95%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/cmd/ByteCodeCommand.java (95%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/cmd/CommandParser.java (96%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/cmd/GetFieldCmd.java (94%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/cmd/GetStaticFieldCmd.java (95%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/cmd/InvokeSpecialCmd.java (94%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/cmd/InvokeVirtualCmd.java (94%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/cmd/LdcCmd.java (96%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/cmd/NewObjectCmd.java (95%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/cmd/NoOperandCmd.java (95%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/cmd/OneOperandCmd.java (94%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/cmd/PutFieldCmd.java (95%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/cmd/TwoOperandCmd.java (96%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/constant/ClassInfo.java (100%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/constant/ConstantInfo.java (100%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/constant/ConstantPool.java (100%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/constant/FieldRefInfo.java (100%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/constant/MethodRefInfo.java (100%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/constant/NameAndTypeInfo.java (100%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/constant/NullConstantInfo.java (100%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/constant/StringInfo.java (100%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/constant/UTF8Info.java (100%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/field/Field.java (96%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/loader/ByteCodeIterator.java (95%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/loader/ClassFileLoader.java (94%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/loader/ClassFileParser.java (96%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/method/Method.java (95%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/print/ClassFilePrinter.java (96%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/print/ConstantPoolPrinter.java (96%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/print/ConstantPoolPrinterBad.java (96%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/test/ClassFileloaderTest.java (96%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/test/EmployeeV1.java (95%) rename liuxin/mini-jvm/{ => answer}/src/com/coderising/jvm/util/Util.java (100%) create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/attr/AttributeInfo.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/attr/CodeAttr.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/attr/LineNumberTable.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/attr/LocalVariableItem.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/attr/LocalVariableTable.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/attr/StackMapTable.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/clz/AccessFlag.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/clz/ClassFile.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/clz/ClassIndex.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/BiPushCmd.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/ByteCodeCommand.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/CommandParser.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/GetFieldCmd.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/GetStaticFieldCmd.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/InvokeSpecialCmd.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/InvokeVirtualCmd.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/LdcCmd.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/NewObjectCmd.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/NoOperandCmd.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/OneOperandCmd.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/PutFieldCmd.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/TwoOperandCmd.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/ClassInfo.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/ConstantInfo.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/ConstantPool.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/FieldRefInfo.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/MethodRefInfo.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/NameAndTypeInfo.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/NullConstantInfo.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/StringInfo.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/UTF8Info.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/field/Field.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/loader/ByteCodeIterator.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/loader/ClassFileLoader.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/loader/ClassFileParser.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/method/Method.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/print/ClassFilePrinter.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/print/ConstantPoolPrinter.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/test/ClassFileloaderTest.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/test/EmployeeV1.java create mode 100644 liuxin/mini-jvm/assignment/src/com/coderising/jvm/util/Util.java diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/attr/AttributeInfo.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/attr/AttributeInfo.java similarity index 96% rename from liuxin/mini-jvm/src/com/coderising/jvm/attr/AttributeInfo.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/attr/AttributeInfo.java index 89fb53394e..88f60c77f6 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/attr/AttributeInfo.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/attr/AttributeInfo.java @@ -1,19 +1,19 @@ -package com.coderising.jvm.attr; - -public abstract class AttributeInfo { - public static final String CODE = "Code"; - public static final String CONST_VALUE = "ConstantValue"; - public static final String EXCEPTIONS = "Exceptions"; - public static final String LINE_NUM_TABLE = "LineNumberTable"; - public static final String LOCAL_VAR_TABLE = "LocalVariableTable"; - public static final String STACK_MAP_TABLE = "StackMapTable"; - int attrNameIndex; - int attrLen ; - public AttributeInfo(int attrNameIndex, int attrLen) { - - this.attrNameIndex = attrNameIndex; - this.attrLen = attrLen; - } - - -} +package com.coderising.jvm.attr; + +public abstract class AttributeInfo { + public static final String CODE = "Code"; + public static final String CONST_VALUE = "ConstantValue"; + public static final String EXCEPTIONS = "Exceptions"; + public static final String LINE_NUM_TABLE = "LineNumberTable"; + public static final String LOCAL_VAR_TABLE = "LocalVariableTable"; + public static final String STACK_MAP_TABLE = "StackMapTable"; + int attrNameIndex; + int attrLen ; + public AttributeInfo(int attrNameIndex, int attrLen) { + + this.attrNameIndex = attrNameIndex; + this.attrLen = attrLen; + } + + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/attr/CodeAttr.java similarity index 96% rename from liuxin/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/attr/CodeAttr.java index c2343e8590..03df78f541 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/attr/CodeAttr.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/attr/CodeAttr.java @@ -1,121 +1,121 @@ -package com.coderising.jvm.attr; - -import com.coderising.jvm.clz.ClassFile; -import com.coderising.jvm.cmd.ByteCodeCommand; -import com.coderising.jvm.cmd.CommandParser; -import com.coderising.jvm.constant.ConstantPool; -import com.coderising.jvm.loader.ByteCodeIterator; - - -public class CodeAttr extends AttributeInfo { - private int maxStack ; - private int maxLocals ; - private int codeLen ; - private String code; - public String getCode() { - return code; - } - - private ByteCodeCommand[] cmds ; - public ByteCodeCommand[] getCmds() { - return cmds; - } - private LineNumberTable lineNumTable; - private LocalVariableTable localVarTable; - private StackMapTable stackMapTable; - - public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen,String code ,ByteCodeCommand[] cmds) { - super(attrNameIndex, attrLen); - this.maxStack = maxStack; - this.maxLocals = maxLocals; - this.codeLen = codeLen; - this.code = code; - this.cmds = cmds; - } - - public void setLineNumberTable(LineNumberTable t) { - this.lineNumTable = t; - } - - public void setLocalVariableTable(LocalVariableTable t) { - this.localVarTable = t; - } - - public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ - - int attrNameIndex = iter.nextU2ToInt(); - int attrLen = iter.nextU4ToInt(); - int maxStack = iter.nextU2ToInt(); - int maxLocals = iter.nextU2ToInt(); - int codeLen = iter.nextU4ToInt(); - - String code = iter.nextUxToHexString(codeLen); - - - ByteCodeCommand[] cmds = CommandParser.parse(clzFile,code); - - CodeAttr codeAttr = new CodeAttr(attrNameIndex,attrLen, maxStack,maxLocals,codeLen,code,cmds); - - int exceptionTableLen = iter.nextU2ToInt(); - //TODO 处理exception - if(exceptionTableLen>0){ - String exTable = iter.nextUxToHexString(exceptionTableLen); - System.out.println("Encountered exception table , just ignore it :" + exTable); - - } - - - int subAttrCount = iter.nextU2ToInt(); - - for(int x=1; x<=subAttrCount; x++){ - int subAttrIndex = iter.nextU2ToInt(); - String subAttrName = clzFile.getConstantPool().getUTF8String(subAttrIndex); - - //已经向前移动了U2, 现在退回去。 - iter.back(2); - //line item table - if(AttributeInfo.LINE_NUM_TABLE.equalsIgnoreCase(subAttrName)){ - - LineNumberTable t = LineNumberTable.parse(iter); - codeAttr.setLineNumberTable(t); - } - else if(AttributeInfo.LOCAL_VAR_TABLE.equalsIgnoreCase(subAttrName)){ - LocalVariableTable t = LocalVariableTable.parse(iter); - codeAttr.setLocalVariableTable(t); - } - else if (AttributeInfo.STACK_MAP_TABLE.equalsIgnoreCase(subAttrName)){ - StackMapTable t = StackMapTable.parse(iter); - codeAttr.setStackMapTable(t); - } - else{ - throw new RuntimeException("Need code to process " + subAttrName); - } - - - } - - return codeAttr; - } - - - public String toString(ConstantPool pool){ - StringBuilder buffer = new StringBuilder(); - //buffer.append("Code:").append(code).append("\n"); - for(int i=0;i<cmds.length;i++){ - buffer.append(cmds[i].toString(pool)).append("\n"); - } - buffer.append("\n"); - buffer.append(this.lineNumTable.toString()); - buffer.append(this.localVarTable.toString(pool)); - return buffer.toString(); - } - private void setStackMapTable(StackMapTable t) { - this.stackMapTable = t; - - } - - - - - -} +package com.coderising.jvm.attr; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.cmd.ByteCodeCommand; +import com.coderising.jvm.cmd.CommandParser; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.loader.ByteCodeIterator; + + +public class CodeAttr extends AttributeInfo { + private int maxStack ; + private int maxLocals ; + private int codeLen ; + private String code; + public String getCode() { + return code; + } + + private ByteCodeCommand[] cmds ; + public ByteCodeCommand[] getCmds() { + return cmds; + } + private LineNumberTable lineNumTable; + private LocalVariableTable localVarTable; + private StackMapTable stackMapTable; + + public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen,String code ,ByteCodeCommand[] cmds) { + super(attrNameIndex, attrLen); + this.maxStack = maxStack; + this.maxLocals = maxLocals; + this.codeLen = codeLen; + this.code = code; + this.cmds = cmds; + } + + public void setLineNumberTable(LineNumberTable t) { + this.lineNumTable = t; + } + + public void setLocalVariableTable(LocalVariableTable t) { + this.localVarTable = t; + } + + public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ + + int attrNameIndex = iter.nextU2ToInt(); + int attrLen = iter.nextU4ToInt(); + int maxStack = iter.nextU2ToInt(); + int maxLocals = iter.nextU2ToInt(); + int codeLen = iter.nextU4ToInt(); + + String code = iter.nextUxToHexString(codeLen); + + + ByteCodeCommand[] cmds = CommandParser.parse(clzFile,code); + + CodeAttr codeAttr = new CodeAttr(attrNameIndex,attrLen, maxStack,maxLocals,codeLen,code,cmds); + + int exceptionTableLen = iter.nextU2ToInt(); + //TODO 处理exception + if(exceptionTableLen>0){ + String exTable = iter.nextUxToHexString(exceptionTableLen); + System.out.println("Encountered exception table , just ignore it :" + exTable); + + } + + + int subAttrCount = iter.nextU2ToInt(); + + for(int x=1; x<=subAttrCount; x++){ + int subAttrIndex = iter.nextU2ToInt(); + String subAttrName = clzFile.getConstantPool().getUTF8String(subAttrIndex); + + //已经向前移动了U2, 现在退回去。 + iter.back(2); + //line item table + if(AttributeInfo.LINE_NUM_TABLE.equalsIgnoreCase(subAttrName)){ + + LineNumberTable t = LineNumberTable.parse(iter); + codeAttr.setLineNumberTable(t); + } + else if(AttributeInfo.LOCAL_VAR_TABLE.equalsIgnoreCase(subAttrName)){ + LocalVariableTable t = LocalVariableTable.parse(iter); + codeAttr.setLocalVariableTable(t); + } + else if (AttributeInfo.STACK_MAP_TABLE.equalsIgnoreCase(subAttrName)){ + StackMapTable t = StackMapTable.parse(iter); + codeAttr.setStackMapTable(t); + } + else{ + throw new RuntimeException("Need code to process " + subAttrName); + } + + + } + + return codeAttr; + } + + + public String toString(ConstantPool pool){ + StringBuilder buffer = new StringBuilder(); + //buffer.append("Code:").append(code).append("\n"); + for(int i=0;i<cmds.length;i++){ + buffer.append(cmds[i].toString(pool)).append("\n"); + } + buffer.append("\n"); + buffer.append(this.lineNumTable.toString()); + buffer.append(this.localVarTable.toString(pool)); + return buffer.toString(); + } + private void setStackMapTable(StackMapTable t) { + this.stackMapTable = t; + + } + + + + + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/attr/LineNumberTable.java similarity index 95% rename from liuxin/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/attr/LineNumberTable.java index 7ee5d1bc5e..e3189959d7 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/attr/LineNumberTable.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/attr/LineNumberTable.java @@ -1,68 +1,68 @@ -package com.coderising.jvm.attr; - -import java.util.ArrayList; -import java.util.List; - - -import com.coderising.jvm.loader.ByteCodeIterator; - -public class LineNumberTable extends AttributeInfo { - List<LineNumberItem> items = new ArrayList<LineNumberItem>(); - - private static class LineNumberItem{ - int startPC; - int lineNum; - public int getStartPC() { - return startPC; - } - public void setStartPC(int startPC) { - this.startPC = startPC; - } - public int getLineNum() { - return lineNum; - } - public void setLineNum(int lineNum) { - this.lineNum = lineNum; - } - } - public void addLineNumberItem(LineNumberItem item){ - this.items.add(item); - } - public LineNumberTable(int attrNameIndex, int attrLen) { - super(attrNameIndex, attrLen); - - } - - public static LineNumberTable parse(ByteCodeIterator iter){ - - int index = iter.nextU2ToInt(); - int len = iter.nextU4ToInt(); - - LineNumberTable table = new LineNumberTable(index,len); - - int itemLen = iter.nextU2ToInt(); - - for(int i=1; i<=itemLen; i++){ - LineNumberItem item = new LineNumberItem(); - item.setStartPC(iter.nextU2ToInt()); - item.setLineNum(iter.nextU2ToInt()); - table.addLineNumberItem(item); - } - return table; - } - - public String toString(){ - StringBuilder buffer = new StringBuilder(); - buffer.append("Line Number Table:\n"); - for(LineNumberItem item : items){ - buffer.append("startPC:"+item.getStartPC()).append(","); - buffer.append("lineNum:"+item.getLineNum()).append("\n"); - } - buffer.append("\n"); - return buffer.toString(); - - } - - - -} +package com.coderising.jvm.attr; + +import java.util.ArrayList; +import java.util.List; + + +import com.coderising.jvm.loader.ByteCodeIterator; + +public class LineNumberTable extends AttributeInfo { + List<LineNumberItem> items = new ArrayList<LineNumberItem>(); + + private static class LineNumberItem{ + int startPC; + int lineNum; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLineNum() { + return lineNum; + } + public void setLineNum(int lineNum) { + this.lineNum = lineNum; + } + } + public void addLineNumberItem(LineNumberItem item){ + this.items.add(item); + } + public LineNumberTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + + } + + public static LineNumberTable parse(ByteCodeIterator iter){ + + int index = iter.nextU2ToInt(); + int len = iter.nextU4ToInt(); + + LineNumberTable table = new LineNumberTable(index,len); + + int itemLen = iter.nextU2ToInt(); + + for(int i=1; i<=itemLen; i++){ + LineNumberItem item = new LineNumberItem(); + item.setStartPC(iter.nextU2ToInt()); + item.setLineNum(iter.nextU2ToInt()); + table.addLineNumberItem(item); + } + return table; + } + + public String toString(){ + StringBuilder buffer = new StringBuilder(); + buffer.append("Line Number Table:\n"); + for(LineNumberItem item : items){ + buffer.append("startPC:"+item.getStartPC()).append(","); + buffer.append("lineNum:"+item.getLineNum()).append("\n"); + } + buffer.append("\n"); + return buffer.toString(); + + } + + + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/attr/LocalVariableItem.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/attr/LocalVariableItem.java similarity index 95% rename from liuxin/mini-jvm/src/com/coderising/jvm/attr/LocalVariableItem.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/attr/LocalVariableItem.java index 3eb2654e36..962c3b8bc4 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/attr/LocalVariableItem.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/attr/LocalVariableItem.java @@ -1,39 +1,39 @@ -package com.coderising.jvm.attr; - -public class LocalVariableItem { - private int startPC; - private int length; - private int nameIndex; - private int descIndex; - private int index; - public int getStartPC() { - return startPC; - } - public void setStartPC(int startPC) { - this.startPC = startPC; - } - public int getLength() { - return length; - } - public void setLength(int length) { - this.length = length; - } - public int getNameIndex() { - return nameIndex; - } - public void setNameIndex(int nameIndex) { - this.nameIndex = nameIndex; - } - public int getDescIndex() { - return descIndex; - } - public void setDescIndex(int descIndex) { - this.descIndex = descIndex; - } - public int getIndex() { - return index; - } - public void setIndex(int index) { - this.index = index; - } -} +package com.coderising.jvm.attr; + +public class LocalVariableItem { + private int startPC; + private int length; + private int nameIndex; + private int descIndex; + private int index; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getNameIndex() { + return nameIndex; + } + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + public int getDescIndex() { + return descIndex; + } + public void setDescIndex(int descIndex) { + this.descIndex = descIndex; + } + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/attr/LocalVariableTable.java similarity index 96% rename from liuxin/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/attr/LocalVariableTable.java index 2e332f170d..88f677b2c8 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/attr/LocalVariableTable.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/attr/LocalVariableTable.java @@ -1,58 +1,58 @@ -package com.coderising.jvm.attr; - - -import java.util.ArrayList; -import java.util.List; - -import com.coderising.jvm.constant.ConstantPool; - -import com.coderising.jvm.loader.ByteCodeIterator; - -public class LocalVariableTable extends AttributeInfo{ - - List<LocalVariableItem> items = new ArrayList<LocalVariableItem>(); - - public LocalVariableTable(int attrNameIndex, int attrLen) { - super(attrNameIndex, attrLen); - } - - - private void addLocalVariableItem(LocalVariableItem item) { - this.items.add(item); - } - - public static LocalVariableTable parse(ByteCodeIterator iter){ - - int index = iter.nextU2ToInt(); - int len = iter.nextU4ToInt(); - - LocalVariableTable table = new LocalVariableTable(index,len); - - int itemLen = iter.nextU2ToInt(); - - for(int i=1; i<=itemLen; i++){ - LocalVariableItem item = new LocalVariableItem(); - item.setStartPC(iter.nextU2ToInt()); - item.setLength(iter.nextU2ToInt()); - item.setNameIndex(iter.nextU2ToInt()); - item.setDescIndex(iter.nextU2ToInt()); - item.setIndex(iter.nextU2ToInt()); - table.addLocalVariableItem(item); - } - return table; - } - - - public String toString(ConstantPool pool){ - StringBuilder buffer = new StringBuilder(); - buffer.append("Local Variable Table:\n"); - for(LocalVariableItem item : items){ - buffer.append("startPC:"+item.getStartPC()).append(","); - buffer.append("name:"+pool.getUTF8String(item.getNameIndex())).append(","); - buffer.append("desc:"+pool.getUTF8String(item.getDescIndex())).append(","); - buffer.append("slotIndex:"+ item.getIndex()).append("\n"); - } - buffer.append("\n"); - return buffer.toString(); - } -} +package com.coderising.jvm.attr; + + +import java.util.ArrayList; +import java.util.List; + +import com.coderising.jvm.constant.ConstantPool; + +import com.coderising.jvm.loader.ByteCodeIterator; + +public class LocalVariableTable extends AttributeInfo{ + + List<LocalVariableItem> items = new ArrayList<LocalVariableItem>(); + + public LocalVariableTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + + private void addLocalVariableItem(LocalVariableItem item) { + this.items.add(item); + } + + public static LocalVariableTable parse(ByteCodeIterator iter){ + + int index = iter.nextU2ToInt(); + int len = iter.nextU4ToInt(); + + LocalVariableTable table = new LocalVariableTable(index,len); + + int itemLen = iter.nextU2ToInt(); + + for(int i=1; i<=itemLen; i++){ + LocalVariableItem item = new LocalVariableItem(); + item.setStartPC(iter.nextU2ToInt()); + item.setLength(iter.nextU2ToInt()); + item.setNameIndex(iter.nextU2ToInt()); + item.setDescIndex(iter.nextU2ToInt()); + item.setIndex(iter.nextU2ToInt()); + table.addLocalVariableItem(item); + } + return table; + } + + + public String toString(ConstantPool pool){ + StringBuilder buffer = new StringBuilder(); + buffer.append("Local Variable Table:\n"); + for(LocalVariableItem item : items){ + buffer.append("startPC:"+item.getStartPC()).append(","); + buffer.append("name:"+pool.getUTF8String(item.getNameIndex())).append(","); + buffer.append("desc:"+pool.getUTF8String(item.getDescIndex())).append(","); + buffer.append("slotIndex:"+ item.getIndex()).append("\n"); + } + buffer.append("\n"); + return buffer.toString(); + } +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/attr/StackMapTable.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/attr/StackMapTable.java similarity index 95% rename from liuxin/mini-jvm/src/com/coderising/jvm/attr/StackMapTable.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/attr/StackMapTable.java index 44c5d90d46..18f2ad0360 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/attr/StackMapTable.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/attr/StackMapTable.java @@ -1,30 +1,30 @@ -package com.coderising.jvm.attr; - - -import com.coderising.jvm.loader.ByteCodeIterator; - -public class StackMapTable extends AttributeInfo{ - - private String originalCode; - - public StackMapTable(int attrNameIndex, int attrLen) { - super(attrNameIndex, attrLen); - } - - public static StackMapTable parse(ByteCodeIterator iter){ - int index = iter.nextU2ToInt(); - int len = iter.nextU4ToInt(); - StackMapTable t = new StackMapTable(index,len); - - //后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 - String code = iter.nextUxToHexString(len); - t.setOriginalCode(code); - - return t; - } - - private void setOriginalCode(String code) { - this.originalCode = code; - - } -} +package com.coderising.jvm.attr; + + +import com.coderising.jvm.loader.ByteCodeIterator; + +public class StackMapTable extends AttributeInfo{ + + private String originalCode; + + public StackMapTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static StackMapTable parse(ByteCodeIterator iter){ + int index = iter.nextU2ToInt(); + int len = iter.nextU4ToInt(); + StackMapTable t = new StackMapTable(index,len); + + //后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 + String code = iter.nextUxToHexString(len); + t.setOriginalCode(code); + + return t; + } + + private void setOriginalCode(String code) { + this.originalCode = code; + + } +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/clz/AccessFlag.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/clz/AccessFlag.java similarity index 100% rename from liuxin/mini-jvm/src/com/coderising/jvm/clz/AccessFlag.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/clz/AccessFlag.java diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/clz/ClassFile.java similarity index 96% rename from liuxin/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/clz/ClassFile.java index f91b9e48f4..58424f3c0b 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/clz/ClassFile.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/clz/ClassFile.java @@ -1,120 +1,120 @@ -package com.coderising.jvm.clz; - -import java.util.ArrayList; -import java.util.List; - -import com.coderising.jvm.constant.ClassInfo; -import com.coderising.jvm.constant.ConstantPool; -import com.coderising.jvm.field.Field; -import com.coderising.jvm.method.Method; - -public class ClassFile { - - private int minorVersion; - private int majorVersion; - - private AccessFlag accessFlag; - private ClassIndex clzIndex; - private ConstantPool pool; - private List<Field> fields = new ArrayList<Field>(); - private List<Method> methods = new ArrayList<Method>(); - - 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 addField(Field f){ - this.fields.add(f); - } - public List<Field> getFields(){ - return this.fields; - } - public void addMethod(Method m){ - this.methods.add(m); - } - public List<Method> getMethods() { - return methods; - } - - - 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()); - - - } - - public String getClassName(){ - int thisClassIndex = this.clzIndex.getThisClassIndex(); - ClassInfo thisClass = (ClassInfo)this.getConstantPool().getConstantInfo(thisClassIndex); - return thisClass.getClassName(); - } - public String getSuperClassName(){ - ClassInfo superClass = (ClassInfo)this.getConstantPool().getConstantInfo(this.clzIndex.getSuperClassIndex()); - return superClass.getClassName(); - } - - public Method getMethod(String methodName, String paramAndReturnType){ - - for(Method m :methods){ - - int nameIndex = m.getNameIndex(); - int descriptionIndex = m.getDescriptorIndex(); - - String name = this.getConstantPool().getUTF8String(nameIndex); - String desc = this.getConstantPool().getUTF8String(descriptionIndex); - if(name.equals(methodName) && desc.equals(paramAndReturnType)){ - return m; - } - } - return null; - } - public Method getMainMethod(){ - for(Method m :methods){ - int nameIndex = m.getNameIndex(); - int descIndex = m.getDescriptorIndex(); - String name = this.getConstantPool().getUTF8String(nameIndex); - String desc = this.getConstantPool().getUTF8String(descIndex); - if(name.equals("main") && desc.equals("([Ljava/lang/String;)V")){ - return m; - } - } - return null; - } -} +package com.coderising.jvm.clz; + +import java.util.ArrayList; +import java.util.List; + +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.field.Field; +import com.coderising.jvm.method.Method; + +public class ClassFile { + + private int minorVersion; + private int majorVersion; + + private AccessFlag accessFlag; + private ClassIndex clzIndex; + private ConstantPool pool; + private List<Field> fields = new ArrayList<Field>(); + private List<Method> methods = new ArrayList<Method>(); + + 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 addField(Field f){ + this.fields.add(f); + } + public List<Field> getFields(){ + return this.fields; + } + public void addMethod(Method m){ + this.methods.add(m); + } + public List<Method> getMethods() { + return methods; + } + + + 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()); + + + } + + public String getClassName(){ + int thisClassIndex = this.clzIndex.getThisClassIndex(); + ClassInfo thisClass = (ClassInfo)this.getConstantPool().getConstantInfo(thisClassIndex); + return thisClass.getClassName(); + } + public String getSuperClassName(){ + ClassInfo superClass = (ClassInfo)this.getConstantPool().getConstantInfo(this.clzIndex.getSuperClassIndex()); + return superClass.getClassName(); + } + + public Method getMethod(String methodName, String paramAndReturnType){ + + for(Method m :methods){ + + int nameIndex = m.getNameIndex(); + int descriptionIndex = m.getDescriptorIndex(); + + String name = this.getConstantPool().getUTF8String(nameIndex); + String desc = this.getConstantPool().getUTF8String(descriptionIndex); + if(name.equals(methodName) && desc.equals(paramAndReturnType)){ + return m; + } + } + return null; + } + public Method getMainMethod(){ + for(Method m :methods){ + int nameIndex = m.getNameIndex(); + int descIndex = m.getDescriptorIndex(); + String name = this.getConstantPool().getUTF8String(nameIndex); + String desc = this.getConstantPool().getUTF8String(descIndex); + if(name.equals("main") && desc.equals("([Ljava/lang/String;)V")){ + return m; + } + } + return null; + } +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/clz/ClassIndex.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/clz/ClassIndex.java similarity index 100% rename from liuxin/mini-jvm/src/com/coderising/jvm/clz/ClassIndex.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/clz/ClassIndex.java diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/BiPushCmd.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/BiPushCmd.java similarity index 95% rename from liuxin/mini-jvm/src/com/coderising/jvm/cmd/BiPushCmd.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/BiPushCmd.java index 8c15e1bd44..cd0fbd4848 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/BiPushCmd.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/BiPushCmd.java @@ -1,23 +1,23 @@ -package com.coderising.jvm.cmd; - -import com.coderising.jvm.clz.ClassFile; -import com.coderising.jvm.constant.ConstantInfo; -import com.coderising.jvm.constant.ConstantPool; - - -public class BiPushCmd extends OneOperandCmd { - - public BiPushCmd(ClassFile clzFile,String opCode) { - super(clzFile,opCode); - - } - - @Override - public String toString(ConstantPool pool) { - - return this.getOffset()+": "+ this.getOpCode()+" " + this.getReadableCodeText() + " " + this.getOperand(); - } - - - -} +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantInfo; +import com.coderising.jvm.constant.ConstantPool; + + +public class BiPushCmd extends OneOperandCmd { + + public BiPushCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + + } + + @Override + public String toString(ConstantPool pool) { + + return this.getOffset()+": "+ this.getOpCode()+" " + this.getReadableCodeText() + " " + this.getOperand(); + } + + + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/ByteCodeCommand.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/ByteCodeCommand.java similarity index 95% rename from liuxin/mini-jvm/src/com/coderising/jvm/cmd/ByteCodeCommand.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/ByteCodeCommand.java index 85f6f637d4..a3abeacc82 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/ByteCodeCommand.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/ByteCodeCommand.java @@ -1,128 +1,128 @@ -package com.coderising.jvm.cmd; - -import java.util.HashMap; -import java.util.Map; - -import com.coderising.jvm.clz.ClassFile; -import com.coderising.jvm.constant.ConstantInfo; -import com.coderising.jvm.constant.ConstantPool; - - -public abstract class ByteCodeCommand { - - String opCode; - ClassFile clzFile; - private int offset; - - private static Map<String,String> codeMap = new HashMap<String,String>(); - - static{ - codeMap.put("01", "aconst_null"); - - codeMap.put("BB", "new"); - codeMap.put("37", "lstore"); - codeMap.put("B7", "invokespecial"); - codeMap.put("B6", "invokevirtual"); - codeMap.put("B4", "getfield"); - codeMap.put("B5", "putfield"); - codeMap.put("B2", "getstatic"); - - codeMap.put("2A", "aload_0"); - codeMap.put("2B", "aload_1"); - codeMap.put("2C", "aload_2"); - - codeMap.put("10", "bipush"); - codeMap.put("15", "iload"); - codeMap.put("1A", "iload_0"); - codeMap.put("1B", "iload_1"); - codeMap.put("1C", "iload_2"); - codeMap.put("1D", "iload_3"); - - codeMap.put("25", "fload_3"); - - codeMap.put("1E", "lload_0"); - - codeMap.put("24", "fload_2"); - codeMap.put("4C", "astore_1"); - - codeMap.put("A2", "if_icmp_ge"); - codeMap.put("A4", "if_icmple"); - - codeMap.put("A7", "goto"); - - codeMap.put("B1", "return"); - codeMap.put("AC", "ireturn"); - codeMap.put("AE", "freturn"); - - codeMap.put("03", "iconst_0"); - codeMap.put("04", "iconst_1"); - - codeMap.put("3C", "istore_1"); - codeMap.put("3D", "istore_2"); - - codeMap.put("59", "dup"); - - codeMap.put("60", "iadd"); - codeMap.put("84", "iinc"); - - codeMap.put("12", "ldc"); - } - - - - - - protected ByteCodeCommand(ClassFile clzFile, String opCode){ - this.clzFile = clzFile; - this.opCode = opCode; - } - - protected ClassFile getClassFile() { - return clzFile; - } - - public int getOffset() { - return offset; - } - - public void setOffset(int offset) { - this.offset = offset; - } - protected ConstantInfo getConstantInfo(int index){ - return this.getClassFile().getConstantPool().getConstantInfo(index); - } - - protected ConstantPool getConstantPool(){ - return this.getClassFile().getConstantPool(); - } - - - - public String getOpCode() { - return opCode; - } - - public abstract int getLength(); - - - - - public String toString(){ - - StringBuffer buffer = new StringBuffer(); - buffer.append(this.opCode); - - return buffer.toString(); - } - public abstract String toString(ConstantPool pool); - - public String getReadableCodeText(){ - String txt = codeMap.get(opCode); - if(txt == null){ - return opCode; - } - return txt; - } - - //public abstract void execute(StackFrame frame,FrameResult result); -} +package com.coderising.jvm.cmd; + +import java.util.HashMap; +import java.util.Map; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantInfo; +import com.coderising.jvm.constant.ConstantPool; + + +public abstract class ByteCodeCommand { + + String opCode; + ClassFile clzFile; + private int offset; + + private static Map<String,String> codeMap = new HashMap<String,String>(); + + static{ + codeMap.put("01", "aconst_null"); + + codeMap.put("BB", "new"); + codeMap.put("37", "lstore"); + codeMap.put("B7", "invokespecial"); + codeMap.put("B6", "invokevirtual"); + codeMap.put("B4", "getfield"); + codeMap.put("B5", "putfield"); + codeMap.put("B2", "getstatic"); + + codeMap.put("2A", "aload_0"); + codeMap.put("2B", "aload_1"); + codeMap.put("2C", "aload_2"); + + codeMap.put("10", "bipush"); + codeMap.put("15", "iload"); + codeMap.put("1A", "iload_0"); + codeMap.put("1B", "iload_1"); + codeMap.put("1C", "iload_2"); + codeMap.put("1D", "iload_3"); + + codeMap.put("25", "fload_3"); + + codeMap.put("1E", "lload_0"); + + codeMap.put("24", "fload_2"); + codeMap.put("4C", "astore_1"); + + codeMap.put("A2", "if_icmp_ge"); + codeMap.put("A4", "if_icmple"); + + codeMap.put("A7", "goto"); + + codeMap.put("B1", "return"); + codeMap.put("AC", "ireturn"); + codeMap.put("AE", "freturn"); + + codeMap.put("03", "iconst_0"); + codeMap.put("04", "iconst_1"); + + codeMap.put("3C", "istore_1"); + codeMap.put("3D", "istore_2"); + + codeMap.put("59", "dup"); + + codeMap.put("60", "iadd"); + codeMap.put("84", "iinc"); + + codeMap.put("12", "ldc"); + } + + + + + + protected ByteCodeCommand(ClassFile clzFile, String opCode){ + this.clzFile = clzFile; + this.opCode = opCode; + } + + protected ClassFile getClassFile() { + return clzFile; + } + + public int getOffset() { + return offset; + } + + public void setOffset(int offset) { + this.offset = offset; + } + protected ConstantInfo getConstantInfo(int index){ + return this.getClassFile().getConstantPool().getConstantInfo(index); + } + + protected ConstantPool getConstantPool(){ + return this.getClassFile().getConstantPool(); + } + + + + public String getOpCode() { + return opCode; + } + + public abstract int getLength(); + + + + + public String toString(){ + + StringBuffer buffer = new StringBuffer(); + buffer.append(this.opCode); + + return buffer.toString(); + } + public abstract String toString(ConstantPool pool); + + public String getReadableCodeText(){ + String txt = codeMap.get(opCode); + if(txt == null){ + return opCode; + } + return txt; + } + + //public abstract void execute(StackFrame frame,FrameResult result); +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/CommandParser.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/CommandParser.java similarity index 96% rename from liuxin/mini-jvm/src/com/coderising/jvm/cmd/CommandParser.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/CommandParser.java index 0dd0573ae5..0410f9d061 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/CommandParser.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/CommandParser.java @@ -1,155 +1,155 @@ -package com.coderising.jvm.cmd; - -import java.util.ArrayList; -import java.util.List; - -import com.coderising.jvm.clz.ClassFile; - -public class CommandParser { - - public static final String aconst_null = "01"; - public static final String new_object = "BB"; - public static final String lstore = "37"; - public static final String invokespecial = "B7"; - public static final String invokevirtual = "B6"; - public static final String getfield = "B4"; - public static final String putfield = "B5"; - public static final String getstatic = "B2"; - public static final String ldc = "12"; - public static final String dup = "59"; - public static final String bipush = "10"; - public static final String aload_0 = "2A"; - public static final String aload_1 = "2B"; - public static final String aload_2 = "2C"; - public static final String iload = "15"; - public static final String iload_1 = "1B"; - public static final String iload_2 = "1C"; - public static final String iload_3 = "1D"; - public static final String fload_3 = "25"; - - public static final String voidreturn = "B1"; - public static final String ireturn = "AC"; - public static final String freturn = "AE"; - - public static final String astore_1 = "4C"; - public static final String if_icmp_ge = "A2"; - public static final String if_icmple = "A4"; - public static final String goto_no_condition = "A7"; - public static final String iconst_0 = "03"; - public static final String iconst_1 = "04"; - public static final String istore_1 = "3C"; - public static final String istore_2 = "3D"; - public static final String iadd = "60"; - public static final String iinc = "84"; - - public static ByteCodeCommand[] parse(ClassFile clzFile, String codes) { - - if ((codes == null) || (codes.length() == 0) || (codes.length() % 2) != 0) { - throw new RuntimeException("the orignal code is not correct"); - - } - - codes = codes.toUpperCase(); - - CommandIterator iter = new CommandIterator(codes); - List<ByteCodeCommand> cmds = new ArrayList<ByteCodeCommand>(); - - while (iter.hasNext()) { - String opCode = iter.next2CharAsString(); - - if (new_object.equals(opCode)) { - NewObjectCmd cmd = new NewObjectCmd(clzFile, opCode); - - cmd.setOprand1(iter.next2CharAsInt()); - cmd.setOprand2(iter.next2CharAsInt()); - - cmds.add(cmd); - } else if (invokespecial.equals(opCode)) { - InvokeSpecialCmd cmd = new InvokeSpecialCmd(clzFile, opCode); - cmd.setOprand1(iter.next2CharAsInt()); - cmd.setOprand2(iter.next2CharAsInt()); - // System.out.println( cmd.toString(clzFile.getConstPool())); - cmds.add(cmd); - } else if (invokevirtual.equals(opCode)) { - InvokeVirtualCmd cmd = new InvokeVirtualCmd(clzFile, opCode); - cmd.setOprand1(iter.next2CharAsInt()); - cmd.setOprand2(iter.next2CharAsInt()); - - cmds.add(cmd); - } else if (getfield.equals(opCode)) { - GetFieldCmd cmd = new GetFieldCmd(clzFile, opCode); - cmd.setOprand1(iter.next2CharAsInt()); - cmd.setOprand2(iter.next2CharAsInt()); - cmds.add(cmd); - } else if (getstatic.equals(opCode)) { - GetStaticFieldCmd cmd = new GetStaticFieldCmd(clzFile, opCode); - cmd.setOprand1(iter.next2CharAsInt()); - cmd.setOprand2(iter.next2CharAsInt()); - cmds.add(cmd); - } else if (putfield.equals(opCode)) { - PutFieldCmd cmd = new PutFieldCmd(clzFile, opCode); - cmd.setOprand1(iter.next2CharAsInt()); - cmd.setOprand2(iter.next2CharAsInt()); - cmds.add(cmd); - } else if (ldc.equals(opCode)) { - LdcCmd cmd = new LdcCmd(clzFile, opCode); - cmd.setOperand(iter.next2CharAsInt()); - cmds.add(cmd); - } else if (bipush.equals(opCode)) { - BiPushCmd cmd = new BiPushCmd(clzFile, opCode); - cmd.setOperand(iter.next2CharAsInt()); - cmds.add(cmd); - } else if (dup.equals(opCode) || aload_0.equals(opCode) || aload_1.equals(opCode) || aload_2.equals(opCode) - || iload_1.equals(opCode) || iload_2.equals(opCode) || iload_3.equals(opCode) - || fload_3.equals(opCode) || voidreturn.equals(opCode) || astore_1.equals(opCode)) { - - NoOperandCmd cmd = new NoOperandCmd(clzFile, opCode); - cmds.add(cmd); - } else { - throw new RuntimeException("Sorry, the java instruction " + opCode + " has not been implemented"); - } - - } - - calcuateOffset(cmds); - - ByteCodeCommand[] result = new ByteCodeCommand[cmds.size()]; - cmds.toArray(result); - return result; - } - - private static void calcuateOffset(List<ByteCodeCommand> cmds) { - - int offset = 0; - for (ByteCodeCommand cmd : cmds) { - cmd.setOffset(offset); - offset += cmd.getLength(); - } - - } - - private static class CommandIterator { - String codes = null; - int pos = 0; - - CommandIterator(String codes) { - this.codes = codes; - } - - public boolean hasNext() { - return pos < this.codes.length(); - } - - public String next2CharAsString() { - String result = codes.substring(pos, pos + 2); - pos += 2; - return result; - } - - public int next2CharAsInt() { - String s = this.next2CharAsString(); - return Integer.valueOf(s, 16).intValue(); - } - - } -} +package com.coderising.jvm.cmd; + +import java.util.ArrayList; +import java.util.List; + +import com.coderising.jvm.clz.ClassFile; + +public class CommandParser { + + public static final String aconst_null = "01"; + public static final String new_object = "BB"; + public static final String lstore = "37"; + public static final String invokespecial = "B7"; + public static final String invokevirtual = "B6"; + public static final String getfield = "B4"; + public static final String putfield = "B5"; + public static final String getstatic = "B2"; + public static final String ldc = "12"; + public static final String dup = "59"; + public static final String bipush = "10"; + public static final String aload_0 = "2A"; + public static final String aload_1 = "2B"; + public static final String aload_2 = "2C"; + public static final String iload = "15"; + public static final String iload_1 = "1B"; + public static final String iload_2 = "1C"; + public static final String iload_3 = "1D"; + public static final String fload_3 = "25"; + + public static final String voidreturn = "B1"; + public static final String ireturn = "AC"; + public static final String freturn = "AE"; + + public static final String astore_1 = "4C"; + public static final String if_icmp_ge = "A2"; + public static final String if_icmple = "A4"; + public static final String goto_no_condition = "A7"; + public static final String iconst_0 = "03"; + public static final String iconst_1 = "04"; + public static final String istore_1 = "3C"; + public static final String istore_2 = "3D"; + public static final String iadd = "60"; + public static final String iinc = "84"; + + public static ByteCodeCommand[] parse(ClassFile clzFile, String codes) { + + if ((codes == null) || (codes.length() == 0) || (codes.length() % 2) != 0) { + throw new RuntimeException("the orignal code is not correct"); + + } + + codes = codes.toUpperCase(); + + CommandIterator iter = new CommandIterator(codes); + List<ByteCodeCommand> cmds = new ArrayList<ByteCodeCommand>(); + + while (iter.hasNext()) { + String opCode = iter.next2CharAsString(); + + if (new_object.equals(opCode)) { + NewObjectCmd cmd = new NewObjectCmd(clzFile, opCode); + + cmd.setOprand1(iter.next2CharAsInt()); + cmd.setOprand2(iter.next2CharAsInt()); + + cmds.add(cmd); + } else if (invokespecial.equals(opCode)) { + InvokeSpecialCmd cmd = new InvokeSpecialCmd(clzFile, opCode); + cmd.setOprand1(iter.next2CharAsInt()); + cmd.setOprand2(iter.next2CharAsInt()); + // System.out.println( cmd.toString(clzFile.getConstPool())); + cmds.add(cmd); + } else if (invokevirtual.equals(opCode)) { + InvokeVirtualCmd cmd = new InvokeVirtualCmd(clzFile, opCode); + cmd.setOprand1(iter.next2CharAsInt()); + cmd.setOprand2(iter.next2CharAsInt()); + + cmds.add(cmd); + } else if (getfield.equals(opCode)) { + GetFieldCmd cmd = new GetFieldCmd(clzFile, opCode); + cmd.setOprand1(iter.next2CharAsInt()); + cmd.setOprand2(iter.next2CharAsInt()); + cmds.add(cmd); + } else if (getstatic.equals(opCode)) { + GetStaticFieldCmd cmd = new GetStaticFieldCmd(clzFile, opCode); + cmd.setOprand1(iter.next2CharAsInt()); + cmd.setOprand2(iter.next2CharAsInt()); + cmds.add(cmd); + } else if (putfield.equals(opCode)) { + PutFieldCmd cmd = new PutFieldCmd(clzFile, opCode); + cmd.setOprand1(iter.next2CharAsInt()); + cmd.setOprand2(iter.next2CharAsInt()); + cmds.add(cmd); + } else if (ldc.equals(opCode)) { + LdcCmd cmd = new LdcCmd(clzFile, opCode); + cmd.setOperand(iter.next2CharAsInt()); + cmds.add(cmd); + } else if (bipush.equals(opCode)) { + BiPushCmd cmd = new BiPushCmd(clzFile, opCode); + cmd.setOperand(iter.next2CharAsInt()); + cmds.add(cmd); + } else if (dup.equals(opCode) || aload_0.equals(opCode) || aload_1.equals(opCode) || aload_2.equals(opCode) + || iload_1.equals(opCode) || iload_2.equals(opCode) || iload_3.equals(opCode) + || fload_3.equals(opCode) || voidreturn.equals(opCode) || astore_1.equals(opCode)) { + + NoOperandCmd cmd = new NoOperandCmd(clzFile, opCode); + cmds.add(cmd); + } else { + throw new RuntimeException("Sorry, the java instruction " + opCode + " has not been implemented"); + } + + } + + calcuateOffset(cmds); + + ByteCodeCommand[] result = new ByteCodeCommand[cmds.size()]; + cmds.toArray(result); + return result; + } + + private static void calcuateOffset(List<ByteCodeCommand> cmds) { + + int offset = 0; + for (ByteCodeCommand cmd : cmds) { + cmd.setOffset(offset); + offset += cmd.getLength(); + } + + } + + private static class CommandIterator { + String codes = null; + int pos = 0; + + CommandIterator(String codes) { + this.codes = codes; + } + + public boolean hasNext() { + return pos < this.codes.length(); + } + + public String next2CharAsString() { + String result = codes.substring(pos, pos + 2); + pos += 2; + return result; + } + + public int next2CharAsInt() { + String s = this.next2CharAsString(); + return Integer.valueOf(s, 16).intValue(); + } + + } +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/GetFieldCmd.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/GetFieldCmd.java similarity index 94% rename from liuxin/mini-jvm/src/com/coderising/jvm/cmd/GetFieldCmd.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/GetFieldCmd.java index 4d989d6cbb..2e6061edd2 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/GetFieldCmd.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/GetFieldCmd.java @@ -1,22 +1,22 @@ -package com.coderising.jvm.cmd; - -import com.coderising.jvm.clz.ClassFile; -import com.coderising.jvm.constant.ConstantPool; - - -public class GetFieldCmd extends TwoOperandCmd { - - public GetFieldCmd(ClassFile clzFile,String opCode) { - super(clzFile,opCode); - } - - @Override - public String toString(ConstantPool pool) { - - return super.getOperandAsField(pool); - } - - - - -} +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; + + +public class GetFieldCmd extends TwoOperandCmd { + + public GetFieldCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsField(pool); + } + + + + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/GetStaticFieldCmd.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/GetStaticFieldCmd.java similarity index 95% rename from liuxin/mini-jvm/src/com/coderising/jvm/cmd/GetStaticFieldCmd.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/GetStaticFieldCmd.java index 9fb13677eb..e6cf9d5960 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/GetStaticFieldCmd.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/GetStaticFieldCmd.java @@ -1,23 +1,23 @@ -package com.coderising.jvm.cmd; - -import com.coderising.jvm.clz.ClassFile; -import com.coderising.jvm.constant.ClassInfo; -import com.coderising.jvm.constant.ConstantPool; -import com.coderising.jvm.constant.FieldRefInfo; -import com.coderising.jvm.constant.UTF8Info; - - -public class GetStaticFieldCmd extends TwoOperandCmd { - - public GetStaticFieldCmd(ClassFile clzFile,String opCode) { - super(clzFile,opCode); - - } - - @Override - public String toString(ConstantPool pool) { - - return super.getOperandAsField(pool); - } - -} +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.FieldRefInfo; +import com.coderising.jvm.constant.UTF8Info; + + +public class GetStaticFieldCmd extends TwoOperandCmd { + + public GetStaticFieldCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsField(pool); + } + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/InvokeSpecialCmd.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/InvokeSpecialCmd.java similarity index 94% rename from liuxin/mini-jvm/src/com/coderising/jvm/cmd/InvokeSpecialCmd.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/InvokeSpecialCmd.java index 5ac3454be7..ac228d0e4d 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/InvokeSpecialCmd.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/InvokeSpecialCmd.java @@ -1,23 +1,23 @@ -package com.coderising.jvm.cmd; - -import com.coderising.jvm.clz.ClassFile; -import com.coderising.jvm.constant.ConstantPool; -import com.coderising.jvm.constant.MethodRefInfo; - - -public class InvokeSpecialCmd extends TwoOperandCmd { - - public InvokeSpecialCmd(ClassFile clzFile,String opCode) { - super(clzFile,opCode); - - } - - @Override - public String toString(ConstantPool pool) { - - return super.getOperandAsMethod(pool); - } - - - -} +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.MethodRefInfo; + + +public class InvokeSpecialCmd extends TwoOperandCmd { + + public InvokeSpecialCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsMethod(pool); + } + + + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/InvokeVirtualCmd.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/InvokeVirtualCmd.java similarity index 94% rename from liuxin/mini-jvm/src/com/coderising/jvm/cmd/InvokeVirtualCmd.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/InvokeVirtualCmd.java index 303a64b4c7..c15d827797 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/InvokeVirtualCmd.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/InvokeVirtualCmd.java @@ -1,22 +1,22 @@ -package com.coderising.jvm.cmd; - -import com.coderising.jvm.clz.ClassFile; -import com.coderising.jvm.constant.ConstantPool; - - -public class InvokeVirtualCmd extends TwoOperandCmd { - - public InvokeVirtualCmd(ClassFile clzFile,String opCode) { - super(clzFile,opCode); - } - - @Override - public String toString(ConstantPool pool) { - - return super.getOperandAsMethod(pool); - } - - - - -} +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; + + +public class InvokeVirtualCmd extends TwoOperandCmd { + + public InvokeVirtualCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsMethod(pool); + } + + + + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/LdcCmd.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/LdcCmd.java similarity index 96% rename from liuxin/mini-jvm/src/com/coderising/jvm/cmd/LdcCmd.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/LdcCmd.java index 00f9a5a699..ffb66f811c 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/LdcCmd.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/LdcCmd.java @@ -1,29 +1,29 @@ -package com.coderising.jvm.cmd; - -import com.coderising.jvm.clz.ClassFile; -import com.coderising.jvm.constant.ConstantInfo; -import com.coderising.jvm.constant.ConstantPool; -import com.coderising.jvm.constant.StringInfo; - -public class LdcCmd extends OneOperandCmd { - - public LdcCmd(ClassFile clzFile,String opCode) { - super(clzFile,opCode); - } - - @Override - public String toString(ConstantPool pool) { - - ConstantInfo info = (ConstantInfo)pool.getConstantInfo(this.getOperand()); - - String value = "TBD"; - if(info instanceof StringInfo){ - StringInfo strInfo = (StringInfo)info; - value = strInfo.toString(); - } - - return this.getOffset()+":"+this.getOpCode()+" " + this.getReadableCodeText() + " "+ value; - - } - -} +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantInfo; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.StringInfo; + +public class LdcCmd extends OneOperandCmd { + + public LdcCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + ConstantInfo info = (ConstantInfo)pool.getConstantInfo(this.getOperand()); + + String value = "TBD"; + if(info instanceof StringInfo){ + StringInfo strInfo = (StringInfo)info; + value = strInfo.toString(); + } + + return this.getOffset()+":"+this.getOpCode()+" " + this.getReadableCodeText() + " "+ value; + + } + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/NewObjectCmd.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/NewObjectCmd.java similarity index 95% rename from liuxin/mini-jvm/src/com/coderising/jvm/cmd/NewObjectCmd.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/NewObjectCmd.java index a43c8bd964..33813b5d59 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/NewObjectCmd.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/NewObjectCmd.java @@ -1,19 +1,19 @@ -package com.coderising.jvm.cmd; - -import com.coderising.jvm.clz.ClassFile; -import com.coderising.jvm.constant.ConstantPool; - -public class NewObjectCmd extends TwoOperandCmd{ - - public NewObjectCmd(ClassFile clzFile, String opCode){ - super(clzFile,opCode); - } - - @Override - public String toString(ConstantPool pool) { - - return super.getOperandAsClassInfo(pool); - } - - -} +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; + +public class NewObjectCmd extends TwoOperandCmd{ + + public NewObjectCmd(ClassFile clzFile, String opCode){ + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsClassInfo(pool); + } + + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/NoOperandCmd.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/NoOperandCmd.java similarity index 95% rename from liuxin/mini-jvm/src/com/coderising/jvm/cmd/NoOperandCmd.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/NoOperandCmd.java index 92e5c4f3f1..56c28fefe2 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/NoOperandCmd.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/NoOperandCmd.java @@ -1,23 +1,23 @@ -package com.coderising.jvm.cmd; - -import com.coderising.jvm.clz.ClassFile; -import com.coderising.jvm.constant.ConstantPool; - -public class NoOperandCmd extends ByteCodeCommand{ - - public NoOperandCmd(ClassFile clzFile, String opCode) { - super(clzFile, opCode); - } - - @Override - public String toString(ConstantPool pool) { - return this.getOffset()+":" +this.getOpCode() + " "+ this.getReadableCodeText(); - } - - - - public int getLength(){ - return 1; - } - -} +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; + +public class NoOperandCmd extends ByteCodeCommand{ + + public NoOperandCmd(ClassFile clzFile, String opCode) { + super(clzFile, opCode); + } + + @Override + public String toString(ConstantPool pool) { + return this.getOffset()+":" +this.getOpCode() + " "+ this.getReadableCodeText(); + } + + + + public int getLength(){ + return 1; + } + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/OneOperandCmd.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/OneOperandCmd.java similarity index 94% rename from liuxin/mini-jvm/src/com/coderising/jvm/cmd/OneOperandCmd.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/OneOperandCmd.java index 6b1b8c284c..963d064257 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/OneOperandCmd.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/OneOperandCmd.java @@ -1,27 +1,27 @@ -package com.coderising.jvm.cmd; - -import com.coderising.jvm.clz.ClassFile; - -public abstract class OneOperandCmd extends ByteCodeCommand { - - private int operand; - - public OneOperandCmd(ClassFile clzFile,String opCode) { - super(clzFile, opCode); - - } - public int getOperand() { - - return this.operand; - } - - public void setOperand(int oprand1) { - this.operand = oprand1; - - } - public int getLength(){ - return 2; - } - - -} +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; + +public abstract class OneOperandCmd extends ByteCodeCommand { + + private int operand; + + public OneOperandCmd(ClassFile clzFile,String opCode) { + super(clzFile, opCode); + + } + public int getOperand() { + + return this.operand; + } + + public void setOperand(int oprand1) { + this.operand = oprand1; + + } + public int getLength(){ + return 2; + } + + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/PutFieldCmd.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/PutFieldCmd.java similarity index 95% rename from liuxin/mini-jvm/src/com/coderising/jvm/cmd/PutFieldCmd.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/PutFieldCmd.java index 00b29e1fbc..85bb369c19 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/PutFieldCmd.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/PutFieldCmd.java @@ -1,19 +1,19 @@ -package com.coderising.jvm.cmd; - -import com.coderising.jvm.clz.ClassFile; -import com.coderising.jvm.constant.ConstantPool; - -public class PutFieldCmd extends TwoOperandCmd { - - public PutFieldCmd(ClassFile clzFile,String opCode) { - super(clzFile,opCode); - } - - @Override - public String toString(ConstantPool pool) { - - return super.getOperandAsField(pool); - } - - -} +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; + +public class PutFieldCmd extends TwoOperandCmd { + + public PutFieldCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsField(pool); + } + + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/TwoOperandCmd.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/TwoOperandCmd.java similarity index 96% rename from liuxin/mini-jvm/src/com/coderising/jvm/cmd/TwoOperandCmd.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/TwoOperandCmd.java index 334eec9f98..6c0cf53082 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/cmd/TwoOperandCmd.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/cmd/TwoOperandCmd.java @@ -1,67 +1,67 @@ -package com.coderising.jvm.cmd; - -import com.coderising.jvm.clz.ClassFile; -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; - -public abstract class TwoOperandCmd extends ByteCodeCommand{ - - int oprand1 = -1; - int oprand2 = -1; - - public int getOprand1() { - return oprand1; - } - - public void setOprand1(int oprand1) { - this.oprand1 = oprand1; - } - - public void setOprand2(int oprand2) { - this.oprand2 = oprand2; - } - - public int getOprand2() { - return oprand2; - } - - public TwoOperandCmd(ClassFile clzFile,String opCode) { - super(clzFile, opCode); - } - - public int getIndex(){ - int oprand1 = this.getOprand1(); - int oprand2 = this.getOprand2(); - int index = oprand1 << 8 | oprand2; - return index; - } - - protected String getOperandAsClassInfo(ConstantPool pool){ - int index = getIndex(); - String codeTxt = getReadableCodeText(); - ClassInfo info = (ClassInfo)pool.getConstantInfo(index); - return this.getOffset()+":"+this.getOpCode()+" "+ codeTxt +" "+ info.getClassName(); - } - - protected String getOperandAsMethod(ConstantPool pool){ - int index = getIndex(); - String codeTxt = getReadableCodeText(); - ConstantInfo constInfo = this.getConstantInfo(index); - MethodRefInfo info = (MethodRefInfo)this.getConstantInfo(index); - return this.getOffset()+":"+this.getOpCode()+" " + codeTxt +" "+ info.toString(); - } - - protected String getOperandAsField(ConstantPool pool){ - int index = getIndex(); - - String codeTxt = getReadableCodeText(); - FieldRefInfo info = (FieldRefInfo)this.getConstantInfo(index); - return this.getOffset()+":"+this.getOpCode()+" " + codeTxt +" "+ info.toString(); - } - public int getLength(){ - return 3; - } -} +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +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; + +public abstract class TwoOperandCmd extends ByteCodeCommand{ + + int oprand1 = -1; + int oprand2 = -1; + + public int getOprand1() { + return oprand1; + } + + public void setOprand1(int oprand1) { + this.oprand1 = oprand1; + } + + public void setOprand2(int oprand2) { + this.oprand2 = oprand2; + } + + public int getOprand2() { + return oprand2; + } + + public TwoOperandCmd(ClassFile clzFile,String opCode) { + super(clzFile, opCode); + } + + public int getIndex(){ + int oprand1 = this.getOprand1(); + int oprand2 = this.getOprand2(); + int index = oprand1 << 8 | oprand2; + return index; + } + + protected String getOperandAsClassInfo(ConstantPool pool){ + int index = getIndex(); + String codeTxt = getReadableCodeText(); + ClassInfo info = (ClassInfo)pool.getConstantInfo(index); + return this.getOffset()+":"+this.getOpCode()+" "+ codeTxt +" "+ info.getClassName(); + } + + protected String getOperandAsMethod(ConstantPool pool){ + int index = getIndex(); + String codeTxt = getReadableCodeText(); + ConstantInfo constInfo = this.getConstantInfo(index); + MethodRefInfo info = (MethodRefInfo)this.getConstantInfo(index); + return this.getOffset()+":"+this.getOpCode()+" " + codeTxt +" "+ info.toString(); + } + + protected String getOperandAsField(ConstantPool pool){ + int index = getIndex(); + + String codeTxt = getReadableCodeText(); + FieldRefInfo info = (FieldRefInfo)this.getConstantInfo(index); + return this.getOffset()+":"+this.getOpCode()+" " + codeTxt +" "+ info.toString(); + } + public int getLength(){ + return 3; + } +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/constant/ClassInfo.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/constant/ClassInfo.java similarity index 100% rename from liuxin/mini-jvm/src/com/coderising/jvm/constant/ClassInfo.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/constant/ClassInfo.java diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/constant/ConstantInfo.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/constant/ConstantInfo.java similarity index 100% rename from liuxin/mini-jvm/src/com/coderising/jvm/constant/ConstantInfo.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/constant/ConstantInfo.java diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/constant/ConstantPool.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/constant/ConstantPool.java similarity index 100% rename from liuxin/mini-jvm/src/com/coderising/jvm/constant/ConstantPool.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/constant/ConstantPool.java diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/constant/FieldRefInfo.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/constant/FieldRefInfo.java similarity index 100% rename from liuxin/mini-jvm/src/com/coderising/jvm/constant/FieldRefInfo.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/constant/FieldRefInfo.java diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/constant/MethodRefInfo.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/constant/MethodRefInfo.java similarity index 100% rename from liuxin/mini-jvm/src/com/coderising/jvm/constant/MethodRefInfo.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/constant/MethodRefInfo.java diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/constant/NameAndTypeInfo.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/constant/NameAndTypeInfo.java similarity index 100% rename from liuxin/mini-jvm/src/com/coderising/jvm/constant/NameAndTypeInfo.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/constant/NameAndTypeInfo.java diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/constant/NullConstantInfo.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/constant/NullConstantInfo.java similarity index 100% rename from liuxin/mini-jvm/src/com/coderising/jvm/constant/NullConstantInfo.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/constant/NullConstantInfo.java diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/constant/StringInfo.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/constant/StringInfo.java similarity index 100% rename from liuxin/mini-jvm/src/com/coderising/jvm/constant/StringInfo.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/constant/StringInfo.java diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/constant/UTF8Info.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/constant/UTF8Info.java similarity index 100% rename from liuxin/mini-jvm/src/com/coderising/jvm/constant/UTF8Info.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/constant/UTF8Info.java diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/field/Field.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/field/Field.java similarity index 96% rename from liuxin/mini-jvm/src/com/coderising/jvm/field/Field.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/field/Field.java index 0267f3145e..c6eb0196f8 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/field/Field.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/field/Field.java @@ -1,50 +1,50 @@ -package com.coderising.jvm.field; - -import com.coderising.jvm.constant.ConstantPool; -import com.coderising.jvm.constant.UTF8Info; -import com.coderising.jvm.loader.ByteCodeIterator; - - -public class Field { - private int accessFlag; - private int nameIndex; - private int descriptorIndex; - - - - private ConstantPool pool; - - public Field( int accessFlag, int nameIndex, int descriptorIndex,ConstantPool pool) { - - this.accessFlag = accessFlag; - this.nameIndex = nameIndex; - this.descriptorIndex = descriptorIndex; - this.pool = pool; - } - - public String toString() { - String name = ((UTF8Info)pool.getConstantInfo(this.nameIndex)).getValue(); - - String desc = ((UTF8Info)pool.getConstantInfo(this.descriptorIndex)).getValue(); - return name +":"+ desc; - } - - - public static Field parse(ConstantPool pool,ByteCodeIterator iter){ - - int accessFlag = iter.nextU2ToInt(); - int nameIndex = iter.nextU2ToInt(); - int descIndex = iter.nextU2ToInt(); - int attribCount = iter.nextU2ToInt(); - //System.out.println("field attribute count:"+ attribCount); - - Field f = new Field(accessFlag, nameIndex, descIndex,pool); - - if(attribCount > 0){ - throw new RuntimeException("Field Attribute has not been implemented"); - } - - return f; - } - -} +package com.coderising.jvm.field; + +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.UTF8Info; +import com.coderising.jvm.loader.ByteCodeIterator; + + +public class Field { + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + + + private ConstantPool pool; + + public Field( int accessFlag, int nameIndex, int descriptorIndex,ConstantPool pool) { + + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + this.pool = pool; + } + + public String toString() { + String name = ((UTF8Info)pool.getConstantInfo(this.nameIndex)).getValue(); + + String desc = ((UTF8Info)pool.getConstantInfo(this.descriptorIndex)).getValue(); + return name +":"+ desc; + } + + + public static Field parse(ConstantPool pool,ByteCodeIterator iter){ + + int accessFlag = iter.nextU2ToInt(); + int nameIndex = iter.nextU2ToInt(); + int descIndex = iter.nextU2ToInt(); + int attribCount = iter.nextU2ToInt(); + //System.out.println("field attribute count:"+ attribCount); + + Field f = new Field(accessFlag, nameIndex, descIndex,pool); + + if(attribCount > 0){ + throw new RuntimeException("Field Attribute has not been implemented"); + } + + return f; + } + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/loader/ByteCodeIterator.java similarity index 95% rename from liuxin/mini-jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/loader/ByteCodeIterator.java index 5c5173fbe8..6fb5570dff 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/loader/ByteCodeIterator.java @@ -1,57 +1,57 @@ -package com.coderising.jvm.loader; - -import java.util.Arrays; - -import com.coderising.jvm.util.Util; - -public class ByteCodeIterator { - byte[] codes; - int pos = 0; - - ByteCodeIterator(byte[] codes) { - this.codes = codes; - } - - - - 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; - } - - 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 nextUxToHexString(int len) { - byte[] tmp = new byte[len]; - - for (int i = 0; i < len; i++) { - tmp[i] = codes[pos++]; - } - return Util.byteToHexString(tmp).toLowerCase(); - - } - - public void back(int n) { - this.pos -= n; - } -} +package com.coderising.jvm.loader; + +import java.util.Arrays; + +import com.coderising.jvm.util.Util; + +public class ByteCodeIterator { + byte[] codes; + int pos = 0; + + ByteCodeIterator(byte[] codes) { + this.codes = codes; + } + + + + 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; + } + + 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 nextUxToHexString(int len) { + byte[] tmp = new byte[len]; + + for (int i = 0; i < len; i++) { + tmp[i] = codes[pos++]; + } + return Util.byteToHexString(tmp).toLowerCase(); + + } + + public void back(int n) { + this.pos -= n; + } +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/loader/ClassFileLoader.java similarity index 94% rename from liuxin/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/loader/ClassFileLoader.java index 9ff27b16cf..33185d8175 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/loader/ClassFileLoader.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/loader/ClassFileLoader.java @@ -1,140 +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<String> clzPaths = new ArrayList<String>(); - - 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; - - } - - - - +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<String> clzPaths = new ArrayList<String>(); + + 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/liuxin/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/loader/ClassFileParser.java similarity index 96% rename from liuxin/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/loader/ClassFileParser.java index 4b258706c8..5bf7a220f7 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/loader/ClassFileParser.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/loader/ClassFileParser.java @@ -1,171 +1,171 @@ -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; -import com.coderising.jvm.field.Field; -import com.coderising.jvm.method.Method; - -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); - - AccessFlag flag = parseAccessFlag(iter); - clzFile.setAccessFlag(flag); - - ClassIndex clzIndex = parseClassInfex(iter); - clzFile.setClassIndex(clzIndex); - - parseInterfaces(iter); - - parseFileds(clzFile, iter); - - parseMethods(clzFile, iter); - - return clzFile; - } - - private AccessFlag parseAccessFlag(ByteCodeIterator iter) { - - AccessFlag flag = new AccessFlag(iter.nextU2ToInt()); - - return flag; - } - - private ClassIndex parseClassInfex(ByteCodeIterator iter) { - - int thisClassIndex = iter.nextU2ToInt(); - int superClassIndex = iter.nextU2ToInt(); - - ClassIndex clzIndex = new ClassIndex(); - - clzIndex.setThisClassIndex(thisClassIndex); - clzIndex.setSuperClassIndex(superClassIndex); - - return clzIndex; - - } - - private ConstantPool parseConstantPool(ByteCodeIterator iter) { - - int constPoolCount = iter.nextU2ToInt(); - - //System.out.println("Constant Pool Count :" + constPoolCount); - - ConstantPool pool = new ConstantPool(); - - 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); - - pool.addConstantInfo(clzInfo); - } else if (tag == 1) { - // UTF-8 String - int len = iter.nextU2ToInt(); - byte[] data = iter.getBytes(len); - String value = null; - try { - value = new String(data, "UTF-8"); - } catch (UnsupportedEncodingException e) { - 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) { - // MethodRef - MethodRefInfo method = new MethodRefInfo(pool); - method.setClassInfoIndex(iter.nextU2ToInt()); - method.setNameAndTypeIndex(iter.nextU2ToInt()); - pool.addConstantInfo(method); - } else if (tag == 12) { - // Name and Type Info - NameAndTypeInfo nameType = new NameAndTypeInfo(pool); - nameType.setIndex1(iter.nextU2ToInt()); - nameType.setIndex2(iter.nextU2ToInt()); - pool.addConstantInfo(nameType); - } else { - throw new RuntimeException("the constant pool tag " + tag + " has not been implemented yet."); - } - } - - System.out.println("Finished reading Constant pool "); - - return pool; - } - private void parseInterfaces(ByteCodeIterator iter) { - int interfaceCount = iter.nextU2ToInt(); - - System.out.println("interfaceCount:" + interfaceCount); - - // TODO : 如果实现了interface, 这里需要解析 - } - - private void parseFileds(ClassFile clzFile, ByteCodeIterator iter) { - int fieldCount = iter.nextU2ToInt(); - - for (int i = 1; i <= fieldCount; i++) { - Field f = Field.parse(clzFile.getConstantPool(), iter); - clzFile.addField(f); - } - - } - - private void parseMethods(ClassFile clzFile, ByteCodeIterator iter) { - - int methodCount = iter.nextU2ToInt(); - - for (int i = 1; i <= methodCount; i++) { - Method m = Method.parse(clzFile, iter); - clzFile.addMethod(m); - } - - } - -} +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; +import com.coderising.jvm.field.Field; +import com.coderising.jvm.method.Method; + +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); + + AccessFlag flag = parseAccessFlag(iter); + clzFile.setAccessFlag(flag); + + ClassIndex clzIndex = parseClassInfex(iter); + clzFile.setClassIndex(clzIndex); + + parseInterfaces(iter); + + parseFileds(clzFile, iter); + + parseMethods(clzFile, iter); + + return clzFile; + } + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + + AccessFlag flag = new AccessFlag(iter.nextU2ToInt()); + + return flag; + } + + private ClassIndex parseClassInfex(ByteCodeIterator iter) { + + int thisClassIndex = iter.nextU2ToInt(); + int superClassIndex = iter.nextU2ToInt(); + + ClassIndex clzIndex = new ClassIndex(); + + clzIndex.setThisClassIndex(thisClassIndex); + clzIndex.setSuperClassIndex(superClassIndex); + + return clzIndex; + + } + + private ConstantPool parseConstantPool(ByteCodeIterator iter) { + + int constPoolCount = iter.nextU2ToInt(); + + //System.out.println("Constant Pool Count :" + constPoolCount); + + ConstantPool pool = new ConstantPool(); + + 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); + + pool.addConstantInfo(clzInfo); + } else if (tag == 1) { + // UTF-8 String + int len = iter.nextU2ToInt(); + byte[] data = iter.getBytes(len); + String value = null; + try { + value = new String(data, "UTF-8"); + } catch (UnsupportedEncodingException e) { + 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) { + // MethodRef + MethodRefInfo method = new MethodRefInfo(pool); + method.setClassInfoIndex(iter.nextU2ToInt()); + method.setNameAndTypeIndex(iter.nextU2ToInt()); + pool.addConstantInfo(method); + } else if (tag == 12) { + // Name and Type Info + NameAndTypeInfo nameType = new NameAndTypeInfo(pool); + nameType.setIndex1(iter.nextU2ToInt()); + nameType.setIndex2(iter.nextU2ToInt()); + pool.addConstantInfo(nameType); + } else { + throw new RuntimeException("the constant pool tag " + tag + " has not been implemented yet."); + } + } + + System.out.println("Finished reading Constant pool "); + + return pool; + } + private void parseInterfaces(ByteCodeIterator iter) { + int interfaceCount = iter.nextU2ToInt(); + + System.out.println("interfaceCount:" + interfaceCount); + + // TODO : 如果实现了interface, 这里需要解析 + } + + private void parseFileds(ClassFile clzFile, ByteCodeIterator iter) { + int fieldCount = iter.nextU2ToInt(); + + for (int i = 1; i <= fieldCount; i++) { + Field f = Field.parse(clzFile.getConstantPool(), iter); + clzFile.addField(f); + } + + } + + private void parseMethods(ClassFile clzFile, ByteCodeIterator iter) { + + int methodCount = iter.nextU2ToInt(); + + for (int i = 1; i <= methodCount; i++) { + Method m = Method.parse(clzFile, iter); + clzFile.addMethod(m); + } + + } + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/method/Method.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/method/Method.java similarity index 95% rename from liuxin/mini-jvm/src/com/coderising/jvm/method/Method.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/method/Method.java index 74f5ae8c16..71ab6ab053 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/method/Method.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/method/Method.java @@ -1,103 +1,103 @@ -package com.coderising.jvm.method; - -import com.coderising.jvm.clz.ClassFile; -import com.coderising.jvm.cmd.ByteCodeCommand; -import com.coderising.jvm.attr.AttributeInfo; -import com.coderising.jvm.attr.CodeAttr; -import com.coderising.jvm.constant.ConstantPool; -import com.coderising.jvm.constant.UTF8Info; -import com.coderising.jvm.loader.ByteCodeIterator; - - - -public class Method { - - private int accessFlag; - private int nameIndex; - private int descriptorIndex; - - private CodeAttr codeAttr; - - private ClassFile clzFile; - - - public ClassFile getClzFile() { - return clzFile; - } - - public int getNameIndex() { - return nameIndex; - } - public int getDescriptorIndex() { - return descriptorIndex; - } - - public CodeAttr getCodeAttr() { - return codeAttr; - } - - public void setCodeAttr(CodeAttr code) { - this.codeAttr = code; - } - - - - public Method(ClassFile clzFile,int accessFlag, int nameIndex, int descriptorIndex) { - this.clzFile = clzFile; - this.accessFlag = accessFlag; - this.nameIndex = nameIndex; - this.descriptorIndex = descriptorIndex; - } - - - - - -public String toString() { - - ConstantPool pool = this.clzFile.getConstantPool(); - StringBuilder buffer = new StringBuilder(); - - String name = ((UTF8Info)pool.getConstantInfo(this.nameIndex)).getValue(); - - String desc = ((UTF8Info)pool.getConstantInfo(this.descriptorIndex)).getValue(); - - buffer.append(name).append(":").append(desc).append("\n"); - - buffer.append(this.codeAttr.toString(pool)); - - return buffer.toString(); - } - - public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ - int accessFlag = iter.nextU2ToInt(); - int nameIndex = iter.nextU2ToInt(); - int descIndex = iter.nextU2ToInt(); - int attribCount = iter.nextU2ToInt(); - - - Method m = new Method(clzFile, accessFlag, nameIndex, descIndex); - - for( int j=1; j<= attribCount; j++){ - - int attrNameIndex = iter.nextU2ToInt(); - String attrName = clzFile.getConstantPool().getUTF8String(attrNameIndex); - iter.back(2); - - if(AttributeInfo.CODE.equalsIgnoreCase(attrName)){ - CodeAttr codeAttr = CodeAttr.parse(clzFile, iter); - m.setCodeAttr(codeAttr); - } else{ - throw new RuntimeException("only CODE attribute is implemented , please implement the "+ attrName); - } - - } - - return m ; - - } - - public ByteCodeCommand[] getCmds() { - return this.getCodeAttr().getCmds(); - } -} +package com.coderising.jvm.method; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.cmd.ByteCodeCommand; +import com.coderising.jvm.attr.AttributeInfo; +import com.coderising.jvm.attr.CodeAttr; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.UTF8Info; +import com.coderising.jvm.loader.ByteCodeIterator; + + + +public class Method { + + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private CodeAttr codeAttr; + + private ClassFile clzFile; + + + public ClassFile getClzFile() { + return clzFile; + } + + public int getNameIndex() { + return nameIndex; + } + public int getDescriptorIndex() { + return descriptorIndex; + } + + public CodeAttr getCodeAttr() { + return codeAttr; + } + + public void setCodeAttr(CodeAttr code) { + this.codeAttr = code; + } + + + + public Method(ClassFile clzFile,int accessFlag, int nameIndex, int descriptorIndex) { + this.clzFile = clzFile; + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + } + + + + + +public String toString() { + + ConstantPool pool = this.clzFile.getConstantPool(); + StringBuilder buffer = new StringBuilder(); + + String name = ((UTF8Info)pool.getConstantInfo(this.nameIndex)).getValue(); + + String desc = ((UTF8Info)pool.getConstantInfo(this.descriptorIndex)).getValue(); + + buffer.append(name).append(":").append(desc).append("\n"); + + buffer.append(this.codeAttr.toString(pool)); + + return buffer.toString(); + } + + public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ + int accessFlag = iter.nextU2ToInt(); + int nameIndex = iter.nextU2ToInt(); + int descIndex = iter.nextU2ToInt(); + int attribCount = iter.nextU2ToInt(); + + + Method m = new Method(clzFile, accessFlag, nameIndex, descIndex); + + for( int j=1; j<= attribCount; j++){ + + int attrNameIndex = iter.nextU2ToInt(); + String attrName = clzFile.getConstantPool().getUTF8String(attrNameIndex); + iter.back(2); + + if(AttributeInfo.CODE.equalsIgnoreCase(attrName)){ + CodeAttr codeAttr = CodeAttr.parse(clzFile, iter); + m.setCodeAttr(codeAttr); + } else{ + throw new RuntimeException("only CODE attribute is implemented , please implement the "+ attrName); + } + + } + + return m ; + + } + + public ByteCodeCommand[] getCmds() { + return this.getCodeAttr().getCmds(); + } +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/print/ClassFilePrinter.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/print/ClassFilePrinter.java similarity index 96% rename from liuxin/mini-jvm/src/com/coderising/jvm/print/ClassFilePrinter.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/print/ClassFilePrinter.java index d1579dba28..14407bacbe 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/print/ClassFilePrinter.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/print/ClassFilePrinter.java @@ -1,54 +1,54 @@ -package com.coderising.jvm.print; - -import com.coderising.jvm.clz.ClassFile; -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.StringInfo; -import com.coderising.jvm.constant.UTF8Info; -import com.coderising.jvm.loader.ClassFileLoader; - -public class ClassFilePrinter { - ClassFile clzFile = null; - public ClassFilePrinter(ClassFile clzFile){ - this.clzFile = clzFile; - } - - public void print(){ - - if(clzFile.getAccessFlag().isPublicClass()){ - System.out.println("Access flag : public "); - } - System.out.println("Class Name:"+ clzFile.getClassName()); - - System.out.println("Super Class Name:"+ clzFile.getSuperClassName()); - - System.out.println("minor version:" + clzFile.getMinorVersion()); - - System.out.println("major version:" + clzFile.getMinorVersion()); - - ConstantPoolPrinter cnstPoolPrinter = new ConstantPoolPrinter(clzFile.getConstantPool()); - cnstPoolPrinter.print(); - - - - - } - - public static void main(String[] args){ - String path = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\mini-jvm\\bin"; - ClassFileLoader loader = new ClassFileLoader(); - loader.addClassPath(path); - String className = "com.coderising.jvm.test.EmployeeV1"; - - ClassFile clzFile = loader.loadClass(className); - - ClassFilePrinter printer = new ClassFilePrinter(clzFile); - - printer.print(); - } -} +package com.coderising.jvm.print; + +import com.coderising.jvm.clz.ClassFile; +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.StringInfo; +import com.coderising.jvm.constant.UTF8Info; +import com.coderising.jvm.loader.ClassFileLoader; + +public class ClassFilePrinter { + ClassFile clzFile = null; + public ClassFilePrinter(ClassFile clzFile){ + this.clzFile = clzFile; + } + + public void print(){ + + if(clzFile.getAccessFlag().isPublicClass()){ + System.out.println("Access flag : public "); + } + System.out.println("Class Name:"+ clzFile.getClassName()); + + System.out.println("Super Class Name:"+ clzFile.getSuperClassName()); + + System.out.println("minor version:" + clzFile.getMinorVersion()); + + System.out.println("major version:" + clzFile.getMinorVersion()); + + ConstantPoolPrinter cnstPoolPrinter = new ConstantPoolPrinter(clzFile.getConstantPool()); + cnstPoolPrinter.print(); + + + + + } + + public static void main(String[] args){ + String path = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\mini-jvm\\bin"; + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path); + String className = "com.coderising.jvm.test.EmployeeV1"; + + ClassFile clzFile = loader.loadClass(className); + + ClassFilePrinter printer = new ClassFilePrinter(clzFile); + + printer.print(); + } +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/print/ConstantPoolPrinter.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/print/ConstantPoolPrinter.java similarity index 96% rename from liuxin/mini-jvm/src/com/coderising/jvm/print/ConstantPoolPrinter.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/print/ConstantPoolPrinter.java index 923c2270c5..b1301725ec 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/print/ConstantPoolPrinter.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/print/ConstantPoolPrinter.java @@ -1,83 +1,83 @@ -package com.coderising.jvm.print; - -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.StringInfo; -import com.coderising.jvm.constant.UTF8Info; - -public class ConstantPoolPrinter { - ConstantPool pool; - ConstantPoolPrinter(ConstantPool pool){ - this.pool = pool; - } - public void print(){ - - System.out.println("Constant Pool:"); - - ConstantInfo.Visitor visitor = new ConstantInfo.Visitor() { - - @Override - public void visitString(StringInfo info) { - StringBuilder buffer = new StringBuilder(); - buffer.append("String #").append(info.getIndex()); - System.out.println(buffer); - - } - - @Override - public void visitNameAndType(NameAndTypeInfo info) { - StringBuilder buffer = new StringBuilder(); - buffer.append("NameAndType #").append(info.getIndex1()).append(":#") - .append(info.getIndex2()); - System.out.println(buffer); - - } - - @Override - public void visitMethodRef(MethodRefInfo info) { - StringBuilder buffer = new StringBuilder(); - buffer.append("MethodRef #").append(info.getClassInfoIndex()).append(".#") - .append(info.getNameAndTypeIndex()); - System.out.println(buffer); - - } - - @Override - public void visitFieldRef(FieldRefInfo info) { - StringBuilder buffer = new StringBuilder(); - buffer.append("FieldRef #").append(info.getClassInfoIndex()).append(".#") - .append(info.getNameAndTypeIndex()); - System.out.println(buffer); - - } - - @Override - public void visitClassInfo(ClassInfo info) { - StringBuilder buffer = new StringBuilder(); - buffer.append("Class #").append(info.getUtf8Index()) - .append(" ").append(info.getClassName()); - - System.out.println(buffer); - - } - - @Override - public void visistUTF8(UTF8Info info) { - StringBuilder buffer = new StringBuilder(); - buffer.append("UTF8 ").append(info.getValue()); - System.out.println(buffer); - - } - }; - - for(int i=1; i<=pool.getSize(); i++){ - ConstantInfo constantInfo = pool.getConstantInfo(i); - System.out.print("#"+i+"="); - constantInfo.accept(visitor); - } - } -} +package com.coderising.jvm.print; + +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.StringInfo; +import com.coderising.jvm.constant.UTF8Info; + +public class ConstantPoolPrinter { + ConstantPool pool; + ConstantPoolPrinter(ConstantPool pool){ + this.pool = pool; + } + public void print(){ + + System.out.println("Constant Pool:"); + + ConstantInfo.Visitor visitor = new ConstantInfo.Visitor() { + + @Override + public void visitString(StringInfo info) { + StringBuilder buffer = new StringBuilder(); + buffer.append("String #").append(info.getIndex()); + System.out.println(buffer); + + } + + @Override + public void visitNameAndType(NameAndTypeInfo info) { + StringBuilder buffer = new StringBuilder(); + buffer.append("NameAndType #").append(info.getIndex1()).append(":#") + .append(info.getIndex2()); + System.out.println(buffer); + + } + + @Override + public void visitMethodRef(MethodRefInfo info) { + StringBuilder buffer = new StringBuilder(); + buffer.append("MethodRef #").append(info.getClassInfoIndex()).append(".#") + .append(info.getNameAndTypeIndex()); + System.out.println(buffer); + + } + + @Override + public void visitFieldRef(FieldRefInfo info) { + StringBuilder buffer = new StringBuilder(); + buffer.append("FieldRef #").append(info.getClassInfoIndex()).append(".#") + .append(info.getNameAndTypeIndex()); + System.out.println(buffer); + + } + + @Override + public void visitClassInfo(ClassInfo info) { + StringBuilder buffer = new StringBuilder(); + buffer.append("Class #").append(info.getUtf8Index()) + .append(" ").append(info.getClassName()); + + System.out.println(buffer); + + } + + @Override + public void visistUTF8(UTF8Info info) { + StringBuilder buffer = new StringBuilder(); + buffer.append("UTF8 ").append(info.getValue()); + System.out.println(buffer); + + } + }; + + for(int i=1; i<=pool.getSize(); i++){ + ConstantInfo constantInfo = pool.getConstantInfo(i); + System.out.print("#"+i+"="); + constantInfo.accept(visitor); + } + } +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/print/ConstantPoolPrinterBad.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/print/ConstantPoolPrinterBad.java similarity index 96% rename from liuxin/mini-jvm/src/com/coderising/jvm/print/ConstantPoolPrinterBad.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/print/ConstantPoolPrinterBad.java index c674b23e00..1198f6b773 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/print/ConstantPoolPrinterBad.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/print/ConstantPoolPrinterBad.java @@ -1,40 +1,40 @@ -package com.coderising.jvm.print; - -import com.coderising.jvm.constant.ClassInfo; -import com.coderising.jvm.constant.ConstantInfo; -import com.coderising.jvm.constant.ConstantPool; -import com.coderising.jvm.constant.UTF8Info; - -public class ConstantPoolPrinterBad { - ConstantPool pool; - ConstantPoolPrinterBad(ConstantPool pool){ - this.pool = pool; - } - public void print(){ - - System.out.println("Constant Pool:"); - - for(int i=1; i<=pool.getSize(); i++){ - ConstantInfo cnstInfo = pool.getConstantInfo(i); - - System.out.print("#"+i+"="); - if(cnstInfo instanceof ClassInfo){ - ClassInfo info = (ClassInfo)cnstInfo; - // Class #2 com/coderising/jvm/test/EmployeeV1 - StringBuilder buffer = new StringBuilder(); - buffer.append("Class #").append(info.getUtf8Index()) - .append(" ").append(info.getClassName()); - - System.out.println(buffer); - } - if(cnstInfo instanceof UTF8Info){ - //UTF8 com/coderising/jvm/test/EmployeeV1 - UTF8Info info = (UTF8Info)cnstInfo; - StringBuilder buffer = new StringBuilder(); - buffer.append("UTF8 ").append(info.getValue()); - System.out.println(buffer); - } - //其他的if else - } - } -} +package com.coderising.jvm.print; + +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantInfo; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.UTF8Info; + +public class ConstantPoolPrinterBad { + ConstantPool pool; + ConstantPoolPrinterBad(ConstantPool pool){ + this.pool = pool; + } + public void print(){ + + System.out.println("Constant Pool:"); + + for(int i=1; i<=pool.getSize(); i++){ + ConstantInfo cnstInfo = pool.getConstantInfo(i); + + System.out.print("#"+i+"="); + if(cnstInfo instanceof ClassInfo){ + ClassInfo info = (ClassInfo)cnstInfo; + // Class #2 com/coderising/jvm/test/EmployeeV1 + StringBuilder buffer = new StringBuilder(); + buffer.append("Class #").append(info.getUtf8Index()) + .append(" ").append(info.getClassName()); + + System.out.println(buffer); + } + if(cnstInfo instanceof UTF8Info){ + //UTF8 com/coderising/jvm/test/EmployeeV1 + UTF8Info info = (UTF8Info)cnstInfo; + StringBuilder buffer = new StringBuilder(); + buffer.append("UTF8 ").append(info.getValue()); + System.out.println(buffer); + } + //其他的if else + } + } +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/test/ClassFileloaderTest.java similarity index 96% rename from liuxin/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/test/ClassFileloaderTest.java index b26dd457d8..5657310e0d 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/test/ClassFileloaderTest.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -1,354 +1,354 @@ -package com.coderising.jvm.test; - -import java.util.List; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import com.coderising.jvm.clz.ClassFile; -import com.coderising.jvm.clz.ClassIndex; -import com.coderising.jvm.cmd.BiPushCmd; -import com.coderising.jvm.cmd.ByteCodeCommand; -import com.coderising.jvm.cmd.OneOperandCmd; -import com.coderising.jvm.cmd.TwoOperandCmd; -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.field.Field; -import com.coderising.jvm.loader.ClassFileLoader; -import com.coderising.jvm.method.Method; - - - - - -public class ClassFileloaderTest { - - - private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; - - static String path1 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\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); - - } - - - @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(); - } - - /** - * ---------------------------------------------------------------------- - */ - - - @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("<init>", 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()); - } - - /** - * 下面是第三次JVM课应实现的测试用例 - */ - @Test - public void testReadFields(){ - - List<Field> fields = clzFile.getFields(); - Assert.assertEquals(2, fields.size()); - { - Field f = fields.get(0); - Assert.assertEquals("name:Ljava/lang/String;", f.toString()); - } - { - Field f = fields.get(1); - Assert.assertEquals("age:I", f.toString()); - } - } - @Test - public void testMethods(){ - - List<Method> methods = clzFile.getMethods(); - ConstantPool pool = clzFile.getConstantPool(); - - { - Method m = methods.get(0); - assertMethodEquals(pool,m, - "<init>", - "(Ljava/lang/String;I)V", - "2ab7000c2a2bb5000f2a1cb50011b1"); - - } - { - Method m = methods.get(1); - assertMethodEquals(pool,m, - "setName", - "(Ljava/lang/String;)V", - "2a2bb5000fb1"); - - } - { - Method m = methods.get(2); - assertMethodEquals(pool,m, - "setAge", - "(I)V", - "2a1bb50011b1"); - } - { - Method m = methods.get(3); - assertMethodEquals(pool,m, - "sayHello", - "()V", - "b2001c1222b60024b1"); - - } - { - Method m = methods.get(4); - assertMethodEquals(pool,m, - "main", - "([Ljava/lang/String;)V", - "bb000159122b101db7002d4c2bb6002fb1"); - } - } - - private void assertMethodEquals(ConstantPool pool,Method m , String expectedName, String expectedDesc,String expectedCode){ - String methodName = pool.getUTF8String(m.getNameIndex()); - String methodDesc = pool.getUTF8String(m.getDescriptorIndex()); - String code = m.getCodeAttr().getCode(); - Assert.assertEquals(expectedName, methodName); - Assert.assertEquals(expectedDesc, methodDesc); - Assert.assertEquals(expectedCode, code); - } - - @Test - public void testByteCodeCommand(){ - { - Method initMethod = this.clzFile.getMethod("<init>", "(Ljava/lang/String;I)V"); - ByteCodeCommand [] cmds = initMethod.getCmds(); - - assertOpCodeEquals("0: aload_0", cmds[0]); - assertOpCodeEquals("1: invokespecial #12", cmds[1]); - assertOpCodeEquals("4: aload_0", cmds[2]); - assertOpCodeEquals("5: aload_1", cmds[3]); - assertOpCodeEquals("6: putfield #15", cmds[4]); - assertOpCodeEquals("9: aload_0", cmds[5]); - assertOpCodeEquals("10: iload_2", cmds[6]); - assertOpCodeEquals("11: putfield #17", cmds[7]); - assertOpCodeEquals("14: return", cmds[8]); - } - - { - Method setNameMethod = this.clzFile.getMethod("setName", "(Ljava/lang/String;)V"); - ByteCodeCommand [] cmds = setNameMethod.getCmds(); - - assertOpCodeEquals("0: aload_0", cmds[0]); - assertOpCodeEquals("1: aload_1", cmds[1]); - assertOpCodeEquals("2: putfield #15", cmds[2]); - assertOpCodeEquals("5: return", cmds[3]); - - } - - { - Method sayHelloMethod = this.clzFile.getMethod("sayHello", "()V"); - ByteCodeCommand [] cmds = sayHelloMethod.getCmds(); - - assertOpCodeEquals("0: getstatic #28", cmds[0]); - assertOpCodeEquals("3: ldc #34", cmds[1]); - assertOpCodeEquals("5: invokevirtual #36", cmds[2]); - assertOpCodeEquals("8: return", cmds[3]); - - } - - { - Method mainMethod = this.clzFile.getMainMethod(); - - ByteCodeCommand [] cmds = mainMethod.getCmds(); - - assertOpCodeEquals("0: new #1", cmds[0]); - assertOpCodeEquals("3: dup", cmds[1]); - assertOpCodeEquals("4: ldc #43", cmds[2]); - assertOpCodeEquals("6: bipush 29", cmds[3]); - assertOpCodeEquals("8: invokespecial #45", cmds[4]); - assertOpCodeEquals("11: astore_1", cmds[5]); - assertOpCodeEquals("12: aload_1", cmds[6]); - assertOpCodeEquals("13: invokevirtual #47", cmds[7]); - assertOpCodeEquals("16: return", cmds[8]); - } - - } - - private void assertOpCodeEquals(String expected, ByteCodeCommand cmd){ - - String acctual = cmd.getOffset()+": "+cmd.getReadableCodeText(); - - if(cmd instanceof OneOperandCmd){ - if(cmd instanceof BiPushCmd){ - acctual += " " + ((OneOperandCmd)cmd).getOperand(); - } else{ - acctual += " #" + ((OneOperandCmd)cmd).getOperand(); - } - } - if(cmd instanceof TwoOperandCmd){ - acctual += " #" + ((TwoOperandCmd)cmd).getIndex(); - } - Assert.assertEquals(expected, acctual); - } - -} +package com.coderising.jvm.test; + +import java.util.List; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.clz.ClassIndex; +import com.coderising.jvm.cmd.BiPushCmd; +import com.coderising.jvm.cmd.ByteCodeCommand; +import com.coderising.jvm.cmd.OneOperandCmd; +import com.coderising.jvm.cmd.TwoOperandCmd; +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.field.Field; +import com.coderising.jvm.loader.ClassFileLoader; +import com.coderising.jvm.method.Method; + + + + + +public class ClassFileloaderTest { + + + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + + static String path1 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\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); + + } + + + @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(); + } + + /** + * ---------------------------------------------------------------------- + */ + + + @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("<init>", 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()); + } + + /** + * 下面是第三次JVM课应实现的测试用例 + */ + @Test + public void testReadFields(){ + + List<Field> fields = clzFile.getFields(); + Assert.assertEquals(2, fields.size()); + { + Field f = fields.get(0); + Assert.assertEquals("name:Ljava/lang/String;", f.toString()); + } + { + Field f = fields.get(1); + Assert.assertEquals("age:I", f.toString()); + } + } + @Test + public void testMethods(){ + + List<Method> methods = clzFile.getMethods(); + ConstantPool pool = clzFile.getConstantPool(); + + { + Method m = methods.get(0); + assertMethodEquals(pool,m, + "<init>", + "(Ljava/lang/String;I)V", + "2ab7000c2a2bb5000f2a1cb50011b1"); + + } + { + Method m = methods.get(1); + assertMethodEquals(pool,m, + "setName", + "(Ljava/lang/String;)V", + "2a2bb5000fb1"); + + } + { + Method m = methods.get(2); + assertMethodEquals(pool,m, + "setAge", + "(I)V", + "2a1bb50011b1"); + } + { + Method m = methods.get(3); + assertMethodEquals(pool,m, + "sayHello", + "()V", + "b2001c1222b60024b1"); + + } + { + Method m = methods.get(4); + assertMethodEquals(pool,m, + "main", + "([Ljava/lang/String;)V", + "bb000159122b101db7002d4c2bb6002fb1"); + } + } + + private void assertMethodEquals(ConstantPool pool,Method m , String expectedName, String expectedDesc,String expectedCode){ + String methodName = pool.getUTF8String(m.getNameIndex()); + String methodDesc = pool.getUTF8String(m.getDescriptorIndex()); + String code = m.getCodeAttr().getCode(); + Assert.assertEquals(expectedName, methodName); + Assert.assertEquals(expectedDesc, methodDesc); + Assert.assertEquals(expectedCode, code); + } + + @Test + public void testByteCodeCommand(){ + { + Method initMethod = this.clzFile.getMethod("<init>", "(Ljava/lang/String;I)V"); + ByteCodeCommand [] cmds = initMethod.getCmds(); + + assertOpCodeEquals("0: aload_0", cmds[0]); + assertOpCodeEquals("1: invokespecial #12", cmds[1]); + assertOpCodeEquals("4: aload_0", cmds[2]); + assertOpCodeEquals("5: aload_1", cmds[3]); + assertOpCodeEquals("6: putfield #15", cmds[4]); + assertOpCodeEquals("9: aload_0", cmds[5]); + assertOpCodeEquals("10: iload_2", cmds[6]); + assertOpCodeEquals("11: putfield #17", cmds[7]); + assertOpCodeEquals("14: return", cmds[8]); + } + + { + Method setNameMethod = this.clzFile.getMethod("setName", "(Ljava/lang/String;)V"); + ByteCodeCommand [] cmds = setNameMethod.getCmds(); + + assertOpCodeEquals("0: aload_0", cmds[0]); + assertOpCodeEquals("1: aload_1", cmds[1]); + assertOpCodeEquals("2: putfield #15", cmds[2]); + assertOpCodeEquals("5: return", cmds[3]); + + } + + { + Method sayHelloMethod = this.clzFile.getMethod("sayHello", "()V"); + ByteCodeCommand [] cmds = sayHelloMethod.getCmds(); + + assertOpCodeEquals("0: getstatic #28", cmds[0]); + assertOpCodeEquals("3: ldc #34", cmds[1]); + assertOpCodeEquals("5: invokevirtual #36", cmds[2]); + assertOpCodeEquals("8: return", cmds[3]); + + } + + { + Method mainMethod = this.clzFile.getMainMethod(); + + ByteCodeCommand [] cmds = mainMethod.getCmds(); + + assertOpCodeEquals("0: new #1", cmds[0]); + assertOpCodeEquals("3: dup", cmds[1]); + assertOpCodeEquals("4: ldc #43", cmds[2]); + assertOpCodeEquals("6: bipush 29", cmds[3]); + assertOpCodeEquals("8: invokespecial #45", cmds[4]); + assertOpCodeEquals("11: astore_1", cmds[5]); + assertOpCodeEquals("12: aload_1", cmds[6]); + assertOpCodeEquals("13: invokevirtual #47", cmds[7]); + assertOpCodeEquals("16: return", cmds[8]); + } + + } + + private void assertOpCodeEquals(String expected, ByteCodeCommand cmd){ + + String acctual = cmd.getOffset()+": "+cmd.getReadableCodeText(); + + if(cmd instanceof OneOperandCmd){ + if(cmd instanceof BiPushCmd){ + acctual += " " + ((OneOperandCmd)cmd).getOperand(); + } else{ + acctual += " #" + ((OneOperandCmd)cmd).getOperand(); + } + } + if(cmd instanceof TwoOperandCmd){ + acctual += " #" + ((TwoOperandCmd)cmd).getIndex(); + } + Assert.assertEquals(expected, acctual); + } + +} diff --git a/liuxin/mini-jvm/src/com/coderising/jvm/test/EmployeeV1.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/test/EmployeeV1.java similarity index 95% rename from liuxin/mini-jvm/src/com/coderising/jvm/test/EmployeeV1.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/test/EmployeeV1.java index 9a36573dd3..12e3d7efdd 100644 --- a/liuxin/mini-jvm/src/com/coderising/jvm/test/EmployeeV1.java +++ b/liuxin/mini-jvm/answer/src/com/coderising/jvm/test/EmployeeV1.java @@ -1,28 +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(); - - } +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/liuxin/mini-jvm/src/com/coderising/jvm/util/Util.java b/liuxin/mini-jvm/answer/src/com/coderising/jvm/util/Util.java similarity index 100% rename from liuxin/mini-jvm/src/com/coderising/jvm/util/Util.java rename to liuxin/mini-jvm/answer/src/com/coderising/jvm/util/Util.java diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/attr/AttributeInfo.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/attr/AttributeInfo.java new file mode 100644 index 0000000000..88f60c77f6 --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/attr/AttributeInfo.java @@ -0,0 +1,19 @@ +package com.coderising.jvm.attr; + +public abstract class AttributeInfo { + public static final String CODE = "Code"; + public static final String CONST_VALUE = "ConstantValue"; + public static final String EXCEPTIONS = "Exceptions"; + public static final String LINE_NUM_TABLE = "LineNumberTable"; + public static final String LOCAL_VAR_TABLE = "LocalVariableTable"; + public static final String STACK_MAP_TABLE = "StackMapTable"; + int attrNameIndex; + int attrLen ; + public AttributeInfo(int attrNameIndex, int attrLen) { + + this.attrNameIndex = attrNameIndex; + this.attrLen = attrLen; + } + + +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/attr/CodeAttr.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/attr/CodeAttr.java new file mode 100644 index 0000000000..c4c0c4c6c5 --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/attr/CodeAttr.java @@ -0,0 +1,70 @@ +package com.coderising.jvm.attr; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.cmd.ByteCodeCommand; +import com.coderising.jvm.cmd.CommandParser; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.loader.ByteCodeIterator; + + +public class CodeAttr extends AttributeInfo { + private int maxStack ; + private int maxLocals ; + private int codeLen ; + private String code; + public String getCode() { + return code; + } + + private ByteCodeCommand[] cmds ; + public ByteCodeCommand[] getCmds() { + return cmds; + } + private LineNumberTable lineNumTable; + private LocalVariableTable localVarTable; + private StackMapTable stackMapTable; + + public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen,String code ,ByteCodeCommand[] cmds) { + super(attrNameIndex, attrLen); + this.maxStack = maxStack; + this.maxLocals = maxLocals; + this.codeLen = codeLen; + this.code = code; + this.cmds = cmds; + } + + public void setLineNumberTable(LineNumberTable t) { + this.lineNumTable = t; + } + + public void setLocalVariableTable(LocalVariableTable t) { + this.localVarTable = t; + } + + public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ + + return null; + } + + + public String toString(ConstantPool pool){ + StringBuilder buffer = new StringBuilder(); + //buffer.append("Code:").append(code).append("\n"); + for(int i=0;i<cmds.length;i++){ + buffer.append(cmds[i].toString(pool)).append("\n"); + } + buffer.append("\n"); + buffer.append(this.lineNumTable.toString()); + buffer.append(this.localVarTable.toString(pool)); + return buffer.toString(); + } + private void setStackMapTable(StackMapTable t) { + this.stackMapTable = t; + + } + + + + + +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/attr/LineNumberTable.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/attr/LineNumberTable.java new file mode 100644 index 0000000000..a31a1ff4d0 --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/attr/LineNumberTable.java @@ -0,0 +1,55 @@ +package com.coderising.jvm.attr; + +import java.util.ArrayList; +import java.util.List; + + +import com.coderising.jvm.loader.ByteCodeIterator; + +public class LineNumberTable extends AttributeInfo { + List<LineNumberItem> items = new ArrayList<LineNumberItem>(); + + private static class LineNumberItem{ + int startPC; + int lineNum; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLineNum() { + return lineNum; + } + public void setLineNum(int lineNum) { + this.lineNum = lineNum; + } + } + public void addLineNumberItem(LineNumberItem item){ + this.items.add(item); + } + public LineNumberTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + + } + + public static LineNumberTable parse(ByteCodeIterator iter){ + + return null; + } + + public String toString(){ + StringBuilder buffer = new StringBuilder(); + buffer.append("Line Number Table:\n"); + for(LineNumberItem item : items){ + buffer.append("startPC:"+item.getStartPC()).append(","); + buffer.append("lineNum:"+item.getLineNum()).append("\n"); + } + buffer.append("\n"); + return buffer.toString(); + + } + + + +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/attr/LocalVariableItem.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/attr/LocalVariableItem.java new file mode 100644 index 0000000000..962c3b8bc4 --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/attr/LocalVariableItem.java @@ -0,0 +1,39 @@ +package com.coderising.jvm.attr; + +public class LocalVariableItem { + private int startPC; + private int length; + private int nameIndex; + private int descIndex; + private int index; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getNameIndex() { + return nameIndex; + } + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + public int getDescIndex() { + return descIndex; + } + public void setDescIndex(int descIndex) { + this.descIndex = descIndex; + } + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/attr/LocalVariableTable.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/attr/LocalVariableTable.java new file mode 100644 index 0000000000..14db5dca46 --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/attr/LocalVariableTable.java @@ -0,0 +1,42 @@ +package com.coderising.jvm.attr; + + +import java.util.ArrayList; +import java.util.List; + +import com.coderising.jvm.constant.ConstantPool; + +import com.coderising.jvm.loader.ByteCodeIterator; + +public class LocalVariableTable extends AttributeInfo{ + + List<LocalVariableItem> items = new ArrayList<LocalVariableItem>(); + + public LocalVariableTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + + private void addLocalVariableItem(LocalVariableItem item) { + this.items.add(item); + } + + public static LocalVariableTable parse(ByteCodeIterator iter){ + + return null; + } + + + public String toString(ConstantPool pool){ + StringBuilder buffer = new StringBuilder(); + buffer.append("Local Variable Table:\n"); + for(LocalVariableItem item : items){ + buffer.append("startPC:"+item.getStartPC()).append(","); + buffer.append("name:"+pool.getUTF8String(item.getNameIndex())).append(","); + buffer.append("desc:"+pool.getUTF8String(item.getDescIndex())).append(","); + buffer.append("slotIndex:"+ item.getIndex()).append("\n"); + } + buffer.append("\n"); + return buffer.toString(); + } +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/attr/StackMapTable.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/attr/StackMapTable.java new file mode 100644 index 0000000000..18f2ad0360 --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/attr/StackMapTable.java @@ -0,0 +1,30 @@ +package com.coderising.jvm.attr; + + +import com.coderising.jvm.loader.ByteCodeIterator; + +public class StackMapTable extends AttributeInfo{ + + private String originalCode; + + public StackMapTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static StackMapTable parse(ByteCodeIterator iter){ + int index = iter.nextU2ToInt(); + int len = iter.nextU4ToInt(); + StackMapTable t = new StackMapTable(index,len); + + //后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 + String code = iter.nextUxToHexString(len); + t.setOriginalCode(code); + + return t; + } + + private void setOriginalCode(String code) { + this.originalCode = code; + + } +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/clz/AccessFlag.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..faae056835 --- /dev/null +++ b/liuxin/mini-jvm/assignment/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/liuxin/mini-jvm/assignment/src/com/coderising/jvm/clz/ClassFile.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..2a8dfb6123 --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/clz/ClassFile.java @@ -0,0 +1,102 @@ +package com.coderising.jvm.clz; + +import java.util.ArrayList; +import java.util.List; + +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.field.Field; +import com.coderising.jvm.method.Method; + +public class ClassFile { + + private int minorVersion; + private int majorVersion; + + private AccessFlag accessFlag; + private ClassIndex clzIndex; + private ConstantPool pool; + private List<Field> fields = new ArrayList<Field>(); + private List<Method> methods = new ArrayList<Method>(); + + 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 addField(Field f){ + this.fields.add(f); + } + public List<Field> getFields(){ + return this.fields; + } + public void addMethod(Method m){ + this.methods.add(m); + } + public List<Method> getMethods() { + return methods; + } + + + 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()); + + + } + + public String getClassName(){ + int thisClassIndex = this.clzIndex.getThisClassIndex(); + ClassInfo thisClass = (ClassInfo)this.getConstantPool().getConstantInfo(thisClassIndex); + return thisClass.getClassName(); + } + public String getSuperClassName(){ + ClassInfo superClass = (ClassInfo)this.getConstantPool().getConstantInfo(this.clzIndex.getSuperClassIndex()); + return superClass.getClassName(); + } + + public Method getMethod(String methodName, String paramAndReturnType){ + + + return null; + } + public Method getMainMethod(){ + + return null; + } +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/clz/ClassIndex.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..e424f284b3 --- /dev/null +++ b/liuxin/mini-jvm/assignment/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/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/BiPushCmd.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/BiPushCmd.java new file mode 100644 index 0000000000..cd0fbd4848 --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/BiPushCmd.java @@ -0,0 +1,23 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantInfo; +import com.coderising.jvm.constant.ConstantPool; + + +public class BiPushCmd extends OneOperandCmd { + + public BiPushCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + + } + + @Override + public String toString(ConstantPool pool) { + + return this.getOffset()+": "+ this.getOpCode()+" " + this.getReadableCodeText() + " " + this.getOperand(); + } + + + +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/ByteCodeCommand.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/ByteCodeCommand.java new file mode 100644 index 0000000000..a3abeacc82 --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/ByteCodeCommand.java @@ -0,0 +1,128 @@ +package com.coderising.jvm.cmd; + +import java.util.HashMap; +import java.util.Map; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantInfo; +import com.coderising.jvm.constant.ConstantPool; + + +public abstract class ByteCodeCommand { + + String opCode; + ClassFile clzFile; + private int offset; + + private static Map<String,String> codeMap = new HashMap<String,String>(); + + static{ + codeMap.put("01", "aconst_null"); + + codeMap.put("BB", "new"); + codeMap.put("37", "lstore"); + codeMap.put("B7", "invokespecial"); + codeMap.put("B6", "invokevirtual"); + codeMap.put("B4", "getfield"); + codeMap.put("B5", "putfield"); + codeMap.put("B2", "getstatic"); + + codeMap.put("2A", "aload_0"); + codeMap.put("2B", "aload_1"); + codeMap.put("2C", "aload_2"); + + codeMap.put("10", "bipush"); + codeMap.put("15", "iload"); + codeMap.put("1A", "iload_0"); + codeMap.put("1B", "iload_1"); + codeMap.put("1C", "iload_2"); + codeMap.put("1D", "iload_3"); + + codeMap.put("25", "fload_3"); + + codeMap.put("1E", "lload_0"); + + codeMap.put("24", "fload_2"); + codeMap.put("4C", "astore_1"); + + codeMap.put("A2", "if_icmp_ge"); + codeMap.put("A4", "if_icmple"); + + codeMap.put("A7", "goto"); + + codeMap.put("B1", "return"); + codeMap.put("AC", "ireturn"); + codeMap.put("AE", "freturn"); + + codeMap.put("03", "iconst_0"); + codeMap.put("04", "iconst_1"); + + codeMap.put("3C", "istore_1"); + codeMap.put("3D", "istore_2"); + + codeMap.put("59", "dup"); + + codeMap.put("60", "iadd"); + codeMap.put("84", "iinc"); + + codeMap.put("12", "ldc"); + } + + + + + + protected ByteCodeCommand(ClassFile clzFile, String opCode){ + this.clzFile = clzFile; + this.opCode = opCode; + } + + protected ClassFile getClassFile() { + return clzFile; + } + + public int getOffset() { + return offset; + } + + public void setOffset(int offset) { + this.offset = offset; + } + protected ConstantInfo getConstantInfo(int index){ + return this.getClassFile().getConstantPool().getConstantInfo(index); + } + + protected ConstantPool getConstantPool(){ + return this.getClassFile().getConstantPool(); + } + + + + public String getOpCode() { + return opCode; + } + + public abstract int getLength(); + + + + + public String toString(){ + + StringBuffer buffer = new StringBuffer(); + buffer.append(this.opCode); + + return buffer.toString(); + } + public abstract String toString(ConstantPool pool); + + public String getReadableCodeText(){ + String txt = codeMap.get(opCode); + if(txt == null){ + return opCode; + } + return txt; + } + + //public abstract void execute(StackFrame frame,FrameResult result); +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/CommandParser.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/CommandParser.java new file mode 100644 index 0000000000..2bb36340f5 --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/CommandParser.java @@ -0,0 +1,85 @@ +package com.coderising.jvm.cmd; + +import java.util.ArrayList; +import java.util.List; + +import com.coderising.jvm.clz.ClassFile; + +public class CommandParser { + + public static final String aconst_null = "01"; + public static final String new_object = "BB"; + public static final String lstore = "37"; + public static final String invokespecial = "B7"; + public static final String invokevirtual = "B6"; + public static final String getfield = "B4"; + public static final String putfield = "B5"; + public static final String getstatic = "B2"; + public static final String ldc = "12"; + public static final String dup = "59"; + public static final String bipush = "10"; + public static final String aload_0 = "2A"; + public static final String aload_1 = "2B"; + public static final String aload_2 = "2C"; + public static final String iload = "15"; + public static final String iload_1 = "1B"; + public static final String iload_2 = "1C"; + public static final String iload_3 = "1D"; + public static final String fload_3 = "25"; + + public static final String voidreturn = "B1"; + public static final String ireturn = "AC"; + public static final String freturn = "AE"; + + public static final String astore_1 = "4C"; + public static final String if_icmp_ge = "A2"; + public static final String if_icmple = "A4"; + public static final String goto_no_condition = "A7"; + public static final String iconst_0 = "03"; + public static final String iconst_1 = "04"; + public static final String istore_1 = "3C"; + public static final String istore_2 = "3D"; + public static final String iadd = "60"; + public static final String iinc = "84"; + + public static ByteCodeCommand[] parse(ClassFile clzFile, String codes) { + + + return null; + } + + private static void calcuateOffset(List<ByteCodeCommand> cmds) { + + int offset = 0; + for (ByteCodeCommand cmd : cmds) { + cmd.setOffset(offset); + offset += cmd.getLength(); + } + + } + + private static class CommandIterator { + String codes = null; + int pos = 0; + + CommandIterator(String codes) { + this.codes = codes; + } + + public boolean hasNext() { + return pos < this.codes.length(); + } + + public String next2CharAsString() { + String result = codes.substring(pos, pos + 2); + pos += 2; + return result; + } + + public int next2CharAsInt() { + String s = this.next2CharAsString(); + return Integer.valueOf(s, 16).intValue(); + } + + } +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/GetFieldCmd.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/GetFieldCmd.java new file mode 100644 index 0000000000..2e6061edd2 --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/GetFieldCmd.java @@ -0,0 +1,22 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; + + +public class GetFieldCmd extends TwoOperandCmd { + + public GetFieldCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsField(pool); + } + + + + +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/GetStaticFieldCmd.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/GetStaticFieldCmd.java new file mode 100644 index 0000000000..e6cf9d5960 --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/GetStaticFieldCmd.java @@ -0,0 +1,23 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.FieldRefInfo; +import com.coderising.jvm.constant.UTF8Info; + + +public class GetStaticFieldCmd extends TwoOperandCmd { + + public GetStaticFieldCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsField(pool); + } + +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/InvokeSpecialCmd.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/InvokeSpecialCmd.java new file mode 100644 index 0000000000..ac228d0e4d --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/InvokeSpecialCmd.java @@ -0,0 +1,23 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.MethodRefInfo; + + +public class InvokeSpecialCmd extends TwoOperandCmd { + + public InvokeSpecialCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsMethod(pool); + } + + + +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/InvokeVirtualCmd.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/InvokeVirtualCmd.java new file mode 100644 index 0000000000..c15d827797 --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/InvokeVirtualCmd.java @@ -0,0 +1,22 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; + + +public class InvokeVirtualCmd extends TwoOperandCmd { + + public InvokeVirtualCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsMethod(pool); + } + + + + +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/LdcCmd.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/LdcCmd.java new file mode 100644 index 0000000000..ffb66f811c --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/LdcCmd.java @@ -0,0 +1,29 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantInfo; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.StringInfo; + +public class LdcCmd extends OneOperandCmd { + + public LdcCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + ConstantInfo info = (ConstantInfo)pool.getConstantInfo(this.getOperand()); + + String value = "TBD"; + if(info instanceof StringInfo){ + StringInfo strInfo = (StringInfo)info; + value = strInfo.toString(); + } + + return this.getOffset()+":"+this.getOpCode()+" " + this.getReadableCodeText() + " "+ value; + + } + +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/NewObjectCmd.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/NewObjectCmd.java new file mode 100644 index 0000000000..33813b5d59 --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/NewObjectCmd.java @@ -0,0 +1,19 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; + +public class NewObjectCmd extends TwoOperandCmd{ + + public NewObjectCmd(ClassFile clzFile, String opCode){ + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsClassInfo(pool); + } + + +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/NoOperandCmd.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/NoOperandCmd.java new file mode 100644 index 0000000000..56c28fefe2 --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/NoOperandCmd.java @@ -0,0 +1,23 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; + +public class NoOperandCmd extends ByteCodeCommand{ + + public NoOperandCmd(ClassFile clzFile, String opCode) { + super(clzFile, opCode); + } + + @Override + public String toString(ConstantPool pool) { + return this.getOffset()+":" +this.getOpCode() + " "+ this.getReadableCodeText(); + } + + + + public int getLength(){ + return 1; + } + +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/OneOperandCmd.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/OneOperandCmd.java new file mode 100644 index 0000000000..963d064257 --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/OneOperandCmd.java @@ -0,0 +1,27 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; + +public abstract class OneOperandCmd extends ByteCodeCommand { + + private int operand; + + public OneOperandCmd(ClassFile clzFile,String opCode) { + super(clzFile, opCode); + + } + public int getOperand() { + + return this.operand; + } + + public void setOperand(int oprand1) { + this.operand = oprand1; + + } + public int getLength(){ + return 2; + } + + +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/PutFieldCmd.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/PutFieldCmd.java new file mode 100644 index 0000000000..85bb369c19 --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/PutFieldCmd.java @@ -0,0 +1,19 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; + +public class PutFieldCmd extends TwoOperandCmd { + + public PutFieldCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsField(pool); + } + + +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/TwoOperandCmd.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/TwoOperandCmd.java new file mode 100644 index 0000000000..6c0cf53082 --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/cmd/TwoOperandCmd.java @@ -0,0 +1,67 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +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; + +public abstract class TwoOperandCmd extends ByteCodeCommand{ + + int oprand1 = -1; + int oprand2 = -1; + + public int getOprand1() { + return oprand1; + } + + public void setOprand1(int oprand1) { + this.oprand1 = oprand1; + } + + public void setOprand2(int oprand2) { + this.oprand2 = oprand2; + } + + public int getOprand2() { + return oprand2; + } + + public TwoOperandCmd(ClassFile clzFile,String opCode) { + super(clzFile, opCode); + } + + public int getIndex(){ + int oprand1 = this.getOprand1(); + int oprand2 = this.getOprand2(); + int index = oprand1 << 8 | oprand2; + return index; + } + + protected String getOperandAsClassInfo(ConstantPool pool){ + int index = getIndex(); + String codeTxt = getReadableCodeText(); + ClassInfo info = (ClassInfo)pool.getConstantInfo(index); + return this.getOffset()+":"+this.getOpCode()+" "+ codeTxt +" "+ info.getClassName(); + } + + protected String getOperandAsMethod(ConstantPool pool){ + int index = getIndex(); + String codeTxt = getReadableCodeText(); + ConstantInfo constInfo = this.getConstantInfo(index); + MethodRefInfo info = (MethodRefInfo)this.getConstantInfo(index); + return this.getOffset()+":"+this.getOpCode()+" " + codeTxt +" "+ info.toString(); + } + + protected String getOperandAsField(ConstantPool pool){ + int index = getIndex(); + + String codeTxt = getReadableCodeText(); + FieldRefInfo info = (FieldRefInfo)this.getConstantInfo(index); + return this.getOffset()+":"+this.getOpCode()+" " + codeTxt +" "+ info.toString(); + } + public int getLength(){ + return 3; + } +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/ClassInfo.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..c8e65ff493 --- /dev/null +++ b/liuxin/mini-jvm/assignment/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(); + } + @Override + public void accept(Visitor visitor) { + visitor.visitClassInfo(this); + } +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/ConstantInfo.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..88353df2d3 --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/ConstantInfo.java @@ -0,0 +1,40 @@ +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); + } + + public abstract void accept(Visitor visitor); + + public static interface Visitor{ + public void visitClassInfo(ClassInfo info); + public void visitFieldRef(FieldRefInfo info); + public void visitMethodRef(MethodRefInfo info); + public void visitNameAndType(NameAndTypeInfo info); + public void visitString(StringInfo info); + public void visistUTF8(UTF8Info info); + + } +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/ConstantPool.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..7130eb3a9f --- /dev/null +++ b/liuxin/mini-jvm/assignment/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<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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 int getSize() { + return this.constantInfos.size() -1; + } + + +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/FieldRefInfo.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..7ae71396ef --- /dev/null +++ b/liuxin/mini-jvm/assignment/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(); + } + @Override + public void accept(Visitor visitor) { + visitor.visitFieldRef(this); + } +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/MethodRefInfo.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..036e6d9055 --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/MethodRefInfo.java @@ -0,0 +1,60 @@ +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(); + } + + @Override + public void accept(Visitor visitor) { + visitor.visitMethodRef(this); + } + + + +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/NameAndTypeInfo.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..5cbbba6033 --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,51 @@ +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()+")"; + } + + @Override + public void accept(Visitor visitor) { + visitor.visitNameAndType(this); + + } +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/NullConstantInfo.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..41e0fd7e7a --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/NullConstantInfo.java @@ -0,0 +1,17 @@ +package com.coderising.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo(){ + + } + @Override + public int getType() { + return -1; + } + @Override + public void accept(Visitor visitor) { + + } + +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/StringInfo.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..6bfcb47273 --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/StringInfo.java @@ -0,0 +1,32 @@ +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); + } + + @Override + public void accept(Visitor visitor) { + visitor.visitString(this); + + } + +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/UTF8Info.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..7db88a939e --- /dev/null +++ b/liuxin/mini-jvm/assignment/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; + } + @Override + public void accept(Visitor visitor) { + visitor.visistUTF8(this); + + } + + + +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/field/Field.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/field/Field.java new file mode 100644 index 0000000000..c6eb0196f8 --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/field/Field.java @@ -0,0 +1,50 @@ +package com.coderising.jvm.field; + +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.UTF8Info; +import com.coderising.jvm.loader.ByteCodeIterator; + + +public class Field { + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + + + private ConstantPool pool; + + public Field( int accessFlag, int nameIndex, int descriptorIndex,ConstantPool pool) { + + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + this.pool = pool; + } + + public String toString() { + String name = ((UTF8Info)pool.getConstantInfo(this.nameIndex)).getValue(); + + String desc = ((UTF8Info)pool.getConstantInfo(this.descriptorIndex)).getValue(); + return name +":"+ desc; + } + + + public static Field parse(ConstantPool pool,ByteCodeIterator iter){ + + int accessFlag = iter.nextU2ToInt(); + int nameIndex = iter.nextU2ToInt(); + int descIndex = iter.nextU2ToInt(); + int attribCount = iter.nextU2ToInt(); + //System.out.println("field attribute count:"+ attribCount); + + Field f = new Field(accessFlag, nameIndex, descIndex,pool); + + if(attribCount > 0){ + throw new RuntimeException("Field Attribute has not been implemented"); + } + + return f; + } + +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/loader/ByteCodeIterator.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..6fb5570dff --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,57 @@ +package com.coderising.jvm.loader; + +import java.util.Arrays; + +import com.coderising.jvm.util.Util; + +public class ByteCodeIterator { + byte[] codes; + int pos = 0; + + ByteCodeIterator(byte[] codes) { + this.codes = codes; + } + + + + 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; + } + + 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 nextUxToHexString(int len) { + byte[] tmp = new byte[len]; + + for (int i = 0; i < len; i++) { + tmp[i] = codes[pos++]; + } + return Util.byteToHexString(tmp).toLowerCase(); + + } + + public void back(int n) { + this.pos -= n; + } +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/loader/ClassFileLoader.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..33185d8175 --- /dev/null +++ b/liuxin/mini-jvm/assignment/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<String> clzPaths = new ArrayList<String>(); + + 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/liuxin/mini-jvm/assignment/src/com/coderising/jvm/loader/ClassFileParser.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..a29d9572cd --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/loader/ClassFileParser.java @@ -0,0 +1,62 @@ +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; +import com.coderising.jvm.field.Field; +import com.coderising.jvm.method.Method; + +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; + } + private void parseInterfaces(ByteCodeIterator iter) { + int interfaceCount = iter.nextU2ToInt(); + + System.out.println("interfaceCount:" + interfaceCount); + + // TODO : 如果实现了interface, 这里需要解析 + } + + private void parseFileds(ClassFile clzFile, ByteCodeIterator iter) { + + + } + + private void parseMethods(ClassFile clzFile, ByteCodeIterator iter) { + + + + } + +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/method/Method.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/method/Method.java new file mode 100644 index 0000000000..b86c57ef90 --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/method/Method.java @@ -0,0 +1,80 @@ +package com.coderising.jvm.method; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.cmd.ByteCodeCommand; +import com.coderising.jvm.attr.AttributeInfo; +import com.coderising.jvm.attr.CodeAttr; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.UTF8Info; +import com.coderising.jvm.loader.ByteCodeIterator; + + + +public class Method { + + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private CodeAttr codeAttr; + + private ClassFile clzFile; + + + public ClassFile getClzFile() { + return clzFile; + } + + public int getNameIndex() { + return nameIndex; + } + public int getDescriptorIndex() { + return descriptorIndex; + } + + public CodeAttr getCodeAttr() { + return codeAttr; + } + + public void setCodeAttr(CodeAttr code) { + this.codeAttr = code; + } + + + + public Method(ClassFile clzFile,int accessFlag, int nameIndex, int descriptorIndex) { + this.clzFile = clzFile; + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + } + + + + + + public String toString() { + + ConstantPool pool = this.clzFile.getConstantPool(); + StringBuilder buffer = new StringBuilder(); + + String name = ((UTF8Info)pool.getConstantInfo(this.nameIndex)).getValue(); + + String desc = ((UTF8Info)pool.getConstantInfo(this.descriptorIndex)).getValue(); + + buffer.append(name).append(":").append(desc).append("\n"); + + buffer.append(this.codeAttr.toString(pool)); + + return buffer.toString(); + } + + public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ + return null; + + } + + public ByteCodeCommand[] getCmds() { + return this.getCodeAttr().getCmds(); + } +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/print/ClassFilePrinter.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/print/ClassFilePrinter.java new file mode 100644 index 0000000000..14407bacbe --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/print/ClassFilePrinter.java @@ -0,0 +1,54 @@ +package com.coderising.jvm.print; + +import com.coderising.jvm.clz.ClassFile; +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.StringInfo; +import com.coderising.jvm.constant.UTF8Info; +import com.coderising.jvm.loader.ClassFileLoader; + +public class ClassFilePrinter { + ClassFile clzFile = null; + public ClassFilePrinter(ClassFile clzFile){ + this.clzFile = clzFile; + } + + public void print(){ + + if(clzFile.getAccessFlag().isPublicClass()){ + System.out.println("Access flag : public "); + } + System.out.println("Class Name:"+ clzFile.getClassName()); + + System.out.println("Super Class Name:"+ clzFile.getSuperClassName()); + + System.out.println("minor version:" + clzFile.getMinorVersion()); + + System.out.println("major version:" + clzFile.getMinorVersion()); + + ConstantPoolPrinter cnstPoolPrinter = new ConstantPoolPrinter(clzFile.getConstantPool()); + cnstPoolPrinter.print(); + + + + + } + + public static void main(String[] args){ + String path = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\mini-jvm\\bin"; + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path); + String className = "com.coderising.jvm.test.EmployeeV1"; + + ClassFile clzFile = loader.loadClass(className); + + ClassFilePrinter printer = new ClassFilePrinter(clzFile); + + printer.print(); + } +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/print/ConstantPoolPrinter.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/print/ConstantPoolPrinter.java new file mode 100644 index 0000000000..028161adc7 --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/print/ConstantPoolPrinter.java @@ -0,0 +1,25 @@ +package com.coderising.jvm.print; + +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.StringInfo; +import com.coderising.jvm.constant.UTF8Info; + +public class ConstantPoolPrinter { + ConstantPool pool; + ConstantPoolPrinter(ConstantPool pool){ + this.pool = pool; + } + public void print(){ + + System.out.println("Constant Pool:"); + + + + + } +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/test/ClassFileloaderTest.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..5657310e0d --- /dev/null +++ b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,354 @@ +package com.coderising.jvm.test; + +import java.util.List; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.clz.ClassIndex; +import com.coderising.jvm.cmd.BiPushCmd; +import com.coderising.jvm.cmd.ByteCodeCommand; +import com.coderising.jvm.cmd.OneOperandCmd; +import com.coderising.jvm.cmd.TwoOperandCmd; +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.field.Field; +import com.coderising.jvm.loader.ClassFileLoader; +import com.coderising.jvm.method.Method; + + + + + +public class ClassFileloaderTest { + + + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + + static String path1 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\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); + + } + + + @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(); + } + + /** + * ---------------------------------------------------------------------- + */ + + + @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("<init>", 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()); + } + + /** + * 下面是第三次JVM课应实现的测试用例 + */ + @Test + public void testReadFields(){ + + List<Field> fields = clzFile.getFields(); + Assert.assertEquals(2, fields.size()); + { + Field f = fields.get(0); + Assert.assertEquals("name:Ljava/lang/String;", f.toString()); + } + { + Field f = fields.get(1); + Assert.assertEquals("age:I", f.toString()); + } + } + @Test + public void testMethods(){ + + List<Method> methods = clzFile.getMethods(); + ConstantPool pool = clzFile.getConstantPool(); + + { + Method m = methods.get(0); + assertMethodEquals(pool,m, + "<init>", + "(Ljava/lang/String;I)V", + "2ab7000c2a2bb5000f2a1cb50011b1"); + + } + { + Method m = methods.get(1); + assertMethodEquals(pool,m, + "setName", + "(Ljava/lang/String;)V", + "2a2bb5000fb1"); + + } + { + Method m = methods.get(2); + assertMethodEquals(pool,m, + "setAge", + "(I)V", + "2a1bb50011b1"); + } + { + Method m = methods.get(3); + assertMethodEquals(pool,m, + "sayHello", + "()V", + "b2001c1222b60024b1"); + + } + { + Method m = methods.get(4); + assertMethodEquals(pool,m, + "main", + "([Ljava/lang/String;)V", + "bb000159122b101db7002d4c2bb6002fb1"); + } + } + + private void assertMethodEquals(ConstantPool pool,Method m , String expectedName, String expectedDesc,String expectedCode){ + String methodName = pool.getUTF8String(m.getNameIndex()); + String methodDesc = pool.getUTF8String(m.getDescriptorIndex()); + String code = m.getCodeAttr().getCode(); + Assert.assertEquals(expectedName, methodName); + Assert.assertEquals(expectedDesc, methodDesc); + Assert.assertEquals(expectedCode, code); + } + + @Test + public void testByteCodeCommand(){ + { + Method initMethod = this.clzFile.getMethod("<init>", "(Ljava/lang/String;I)V"); + ByteCodeCommand [] cmds = initMethod.getCmds(); + + assertOpCodeEquals("0: aload_0", cmds[0]); + assertOpCodeEquals("1: invokespecial #12", cmds[1]); + assertOpCodeEquals("4: aload_0", cmds[2]); + assertOpCodeEquals("5: aload_1", cmds[3]); + assertOpCodeEquals("6: putfield #15", cmds[4]); + assertOpCodeEquals("9: aload_0", cmds[5]); + assertOpCodeEquals("10: iload_2", cmds[6]); + assertOpCodeEquals("11: putfield #17", cmds[7]); + assertOpCodeEquals("14: return", cmds[8]); + } + + { + Method setNameMethod = this.clzFile.getMethod("setName", "(Ljava/lang/String;)V"); + ByteCodeCommand [] cmds = setNameMethod.getCmds(); + + assertOpCodeEquals("0: aload_0", cmds[0]); + assertOpCodeEquals("1: aload_1", cmds[1]); + assertOpCodeEquals("2: putfield #15", cmds[2]); + assertOpCodeEquals("5: return", cmds[3]); + + } + + { + Method sayHelloMethod = this.clzFile.getMethod("sayHello", "()V"); + ByteCodeCommand [] cmds = sayHelloMethod.getCmds(); + + assertOpCodeEquals("0: getstatic #28", cmds[0]); + assertOpCodeEquals("3: ldc #34", cmds[1]); + assertOpCodeEquals("5: invokevirtual #36", cmds[2]); + assertOpCodeEquals("8: return", cmds[3]); + + } + + { + Method mainMethod = this.clzFile.getMainMethod(); + + ByteCodeCommand [] cmds = mainMethod.getCmds(); + + assertOpCodeEquals("0: new #1", cmds[0]); + assertOpCodeEquals("3: dup", cmds[1]); + assertOpCodeEquals("4: ldc #43", cmds[2]); + assertOpCodeEquals("6: bipush 29", cmds[3]); + assertOpCodeEquals("8: invokespecial #45", cmds[4]); + assertOpCodeEquals("11: astore_1", cmds[5]); + assertOpCodeEquals("12: aload_1", cmds[6]); + assertOpCodeEquals("13: invokevirtual #47", cmds[7]); + assertOpCodeEquals("16: return", cmds[8]); + } + + } + + private void assertOpCodeEquals(String expected, ByteCodeCommand cmd){ + + String acctual = cmd.getOffset()+": "+cmd.getReadableCodeText(); + + if(cmd instanceof OneOperandCmd){ + if(cmd instanceof BiPushCmd){ + acctual += " " + ((OneOperandCmd)cmd).getOperand(); + } else{ + acctual += " #" + ((OneOperandCmd)cmd).getOperand(); + } + } + if(cmd instanceof TwoOperandCmd){ + acctual += " #" + ((TwoOperandCmd)cmd).getIndex(); + } + Assert.assertEquals(expected, acctual); + } + +} diff --git a/liuxin/mini-jvm/assignment/src/com/coderising/jvm/test/EmployeeV1.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..12e3d7efdd --- /dev/null +++ b/liuxin/mini-jvm/assignment/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/liuxin/mini-jvm/assignment/src/com/coderising/jvm/util/Util.java b/liuxin/mini-jvm/assignment/src/com/coderising/jvm/util/Util.java new file mode 100644 index 0000000000..0c4cc8c57c --- /dev/null +++ b/liuxin/mini-jvm/assignment/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<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 265c8c61df2ad645e9c1d103e9c752d83b2fdf92 Mon Sep 17 00:00:00 2001 From: onlyliuxin <14703250@qq.com> Date: Mon, 17 Apr 2017 10:49:39 +0800 Subject: [PATCH 282/287] refactor --- .../basic/stack/expr/InfixToPostfix.java | 65 ++++--------------- 1 file changed, 13 insertions(+), 52 deletions(-) diff --git a/liuxin/data-structure/answer/src/com/coding/basic/stack/expr/InfixToPostfix.java b/liuxin/data-structure/answer/src/com/coding/basic/stack/expr/InfixToPostfix.java index de040d1687..67ff350735 100644 --- a/liuxin/data-structure/answer/src/com/coding/basic/stack/expr/InfixToPostfix.java +++ b/liuxin/data-structure/answer/src/com/coding/basic/stack/expr/InfixToPostfix.java @@ -1,52 +1,13 @@ -package com.coding.basic.stack.expr; - -import java.util.ArrayList; -import java.util.List; -import java.util.Stack; - -public class InfixToPostfix { - - public static List<Token> convert(String expr) { - - TokenParser parser = new TokenParser(); - List<Token> tokens = parser.parse(expr); - - Stack<Token> s = new Stack<Token>(); - List<Token> result = new ArrayList<Token>(); - - for(Token token : tokens){ - if(token.isOperator()){ - if(token.toString().equals("*") || token.toString().equals("/")){ - - while (!s.empty() - && !s.peek().toString().equals("+") - && !s.peek().toString().equals("-")) { - - result.add(s.pop()); - - } - - s.push(token); - } - if(token.toString().equals("+") || token.toString().equals("-")){ - while (!s.empty() ) { - result.add(s.pop()); - } - s.push(token); - } - } - if(token.isNumber()){ - result.add(token); - } - } - - return result; - } - - public static void main(String[] args){ - List<Token> tokens = convert("10+20*2"); - System.out.println(tokens); - - } - -} +package com.coding.basic.stack.expr; + +import java.util.List; + +public class InfixToPostfix { + + public static List<Token> convert(String expr) { + return null; + } + + + +} From 49a788573ab3a4bb727a69add35f35b1017028a3 Mon Sep 17 00:00:00 2001 From: onlyliuxin <14703250@qq.com> Date: Mon, 17 Apr 2017 10:52:41 +0800 Subject: [PATCH 283/287] refactor --- .../src/com/coding/basic/queue/Josephus.java | 52 ++++------ .../basic/queue/QueueWithTwoStacks.java | 95 ++++++++----------- 2 files changed, 60 insertions(+), 87 deletions(-) diff --git a/liuxin/data-structure/answer/src/com/coding/basic/queue/Josephus.java b/liuxin/data-structure/answer/src/com/coding/basic/queue/Josephus.java index 1f06d9be93..29a9115535 100644 --- a/liuxin/data-structure/answer/src/com/coding/basic/queue/Josephus.java +++ b/liuxin/data-structure/answer/src/com/coding/basic/queue/Josephus.java @@ -1,33 +1,19 @@ -package com.coding.basic.queue; - -import java.util.ArrayList; -import java.util.List; - -/** - * 用Queue来实现Josephus问题 - * 在这个古老的问题当中, N个深陷绝境的人一致同意用这种方式减少生存人数: N个人围成一圈(位置记为0到N-1), 并且从第一个人报数, 报到M的人会被杀死, 知道最后一个人留下来 - * @author liuxin - * - */ -public class Josephus { - - public static List<Integer> execute(int n, int m){ - - Queue<Integer> queue = new Queue<Integer>(); - for (int i = 0; i < n; i++){ - queue.enQueue(i); - } - - List<Integer> result = new ArrayList<Integer>(); - - while (!queue.isEmpty()) { - for (int i = 0; i < m-1; i++){ - queue.enQueue(queue.deQueue()); - } - result.add(queue.deQueue()); - - } - return result; - } - -} +package com.coding.basic.queue; + +import java.util.ArrayList; +import java.util.List; + +/** + * 用Queue来实现Josephus问题 + * 在这个古老的问题当中, N个深陷绝境的人一致同意用这种方式减少生存人数: N个人围成一圈(位置记为0到N-1), 并且从第一个人报数, 报到M的人会被杀死, 知道最后一个人留下来 + * @author liuxin + * + */ +public class Josephus { + + public static List<Integer> execute(int n, int m){ + + return null; + } + +} diff --git a/liuxin/data-structure/answer/src/com/coding/basic/queue/QueueWithTwoStacks.java b/liuxin/data-structure/answer/src/com/coding/basic/queue/QueueWithTwoStacks.java index d986c98bd6..4be68d6cbd 100644 --- a/liuxin/data-structure/answer/src/com/coding/basic/queue/QueueWithTwoStacks.java +++ b/liuxin/data-structure/answer/src/com/coding/basic/queue/QueueWithTwoStacks.java @@ -1,54 +1,41 @@ -package com.coding.basic.queue; - -import java.util.NoSuchElementException; -import java.util.Stack; - -public class QueueWithTwoStacks<E> { - private Stack<E> stack1; - private Stack<E> stack2; - - - public QueueWithTwoStacks() { - stack1 = new Stack<E>(); - stack2 = new Stack<E>(); - } - - - private void moveStack1ToStack2() { - while (!stack1.isEmpty()){ - stack2.push(stack1.pop()); - } - - } - - - public boolean isEmpty() { - return stack1.isEmpty() && stack2.isEmpty(); - } - - - - public int size() { - return stack1.size() + stack2.size(); - } - - - - public void enQueue(E item) { - stack1.push(item); - } - - public E deQueue() { - if (isEmpty()) { - throw new NoSuchElementException("Queue is empty"); - } - if (stack2.isEmpty()) { - moveStack1ToStack2(); - } - - return stack2.pop(); - } - - - } - +package com.coding.basic.queue; + +import java.util.Stack; + +public class QueueWithTwoStacks<E> { + private Stack<E> stack1; + private Stack<E> stack2; + + + public QueueWithTwoStacks() { + stack1 = new Stack<E>(); + stack2 = new Stack<E>(); + } + + + + + + public boolean isEmpty() { + return false; + } + + + + public int size() { + return -1; + } + + + + public void enQueue(E item) { + + } + + public E deQueue() { + return null; + } + + + } + From 7b00c6f8271d4a82c5427d4c260aac5ffe525678 Mon Sep 17 00:00:00 2001 From: DonaldY <448641125@qq.com> Date: Mon, 17 Apr 2017 16:43:09 +0800 Subject: [PATCH 284/287] homework helper --- group24/Homework/1-FirstWeek/ArrayList.java | 35 ++ .../Homework/1-FirstWeek/BinaryTreeNode.java | 32 ++ group24/Homework/1-FirstWeek/Iterator.java | 7 + group24/Homework/1-FirstWeek/LinkedList.java | 125 +++++++ group24/Homework/1-FirstWeek/List.java | 9 + group24/Homework/1-FirstWeek/Queue.java | 61 +++ group24/Homework/1-FirstWeek/Stack.java | 24 ++ .../2-SecondWeek/litestruts/LoginAction.java | 39 ++ .../2-SecondWeek/litestruts/Struts.java | 34 ++ .../2-SecondWeek/litestruts/StrutsTest.java | 43 +++ .../2-SecondWeek/litestruts/View.java | 23 ++ group24/Homework/3-ThirdWeek/LinkedList.java | 125 +++++++ .../3-ThirdWeek/download/DownloadThread.java | 20 + .../3-ThirdWeek/download/FileDownloader.java | 73 ++++ .../download/FileDownloaderTest.java | 59 +++ .../3-ThirdWeek/download/api/Connection.java | 23 ++ .../download/api/ConnectionException.java | 5 + .../download/api/ConnectionManager.java | 10 + .../download/api/DownloadListener.java | 5 + .../download/impl/ConnectionImpl.java | 27 ++ .../download/impl/ConnectionManagerImpl.java | 15 + group24/Homework/4-FourWeek/LRUPageFrame.java | 57 +++ .../Homework/4-FourWeek/LRUPageFrameTest.java | 34 ++ .../jvm/loader/ClassFileLoader .java | 25 ++ .../jvm/test/ClassFileloaderTest.java | 92 +++++ .../4-FourWeek/jvm/test/EmployeeV1.java | 0 group24/Homework/5-FifthWeek/README.txt | 3 + group24/Homework/5-FifthWeek/StackUtil.java | 48 +++ .../Homework/5-FifthWeek/StackUtilTest.java | 65 ++++ .../5-FifthWeek/jvm/clz/AccessFlag.java | 23 ++ .../5-FifthWeek/jvm/clz/ClassFile .java | 58 +++ .../5-FifthWeek/jvm/clz/ClassIndex.java | 17 + .../5-FifthWeek/jvm/constant/ClassInfo.java | 28 ++ .../jvm/constant/ConstantInfo.java | 40 ++ .../jvm/constant/ConstantPool.java | 31 ++ .../jvm/constant/FieldRefInfo.java | 58 +++ .../jvm/constant/MethodRefInfo.java | 60 +++ .../jvm/constant/NameAndTypeInfo.java | 51 +++ .../jvm/constant/NullConstantInfo.java | 17 + .../5-FifthWeek/jvm/constant/StringInfo.java | 32 ++ .../5-FifthWeek/jvm/constant/UTF8Info.java | 37 ++ .../jvm/loader/ByteCodeIterator.java | 18 + .../jvm/loader/ClassFileLoader.java | 62 +++ .../jvm/loader/ClassFileParser.java | 62 +++ .../jvm/test/ClassFileloaderTest.java | 208 ++++++++++ .../5-FifthWeek/jvm/test/EmployeeV1.java | 28 ++ .../Homework/5-FifthWeek/jvm/util/Util.java | 24 ++ group24/Homework/6-SixWeek/InfixExpr.java | 15 + group24/Homework/6-SixWeek/InfixExprTest.java | 52 +++ group24/Homework/6-SixWeek/README.txt | 3 + .../6-SixWeek/jvm/attr/AttributeInfo.java | 19 + .../Homework/6-SixWeek/jvm/attr/CodeAttr.java | 70 ++++ .../6-SixWeek/jvm/attr/LineNumberTable.java | 55 +++ .../6-SixWeek/jvm/attr/LocalVariableItem.java | 39 ++ .../jvm/attr/LocalVariableTable.java | 42 +++ .../6-SixWeek/jvm/attr/StackMapTable.java | 30 ++ .../6-SixWeek/jvm/clz/AccessFlag.java | 25 ++ .../Homework/6-SixWeek/jvm/clz/ClassFile.java | 102 +++++ .../6-SixWeek/jvm/clz/ClassIndex.java | 19 + .../6-SixWeek/jvm/constant/ClassInfo.java | 28 ++ .../6-SixWeek/jvm/constant/ConstantInfo.java | 40 ++ .../6-SixWeek/jvm/constant/ConstantPool.java | 31 ++ .../6-SixWeek/jvm/constant/FieldRefInfo.java | 58 +++ .../6-SixWeek/jvm/constant/MethodRefInfo.java | 60 +++ .../jvm/constant/NameAndTypeInfo.java | 51 +++ .../jvm/constant/NullConstantInfo.java | 17 + .../6-SixWeek/jvm/constant/StringInfo.java | 32 ++ .../6-SixWeek/jvm/constant/UTF8Info.java | 37 ++ .../Homework/6-SixWeek/jvm/field/Field.java | 50 +++ .../jvm/loader/ByteCodeIterator.java | 57 +++ .../6-SixWeek/jvm/loader/ClassFileLoader.java | 140 +++++++ .../6-SixWeek/jvm/loader/ClassFileParser.java | 62 +++ .../Homework/6-SixWeek/jvm/method/Method.java | 80 ++++ .../jvm/test/ClassFileloaderTest.java | 282 ++++++++++++++ .../6-SixWeek/jvm/test/EmployeeV1.java | 28 ++ group24/Homework/6-SixWeek/jvm/util/Util.java | 24 ++ .../Homework/7-SevenWeek/InfixToPostfix.java | 14 + group24/Homework/7-SevenWeek/PostfixExpr.java | 18 + .../Homework/7-SevenWeek/PostfixExprTest.java | 41 ++ group24/Homework/7-SevenWeek/README.txt | 4 + .../7-SevenWeek/jvm/attr/AttributeInfo.java | 19 + .../7-SevenWeek/jvm/attr/CodeAttr.java | 70 ++++ .../7-SevenWeek/jvm/attr/LineNumberTable.java | 55 +++ .../jvm/attr/LocalVariableItem.java | 39 ++ .../jvm/attr/LocalVariableTable.java | 42 +++ .../7-SevenWeek/jvm/attr/StackMapTable.java | 30 ++ .../7-SevenWeek/jvm/clz/AccessFlag.java | 25 ++ .../7-SevenWeek/jvm/clz/ClassFile.java | 102 +++++ .../7-SevenWeek/jvm/clz/ClassIndex.java | 19 + .../7-SevenWeek/jvm/cmd/BiPushCmd.java | 23 ++ .../7-SevenWeek/jvm/cmd/ByteCodeCommand.java | 128 +++++++ .../7-SevenWeek/jvm/cmd/CommandParser.java | 85 +++++ .../7-SevenWeek/jvm/cmd/GetFieldCmd.java | 22 ++ .../jvm/cmd/GetStaticFieldCmd.java | 23 ++ .../7-SevenWeek/jvm/cmd/InvokeSpecialCmd.java | 23 ++ .../7-SevenWeek/jvm/cmd/InvokeVirtualCmd.java | 22 ++ .../Homework/7-SevenWeek/jvm/cmd/LdcCmd.java | 29 ++ .../7-SevenWeek/jvm/cmd/NewObjectCmd.java | 19 + .../7-SevenWeek/jvm/cmd/NoOperandCmd.java | 23 ++ .../7-SevenWeek/jvm/cmd/OneOperandCmd.java | 27 ++ .../7-SevenWeek/jvm/cmd/PutFieldCmd.java | 19 + .../7-SevenWeek/jvm/cmd/TwoOperandCmd.java | 67 ++++ .../7-SevenWeek/jvm/constant/ClassInfo.java | 28 ++ .../jvm/constant/ConstantInfo.java | 40 ++ .../jvm/constant/ConstantPool.java | 31 ++ .../jvm/constant/FieldRefInfo.java | 58 +++ .../jvm/constant/MethodRefInfo.java | 60 +++ .../jvm/constant/NameAndTypeInfo.java | 51 +++ .../jvm/constant/NullConstantInfo.java | 17 + .../7-SevenWeek/jvm/constant/StringInfo.java | 32 ++ .../7-SevenWeek/jvm/constant/UTF8Info.java | 37 ++ .../Homework/7-SevenWeek/jvm/field/Field.java | 50 +++ .../jvm/loader/ByteCodeIterator.java | 57 +++ .../jvm/loader/ClassFileLoader.java | 140 +++++++ .../jvm/loader/ClassFileParser.java | 62 +++ .../7-SevenWeek/jvm/method/Method.java | 80 ++++ .../jvm/print/ClassFilePrinter.java | 54 +++ .../jvm/print/ConstantPoolPrinter.java | 25 ++ .../jvm/test/ClassFileloaderTest.java | 354 ++++++++++++++++++ .../7-SevenWeek/jvm/test/EmployeeV1.java | 28 ++ .../Homework/7-SevenWeek/jvm/util/Util.java | 24 ++ 121 files changed, 5736 insertions(+) create mode 100644 group24/Homework/1-FirstWeek/ArrayList.java create mode 100644 group24/Homework/1-FirstWeek/BinaryTreeNode.java create mode 100644 group24/Homework/1-FirstWeek/Iterator.java create mode 100644 group24/Homework/1-FirstWeek/LinkedList.java create mode 100644 group24/Homework/1-FirstWeek/List.java create mode 100644 group24/Homework/1-FirstWeek/Queue.java create mode 100644 group24/Homework/1-FirstWeek/Stack.java create mode 100644 group24/Homework/2-SecondWeek/litestruts/LoginAction.java create mode 100644 group24/Homework/2-SecondWeek/litestruts/Struts.java create mode 100644 group24/Homework/2-SecondWeek/litestruts/StrutsTest.java create mode 100644 group24/Homework/2-SecondWeek/litestruts/View.java create mode 100644 group24/Homework/3-ThirdWeek/LinkedList.java create mode 100644 group24/Homework/3-ThirdWeek/download/DownloadThread.java create mode 100644 group24/Homework/3-ThirdWeek/download/FileDownloader.java create mode 100644 group24/Homework/3-ThirdWeek/download/FileDownloaderTest.java create mode 100644 group24/Homework/3-ThirdWeek/download/api/Connection.java create mode 100644 group24/Homework/3-ThirdWeek/download/api/ConnectionException.java create mode 100644 group24/Homework/3-ThirdWeek/download/api/ConnectionManager.java create mode 100644 group24/Homework/3-ThirdWeek/download/api/DownloadListener.java create mode 100644 group24/Homework/3-ThirdWeek/download/impl/ConnectionImpl.java create mode 100644 group24/Homework/3-ThirdWeek/download/impl/ConnectionManagerImpl.java create mode 100644 group24/Homework/4-FourWeek/LRUPageFrame.java create mode 100644 group24/Homework/4-FourWeek/LRUPageFrameTest.java create mode 100644 group24/Homework/4-FourWeek/jvm/loader/ClassFileLoader .java create mode 100644 group24/Homework/4-FourWeek/jvm/test/ClassFileloaderTest.java create mode 100644 group24/Homework/4-FourWeek/jvm/test/EmployeeV1.java create mode 100644 group24/Homework/5-FifthWeek/README.txt create mode 100644 group24/Homework/5-FifthWeek/StackUtil.java create mode 100644 group24/Homework/5-FifthWeek/StackUtilTest.java create mode 100644 group24/Homework/5-FifthWeek/jvm/clz/AccessFlag.java create mode 100644 group24/Homework/5-FifthWeek/jvm/clz/ClassFile .java create mode 100644 group24/Homework/5-FifthWeek/jvm/clz/ClassIndex.java create mode 100644 group24/Homework/5-FifthWeek/jvm/constant/ClassInfo.java create mode 100644 group24/Homework/5-FifthWeek/jvm/constant/ConstantInfo.java create mode 100644 group24/Homework/5-FifthWeek/jvm/constant/ConstantPool.java create mode 100644 group24/Homework/5-FifthWeek/jvm/constant/FieldRefInfo.java create mode 100644 group24/Homework/5-FifthWeek/jvm/constant/MethodRefInfo.java create mode 100644 group24/Homework/5-FifthWeek/jvm/constant/NameAndTypeInfo.java create mode 100644 group24/Homework/5-FifthWeek/jvm/constant/NullConstantInfo.java create mode 100644 group24/Homework/5-FifthWeek/jvm/constant/StringInfo.java create mode 100644 group24/Homework/5-FifthWeek/jvm/constant/UTF8Info.java create mode 100644 group24/Homework/5-FifthWeek/jvm/loader/ByteCodeIterator.java create mode 100644 group24/Homework/5-FifthWeek/jvm/loader/ClassFileLoader.java create mode 100644 group24/Homework/5-FifthWeek/jvm/loader/ClassFileParser.java create mode 100644 group24/Homework/5-FifthWeek/jvm/test/ClassFileloaderTest.java create mode 100644 group24/Homework/5-FifthWeek/jvm/test/EmployeeV1.java create mode 100644 group24/Homework/5-FifthWeek/jvm/util/Util.java create mode 100644 group24/Homework/6-SixWeek/InfixExpr.java create mode 100644 group24/Homework/6-SixWeek/InfixExprTest.java create mode 100644 group24/Homework/6-SixWeek/README.txt create mode 100644 group24/Homework/6-SixWeek/jvm/attr/AttributeInfo.java create mode 100644 group24/Homework/6-SixWeek/jvm/attr/CodeAttr.java create mode 100644 group24/Homework/6-SixWeek/jvm/attr/LineNumberTable.java create mode 100644 group24/Homework/6-SixWeek/jvm/attr/LocalVariableItem.java create mode 100644 group24/Homework/6-SixWeek/jvm/attr/LocalVariableTable.java create mode 100644 group24/Homework/6-SixWeek/jvm/attr/StackMapTable.java create mode 100644 group24/Homework/6-SixWeek/jvm/clz/AccessFlag.java create mode 100644 group24/Homework/6-SixWeek/jvm/clz/ClassFile.java create mode 100644 group24/Homework/6-SixWeek/jvm/clz/ClassIndex.java create mode 100644 group24/Homework/6-SixWeek/jvm/constant/ClassInfo.java create mode 100644 group24/Homework/6-SixWeek/jvm/constant/ConstantInfo.java create mode 100644 group24/Homework/6-SixWeek/jvm/constant/ConstantPool.java create mode 100644 group24/Homework/6-SixWeek/jvm/constant/FieldRefInfo.java create mode 100644 group24/Homework/6-SixWeek/jvm/constant/MethodRefInfo.java create mode 100644 group24/Homework/6-SixWeek/jvm/constant/NameAndTypeInfo.java create mode 100644 group24/Homework/6-SixWeek/jvm/constant/NullConstantInfo.java create mode 100644 group24/Homework/6-SixWeek/jvm/constant/StringInfo.java create mode 100644 group24/Homework/6-SixWeek/jvm/constant/UTF8Info.java create mode 100644 group24/Homework/6-SixWeek/jvm/field/Field.java create mode 100644 group24/Homework/6-SixWeek/jvm/loader/ByteCodeIterator.java create mode 100644 group24/Homework/6-SixWeek/jvm/loader/ClassFileLoader.java create mode 100644 group24/Homework/6-SixWeek/jvm/loader/ClassFileParser.java create mode 100644 group24/Homework/6-SixWeek/jvm/method/Method.java create mode 100644 group24/Homework/6-SixWeek/jvm/test/ClassFileloaderTest.java create mode 100644 group24/Homework/6-SixWeek/jvm/test/EmployeeV1.java create mode 100644 group24/Homework/6-SixWeek/jvm/util/Util.java create mode 100644 group24/Homework/7-SevenWeek/InfixToPostfix.java create mode 100644 group24/Homework/7-SevenWeek/PostfixExpr.java create mode 100644 group24/Homework/7-SevenWeek/PostfixExprTest.java create mode 100644 group24/Homework/7-SevenWeek/README.txt create mode 100644 group24/Homework/7-SevenWeek/jvm/attr/AttributeInfo.java create mode 100644 group24/Homework/7-SevenWeek/jvm/attr/CodeAttr.java create mode 100644 group24/Homework/7-SevenWeek/jvm/attr/LineNumberTable.java create mode 100644 group24/Homework/7-SevenWeek/jvm/attr/LocalVariableItem.java create mode 100644 group24/Homework/7-SevenWeek/jvm/attr/LocalVariableTable.java create mode 100644 group24/Homework/7-SevenWeek/jvm/attr/StackMapTable.java create mode 100644 group24/Homework/7-SevenWeek/jvm/clz/AccessFlag.java create mode 100644 group24/Homework/7-SevenWeek/jvm/clz/ClassFile.java create mode 100644 group24/Homework/7-SevenWeek/jvm/clz/ClassIndex.java create mode 100644 group24/Homework/7-SevenWeek/jvm/cmd/BiPushCmd.java create mode 100644 group24/Homework/7-SevenWeek/jvm/cmd/ByteCodeCommand.java create mode 100644 group24/Homework/7-SevenWeek/jvm/cmd/CommandParser.java create mode 100644 group24/Homework/7-SevenWeek/jvm/cmd/GetFieldCmd.java create mode 100644 group24/Homework/7-SevenWeek/jvm/cmd/GetStaticFieldCmd.java create mode 100644 group24/Homework/7-SevenWeek/jvm/cmd/InvokeSpecialCmd.java create mode 100644 group24/Homework/7-SevenWeek/jvm/cmd/InvokeVirtualCmd.java create mode 100644 group24/Homework/7-SevenWeek/jvm/cmd/LdcCmd.java create mode 100644 group24/Homework/7-SevenWeek/jvm/cmd/NewObjectCmd.java create mode 100644 group24/Homework/7-SevenWeek/jvm/cmd/NoOperandCmd.java create mode 100644 group24/Homework/7-SevenWeek/jvm/cmd/OneOperandCmd.java create mode 100644 group24/Homework/7-SevenWeek/jvm/cmd/PutFieldCmd.java create mode 100644 group24/Homework/7-SevenWeek/jvm/cmd/TwoOperandCmd.java create mode 100644 group24/Homework/7-SevenWeek/jvm/constant/ClassInfo.java create mode 100644 group24/Homework/7-SevenWeek/jvm/constant/ConstantInfo.java create mode 100644 group24/Homework/7-SevenWeek/jvm/constant/ConstantPool.java create mode 100644 group24/Homework/7-SevenWeek/jvm/constant/FieldRefInfo.java create mode 100644 group24/Homework/7-SevenWeek/jvm/constant/MethodRefInfo.java create mode 100644 group24/Homework/7-SevenWeek/jvm/constant/NameAndTypeInfo.java create mode 100644 group24/Homework/7-SevenWeek/jvm/constant/NullConstantInfo.java create mode 100644 group24/Homework/7-SevenWeek/jvm/constant/StringInfo.java create mode 100644 group24/Homework/7-SevenWeek/jvm/constant/UTF8Info.java create mode 100644 group24/Homework/7-SevenWeek/jvm/field/Field.java create mode 100644 group24/Homework/7-SevenWeek/jvm/loader/ByteCodeIterator.java create mode 100644 group24/Homework/7-SevenWeek/jvm/loader/ClassFileLoader.java create mode 100644 group24/Homework/7-SevenWeek/jvm/loader/ClassFileParser.java create mode 100644 group24/Homework/7-SevenWeek/jvm/method/Method.java create mode 100644 group24/Homework/7-SevenWeek/jvm/print/ClassFilePrinter.java create mode 100644 group24/Homework/7-SevenWeek/jvm/print/ConstantPoolPrinter.java create mode 100644 group24/Homework/7-SevenWeek/jvm/test/ClassFileloaderTest.java create mode 100644 group24/Homework/7-SevenWeek/jvm/test/EmployeeV1.java create mode 100644 group24/Homework/7-SevenWeek/jvm/util/Util.java diff --git a/group24/Homework/1-FirstWeek/ArrayList.java b/group24/Homework/1-FirstWeek/ArrayList.java new file mode 100644 index 0000000000..4576c016af --- /dev/null +++ b/group24/Homework/1-FirstWeek/ArrayList.java @@ -0,0 +1,35 @@ +package com.coding.basic.array; + +import com.coding.basic.Iterator; +import com.coding.basic.List; + +public class ArrayList implements List { + + private int size = 0; + + private Object[] elementData = new Object[100]; + + 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 Iterator iterator(){ + return null; + } + +} diff --git a/group24/Homework/1-FirstWeek/BinaryTreeNode.java b/group24/Homework/1-FirstWeek/BinaryTreeNode.java new file mode 100644 index 0000000000..d7ac820192 --- /dev/null +++ b/group24/Homework/1-FirstWeek/BinaryTreeNode.java @@ -0,0 +1,32 @@ +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; + } + + public BinaryTreeNode insert(Object o){ + return null; + } + +} diff --git a/group24/Homework/1-FirstWeek/Iterator.java b/group24/Homework/1-FirstWeek/Iterator.java new file mode 100644 index 0000000000..06ef6311b2 --- /dev/null +++ b/group24/Homework/1-FirstWeek/Iterator.java @@ -0,0 +1,7 @@ +package com.coding.basic; + +public interface Iterator { + public boolean hasNext(); + public Object next(); + +} diff --git a/group24/Homework/1-FirstWeek/LinkedList.java b/group24/Homework/1-FirstWeek/LinkedList.java new file mode 100644 index 0000000000..f4c7556a2e --- /dev/null +++ b/group24/Homework/1-FirstWeek/LinkedList.java @@ -0,0 +1,125 @@ +package com.coding.basic.linklist; + +import com.coding.basic.Iterator; +import com.coding.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/Homework/1-FirstWeek/List.java b/group24/Homework/1-FirstWeek/List.java new file mode 100644 index 0000000000..10d13b5832 --- /dev/null +++ b/group24/Homework/1-FirstWeek/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/group24/Homework/1-FirstWeek/Queue.java b/group24/Homework/1-FirstWeek/Queue.java new file mode 100644 index 0000000000..c4c4b7325e --- /dev/null +++ b/group24/Homework/1-FirstWeek/Queue.java @@ -0,0 +1,61 @@ +package com.coding.basic.queue; + +import java.util.NoSuchElementException; + +public class Queue<E> { + private Node<E> first; + private Node<E> last; + private int size; + + + private static class Node<E> { + private E item; + private Node<E> next; + } + + + public Queue() { + first = null; + last = null; + size = 0; + } + + + public boolean isEmpty() { + return first == null; + } + + public int size() { + return size; + } + + + + public void enQueue(E data) { + Node<E> oldlast = last; + last = new Node<E>(); + last.item = data; + last.next = null; + if (isEmpty()) { + first = last; + } + else{ + oldlast.next = last; + } + size++; + } + + public E deQueue() { + if (isEmpty()) { + throw new NoSuchElementException("Queue underflow"); + } + E item = first.item; + first = first.next; + size--; + if (isEmpty()) { + last = null; + } + return item; + } + +} diff --git a/group24/Homework/1-FirstWeek/Stack.java b/group24/Homework/1-FirstWeek/Stack.java new file mode 100644 index 0000000000..fedb243604 --- /dev/null +++ b/group24/Homework/1-FirstWeek/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/group24/Homework/2-SecondWeek/litestruts/LoginAction.java b/group24/Homework/2-SecondWeek/litestruts/LoginAction.java new file mode 100644 index 0000000000..dcdbe226ed --- /dev/null +++ b/group24/Homework/2-SecondWeek/litestruts/LoginAction.java @@ -0,0 +1,39 @@ +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/group24/Homework/2-SecondWeek/litestruts/Struts.java b/group24/Homework/2-SecondWeek/litestruts/Struts.java new file mode 100644 index 0000000000..85e2e22de3 --- /dev/null +++ b/group24/Homework/2-SecondWeek/litestruts/Struts.java @@ -0,0 +1,34 @@ +package com.coderising.litestruts; + +import java.util.Map; + + + +public class Struts { + + public static View runAction(String actionName, Map<String,String> 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中的 <result> 配置,以及execute的返回值, 确定哪一个jsp, + 放到View对象的jsp字段中。 + + */ + + return null; + } + +} diff --git a/group24/Homework/2-SecondWeek/litestruts/StrutsTest.java b/group24/Homework/2-SecondWeek/litestruts/StrutsTest.java new file mode 100644 index 0000000000..b8c81faf3c --- /dev/null +++ b/group24/Homework/2-SecondWeek/litestruts/StrutsTest.java @@ -0,0 +1,43 @@ +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<String,String> params = new HashMap<String,String>(); + 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<String,String> params = new HashMap<String,String>(); + 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/group24/Homework/2-SecondWeek/litestruts/View.java b/group24/Homework/2-SecondWeek/litestruts/View.java new file mode 100644 index 0000000000..07df2a5dab --- /dev/null +++ b/group24/Homework/2-SecondWeek/litestruts/View.java @@ -0,0 +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; + } +} diff --git a/group24/Homework/3-ThirdWeek/LinkedList.java b/group24/Homework/3-ThirdWeek/LinkedList.java new file mode 100644 index 0000000000..f4c7556a2e --- /dev/null +++ b/group24/Homework/3-ThirdWeek/LinkedList.java @@ -0,0 +1,125 @@ +package com.coding.basic.linklist; + +import com.coding.basic.Iterator; +import com.coding.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/Homework/3-ThirdWeek/download/DownloadThread.java b/group24/Homework/3-ThirdWeek/download/DownloadThread.java new file mode 100644 index 0000000000..900a3ad358 --- /dev/null +++ b/group24/Homework/3-ThirdWeek/download/DownloadThread.java @@ -0,0 +1,20 @@ +package com.coderising.download; + +import com.coderising.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/Homework/3-ThirdWeek/download/FileDownloader.java b/group24/Homework/3-ThirdWeek/download/FileDownloader.java new file mode 100644 index 0000000000..c3c8a3f27d --- /dev/null +++ b/group24/Homework/3-ThirdWeek/download/FileDownloader.java @@ -0,0 +1,73 @@ +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; + + +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/Homework/3-ThirdWeek/download/FileDownloaderTest.java b/group24/Homework/3-ThirdWeek/download/FileDownloaderTest.java new file mode 100644 index 0000000000..4ff7f46ae0 --- /dev/null +++ b/group24/Homework/3-ThirdWeek/download/FileDownloaderTest.java @@ -0,0 +1,59 @@ +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://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/Homework/3-ThirdWeek/download/api/Connection.java b/group24/Homework/3-ThirdWeek/download/api/Connection.java new file mode 100644 index 0000000000..0957eaf7f4 --- /dev/null +++ b/group24/Homework/3-ThirdWeek/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/group24/Homework/3-ThirdWeek/download/api/ConnectionException.java b/group24/Homework/3-ThirdWeek/download/api/ConnectionException.java new file mode 100644 index 0000000000..1551a80b3d --- /dev/null +++ b/group24/Homework/3-ThirdWeek/download/api/ConnectionException.java @@ -0,0 +1,5 @@ +package com.coderising.download.api; + +public class ConnectionException extends Exception { + +} diff --git a/group24/Homework/3-ThirdWeek/download/api/ConnectionManager.java b/group24/Homework/3-ThirdWeek/download/api/ConnectionManager.java new file mode 100644 index 0000000000..ce045393b1 --- /dev/null +++ b/group24/Homework/3-ThirdWeek/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/group24/Homework/3-ThirdWeek/download/api/DownloadListener.java b/group24/Homework/3-ThirdWeek/download/api/DownloadListener.java new file mode 100644 index 0000000000..bf9807b307 --- /dev/null +++ b/group24/Homework/3-ThirdWeek/download/api/DownloadListener.java @@ -0,0 +1,5 @@ +package com.coderising.download.api; + +public interface DownloadListener { + public void notifyFinished(); +} diff --git a/group24/Homework/3-ThirdWeek/download/impl/ConnectionImpl.java b/group24/Homework/3-ThirdWeek/download/impl/ConnectionImpl.java new file mode 100644 index 0000000000..36a9d2ce15 --- /dev/null +++ b/group24/Homework/3-ThirdWeek/download/impl/ConnectionImpl.java @@ -0,0 +1,27 @@ +package com.coderising.download.impl; + +import java.io.IOException; + +import com.coderising.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/Homework/3-ThirdWeek/download/impl/ConnectionManagerImpl.java b/group24/Homework/3-ThirdWeek/download/impl/ConnectionManagerImpl.java new file mode 100644 index 0000000000..172371dd55 --- /dev/null +++ b/group24/Homework/3-ThirdWeek/download/impl/ConnectionManagerImpl.java @@ -0,0 +1,15 @@ +package com.coderising.download.impl; + +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 null; + } + +} diff --git a/group24/Homework/4-FourWeek/LRUPageFrame.java b/group24/Homework/4-FourWeek/LRUPageFrame.java new file mode 100644 index 0000000000..994a241a3d --- /dev/null +++ b/group24/Homework/4-FourWeek/LRUPageFrame.java @@ -0,0 +1,57 @@ +package com.coding.basic.linklist; + + +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 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/Homework/4-FourWeek/LRUPageFrameTest.java b/group24/Homework/4-FourWeek/LRUPageFrameTest.java new file mode 100644 index 0000000000..7fd72fc2b4 --- /dev/null +++ b/group24/Homework/4-FourWeek/LRUPageFrameTest.java @@ -0,0 +1,34 @@ +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()); + frame.access(5); + Assert.assertEquals("5,4,0", frame.toString()); + + } + +} diff --git a/group24/Homework/4-FourWeek/jvm/loader/ClassFileLoader .java b/group24/Homework/4-FourWeek/jvm/loader/ClassFileLoader .java new file mode 100644 index 0000000000..55b4b70974 --- /dev/null +++ b/group24/Homework/4-FourWeek/jvm/loader/ClassFileLoader .java @@ -0,0 +1,25 @@ +public class ClassFileLoader { + + private List<String> clzPaths = new ArrayList<String>(); + + public byte[] readBinaryCode(String className) { + + return null; + } + + + public void addClassPath(String path) { + + } + + + + public String getClassPath(){ + + } + + + + + +} \ No newline at end of file diff --git a/group24/Homework/4-FourWeek/jvm/test/ClassFileloaderTest.java b/group24/Homework/4-FourWeek/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..77f1b93eb8 --- /dev/null +++ b/group24/Homework/4-FourWeek/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,92 @@ +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:\\workspace\\min-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); + int i=byteCodes.length; + // ע⣺ֽܺJVM汾йϵ Կõൽж + Assert.assertEquals(2048, 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/group24/Homework/4-FourWeek/jvm/test/EmployeeV1.java b/group24/Homework/4-FourWeek/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..e69de29bb2 diff --git a/group24/Homework/5-FifthWeek/README.txt b/group24/Homework/5-FifthWeek/README.txt new file mode 100644 index 0000000000..8af35e8a67 --- /dev/null +++ b/group24/Homework/5-FifthWeek/README.txt @@ -0,0 +1,3 @@ +1. ҪʵֵClassFileParser.java, ByteCodeIterator.java, + ʵֺҪͨԣClassFileloaderTest.java +2. ݽṹ ʵStackUtil \ No newline at end of file diff --git a/group24/Homework/5-FifthWeek/StackUtil.java b/group24/Homework/5-FifthWeek/StackUtil.java new file mode 100644 index 0000000000..b0ec38161d --- /dev/null +++ b/group24/Homework/5-FifthWeek/StackUtil.java @@ -0,0 +1,48 @@ +package com.coding.basic.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<Integer> 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; + } + + +} diff --git a/group24/Homework/5-FifthWeek/StackUtilTest.java b/group24/Homework/5-FifthWeek/StackUtilTest.java new file mode 100644 index 0000000000..76f2cb7668 --- /dev/null +++ b/group24/Homework/5-FifthWeek/StackUtilTest.java @@ -0,0 +1,65 @@ +package com.coding.basic.stack; + +import java.util.Stack; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +public class StackUtilTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + + @Test + public void testReverse() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + Assert.assertEquals("[1, 2, 3, 4, 5]", s.toString()); + StackUtil.reverse(s); + Assert.assertEquals("[5, 4, 3, 2, 1]", s.toString()); + } + + @Test + public void testRemove() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + StackUtil.remove(s, 2); + Assert.assertEquals("[1, 3]", s.toString()); + } + + @Test + public void testGetTop() { + Stack<Integer> s = new Stack(); + s.push(1); + s.push(2); + s.push(3); + s.push(4); + s.push(5); + { + Object[] values = StackUtil.getTop(s, 3); + Assert.assertEquals(5, values[0]); + Assert.assertEquals(4, values[1]); + Assert.assertEquals(3, values[2]); + } + } + + @Test + public void testIsValidPairs() { + Assert.assertTrue(StackUtil.isValidPairs("([e{d}f])")); + Assert.assertFalse(StackUtil.isValidPairs("([b{x]y})")); + } + +} diff --git a/group24/Homework/5-FifthWeek/jvm/clz/AccessFlag.java b/group24/Homework/5-FifthWeek/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..2d93c5cebf --- /dev/null +++ b/group24/Homework/5-FifthWeek/jvm/clz/AccessFlag.java @@ -0,0 +1,23 @@ +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/group24/Homework/5-FifthWeek/jvm/clz/ClassFile .java b/group24/Homework/5-FifthWeek/jvm/clz/ClassFile .java new file mode 100644 index 0000000000..0406ec7b46 --- /dev/null +++ b/group24/Homework/5-FifthWeek/jvm/clz/ClassFile .java @@ -0,0 +1,58 @@ +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(); + } \ No newline at end of file diff --git a/group24/Homework/5-FifthWeek/jvm/clz/ClassIndex.java b/group24/Homework/5-FifthWeek/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..f1505a5050 --- /dev/null +++ b/group24/Homework/5-FifthWeek/jvm/clz/ClassIndex.java @@ -0,0 +1,17 @@ +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/group24/Homework/5-FifthWeek/jvm/constant/ClassInfo.java b/group24/Homework/5-FifthWeek/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..c8e65ff493 --- /dev/null +++ b/group24/Homework/5-FifthWeek/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(); + } + @Override + public void accept(Visitor visitor) { + visitor.visitClassInfo(this); + } +} diff --git a/group24/Homework/5-FifthWeek/jvm/constant/ConstantInfo.java b/group24/Homework/5-FifthWeek/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..88353df2d3 --- /dev/null +++ b/group24/Homework/5-FifthWeek/jvm/constant/ConstantInfo.java @@ -0,0 +1,40 @@ +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); + } + + public abstract void accept(Visitor visitor); + + public static interface Visitor{ + public void visitClassInfo(ClassInfo info); + public void visitFieldRef(FieldRefInfo info); + public void visitMethodRef(MethodRefInfo info); + public void visitNameAndType(NameAndTypeInfo info); + public void visitString(StringInfo info); + public void visistUTF8(UTF8Info info); + + } +} diff --git a/group24/Homework/5-FifthWeek/jvm/constant/ConstantPool.java b/group24/Homework/5-FifthWeek/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..7130eb3a9f --- /dev/null +++ b/group24/Homework/5-FifthWeek/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<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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 int getSize() { + return this.constantInfos.size() -1; + } + + +} diff --git a/group24/Homework/5-FifthWeek/jvm/constant/FieldRefInfo.java b/group24/Homework/5-FifthWeek/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..7ae71396ef --- /dev/null +++ b/group24/Homework/5-FifthWeek/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(); + } + @Override + public void accept(Visitor visitor) { + visitor.visitFieldRef(this); + } +} diff --git a/group24/Homework/5-FifthWeek/jvm/constant/MethodRefInfo.java b/group24/Homework/5-FifthWeek/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..036e6d9055 --- /dev/null +++ b/group24/Homework/5-FifthWeek/jvm/constant/MethodRefInfo.java @@ -0,0 +1,60 @@ +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(); + } + + @Override + public void accept(Visitor visitor) { + visitor.visitMethodRef(this); + } + + + +} diff --git a/group24/Homework/5-FifthWeek/jvm/constant/NameAndTypeInfo.java b/group24/Homework/5-FifthWeek/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..5cbbba6033 --- /dev/null +++ b/group24/Homework/5-FifthWeek/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,51 @@ +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()+")"; + } + + @Override + public void accept(Visitor visitor) { + visitor.visitNameAndType(this); + + } +} diff --git a/group24/Homework/5-FifthWeek/jvm/constant/NullConstantInfo.java b/group24/Homework/5-FifthWeek/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..41e0fd7e7a --- /dev/null +++ b/group24/Homework/5-FifthWeek/jvm/constant/NullConstantInfo.java @@ -0,0 +1,17 @@ +package com.coderising.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo(){ + + } + @Override + public int getType() { + return -1; + } + @Override + public void accept(Visitor visitor) { + + } + +} diff --git a/group24/Homework/5-FifthWeek/jvm/constant/StringInfo.java b/group24/Homework/5-FifthWeek/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..6bfcb47273 --- /dev/null +++ b/group24/Homework/5-FifthWeek/jvm/constant/StringInfo.java @@ -0,0 +1,32 @@ +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); + } + + @Override + public void accept(Visitor visitor) { + visitor.visitString(this); + + } + +} diff --git a/group24/Homework/5-FifthWeek/jvm/constant/UTF8Info.java b/group24/Homework/5-FifthWeek/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..7db88a939e --- /dev/null +++ b/group24/Homework/5-FifthWeek/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; + } + @Override + public void accept(Visitor visitor) { + visitor.visistUTF8(this); + + } + + + +} diff --git a/group24/Homework/5-FifthWeek/jvm/loader/ByteCodeIterator.java b/group24/Homework/5-FifthWeek/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..b3a25fa8c8 --- /dev/null +++ b/group24/Homework/5-FifthWeek/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,18 @@ +package com.coderising.jvm.loader; + +import java.util.Arrays; + +import com.coderising.jvm.util.Util; + +public class ByteCodeIterator { + private byte[] codes; + private int pos; + + public ByteCodeIterator(byte[] codes){ + this.codes = codes; + } + + + + +} diff --git a/group24/Homework/5-FifthWeek/jvm/loader/ClassFileLoader.java b/group24/Homework/5-FifthWeek/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..3b8ddb6a17 --- /dev/null +++ b/group24/Homework/5-FifthWeek/jvm/loader/ClassFileLoader.java @@ -0,0 +1,62 @@ +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<String> clzPaths = new ArrayList<String>(); + + 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; + + + + } + + 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) { + + return null; + } + +} \ No newline at end of file diff --git a/group24/Homework/5-FifthWeek/jvm/loader/ClassFileParser.java b/group24/Homework/5-FifthWeek/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..a29d9572cd --- /dev/null +++ b/group24/Homework/5-FifthWeek/jvm/loader/ClassFileParser.java @@ -0,0 +1,62 @@ +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; +import com.coderising.jvm.field.Field; +import com.coderising.jvm.method.Method; + +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; + } + private void parseInterfaces(ByteCodeIterator iter) { + int interfaceCount = iter.nextU2ToInt(); + + System.out.println("interfaceCount:" + interfaceCount); + + // TODO : 如果实现了interface, 这里需要解析 + } + + private void parseFileds(ClassFile clzFile, ByteCodeIterator iter) { + + + } + + private void parseMethods(ClassFile clzFile, ByteCodeIterator iter) { + + + + } + +} diff --git a/group24/Homework/5-FifthWeek/jvm/test/ClassFileloaderTest.java b/group24/Homework/5-FifthWeek/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..657bf296f6 --- /dev/null +++ b/group24/Homework/5-FifthWeek/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,208 @@ +package com.coderising.jvm.test; + +import java.util.List; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.clz.ClassIndex; +import com.coderising.jvm.cmd.BiPushCmd; +import com.coderising.jvm.cmd.ByteCodeCommand; +import com.coderising.jvm.cmd.OneOperandCmd; +import com.coderising.jvm.cmd.TwoOperandCmd; +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.field.Field; +import com.coderising.jvm.loader.ClassFileLoader; +import com.coderising.jvm.method.Method; + + + + + +public class ClassFileloaderTest { + + + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + + static String path1 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\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); + + } + + + @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(); + } + + /** + * ---------------------------------------------------------------------- + */ + + + @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("<init>", 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()); + } + +} \ No newline at end of file diff --git a/group24/Homework/5-FifthWeek/jvm/test/EmployeeV1.java b/group24/Homework/5-FifthWeek/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..12e3d7efdd --- /dev/null +++ b/group24/Homework/5-FifthWeek/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/group24/Homework/5-FifthWeek/jvm/util/Util.java b/group24/Homework/5-FifthWeek/jvm/util/Util.java new file mode 100644 index 0000000000..0c4cc8c57c --- /dev/null +++ b/group24/Homework/5-FifthWeek/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<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/group24/Homework/6-SixWeek/InfixExpr.java b/group24/Homework/6-SixWeek/InfixExpr.java new file mode 100644 index 0000000000..ef85ff007f --- /dev/null +++ b/group24/Homework/6-SixWeek/InfixExpr.java @@ -0,0 +1,15 @@ +package com.coding.basic.stack.expr; + +public class InfixExpr { + String expr = null; + + public InfixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + return 0.0f; + } + + +} diff --git a/group24/Homework/6-SixWeek/InfixExprTest.java b/group24/Homework/6-SixWeek/InfixExprTest.java new file mode 100644 index 0000000000..20e34e8852 --- /dev/null +++ b/group24/Homework/6-SixWeek/InfixExprTest.java @@ -0,0 +1,52 @@ +package com.coding.basic.stack.expr; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class InfixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + //InfixExpr expr = new InfixExpr("300*20+12*5-20/4"); + { + InfixExpr expr = new InfixExpr("2+3*4+5"); + Assert.assertEquals(19.0, expr.evaluate(), 0.001f); + } + { + InfixExpr expr = new InfixExpr("3*20+12*5-40/2"); + Assert.assertEquals(100.0, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("3*20/2"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("20/2*3"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("10-30+50"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + { + InfixExpr expr = new InfixExpr("10-2*3+50"); + Assert.assertEquals(54, expr.evaluate(), 0.001f); + } + + } + +} diff --git a/group24/Homework/6-SixWeek/README.txt b/group24/Homework/6-SixWeek/README.txt new file mode 100644 index 0000000000..facdfabf7b --- /dev/null +++ b/group24/Homework/6-SixWeek/README.txt @@ -0,0 +1,3 @@ +1. ʵֶһ.classļֶκͷĶȡ +ҪʵֵClassFileParser.javaص ʵֺҪͨԣClassFileloaderTest.java +2. ݽṹ ʵInfixExpr.java ҪͨInfixExprTest.java \ No newline at end of file diff --git a/group24/Homework/6-SixWeek/jvm/attr/AttributeInfo.java b/group24/Homework/6-SixWeek/jvm/attr/AttributeInfo.java new file mode 100644 index 0000000000..88f60c77f6 --- /dev/null +++ b/group24/Homework/6-SixWeek/jvm/attr/AttributeInfo.java @@ -0,0 +1,19 @@ +package com.coderising.jvm.attr; + +public abstract class AttributeInfo { + public static final String CODE = "Code"; + public static final String CONST_VALUE = "ConstantValue"; + public static final String EXCEPTIONS = "Exceptions"; + public static final String LINE_NUM_TABLE = "LineNumberTable"; + public static final String LOCAL_VAR_TABLE = "LocalVariableTable"; + public static final String STACK_MAP_TABLE = "StackMapTable"; + int attrNameIndex; + int attrLen ; + public AttributeInfo(int attrNameIndex, int attrLen) { + + this.attrNameIndex = attrNameIndex; + this.attrLen = attrLen; + } + + +} diff --git a/group24/Homework/6-SixWeek/jvm/attr/CodeAttr.java b/group24/Homework/6-SixWeek/jvm/attr/CodeAttr.java new file mode 100644 index 0000000000..c4c0c4c6c5 --- /dev/null +++ b/group24/Homework/6-SixWeek/jvm/attr/CodeAttr.java @@ -0,0 +1,70 @@ +package com.coderising.jvm.attr; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.cmd.ByteCodeCommand; +import com.coderising.jvm.cmd.CommandParser; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.loader.ByteCodeIterator; + + +public class CodeAttr extends AttributeInfo { + private int maxStack ; + private int maxLocals ; + private int codeLen ; + private String code; + public String getCode() { + return code; + } + + private ByteCodeCommand[] cmds ; + public ByteCodeCommand[] getCmds() { + return cmds; + } + private LineNumberTable lineNumTable; + private LocalVariableTable localVarTable; + private StackMapTable stackMapTable; + + public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen,String code ,ByteCodeCommand[] cmds) { + super(attrNameIndex, attrLen); + this.maxStack = maxStack; + this.maxLocals = maxLocals; + this.codeLen = codeLen; + this.code = code; + this.cmds = cmds; + } + + public void setLineNumberTable(LineNumberTable t) { + this.lineNumTable = t; + } + + public void setLocalVariableTable(LocalVariableTable t) { + this.localVarTable = t; + } + + public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ + + return null; + } + + + public String toString(ConstantPool pool){ + StringBuilder buffer = new StringBuilder(); + //buffer.append("Code:").append(code).append("\n"); + for(int i=0;i<cmds.length;i++){ + buffer.append(cmds[i].toString(pool)).append("\n"); + } + buffer.append("\n"); + buffer.append(this.lineNumTable.toString()); + buffer.append(this.localVarTable.toString(pool)); + return buffer.toString(); + } + private void setStackMapTable(StackMapTable t) { + this.stackMapTable = t; + + } + + + + + +} diff --git a/group24/Homework/6-SixWeek/jvm/attr/LineNumberTable.java b/group24/Homework/6-SixWeek/jvm/attr/LineNumberTable.java new file mode 100644 index 0000000000..a31a1ff4d0 --- /dev/null +++ b/group24/Homework/6-SixWeek/jvm/attr/LineNumberTable.java @@ -0,0 +1,55 @@ +package com.coderising.jvm.attr; + +import java.util.ArrayList; +import java.util.List; + + +import com.coderising.jvm.loader.ByteCodeIterator; + +public class LineNumberTable extends AttributeInfo { + List<LineNumberItem> items = new ArrayList<LineNumberItem>(); + + private static class LineNumberItem{ + int startPC; + int lineNum; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLineNum() { + return lineNum; + } + public void setLineNum(int lineNum) { + this.lineNum = lineNum; + } + } + public void addLineNumberItem(LineNumberItem item){ + this.items.add(item); + } + public LineNumberTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + + } + + public static LineNumberTable parse(ByteCodeIterator iter){ + + return null; + } + + public String toString(){ + StringBuilder buffer = new StringBuilder(); + buffer.append("Line Number Table:\n"); + for(LineNumberItem item : items){ + buffer.append("startPC:"+item.getStartPC()).append(","); + buffer.append("lineNum:"+item.getLineNum()).append("\n"); + } + buffer.append("\n"); + return buffer.toString(); + + } + + + +} diff --git a/group24/Homework/6-SixWeek/jvm/attr/LocalVariableItem.java b/group24/Homework/6-SixWeek/jvm/attr/LocalVariableItem.java new file mode 100644 index 0000000000..962c3b8bc4 --- /dev/null +++ b/group24/Homework/6-SixWeek/jvm/attr/LocalVariableItem.java @@ -0,0 +1,39 @@ +package com.coderising.jvm.attr; + +public class LocalVariableItem { + private int startPC; + private int length; + private int nameIndex; + private int descIndex; + private int index; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getNameIndex() { + return nameIndex; + } + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + public int getDescIndex() { + return descIndex; + } + public void setDescIndex(int descIndex) { + this.descIndex = descIndex; + } + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } +} diff --git a/group24/Homework/6-SixWeek/jvm/attr/LocalVariableTable.java b/group24/Homework/6-SixWeek/jvm/attr/LocalVariableTable.java new file mode 100644 index 0000000000..14db5dca46 --- /dev/null +++ b/group24/Homework/6-SixWeek/jvm/attr/LocalVariableTable.java @@ -0,0 +1,42 @@ +package com.coderising.jvm.attr; + + +import java.util.ArrayList; +import java.util.List; + +import com.coderising.jvm.constant.ConstantPool; + +import com.coderising.jvm.loader.ByteCodeIterator; + +public class LocalVariableTable extends AttributeInfo{ + + List<LocalVariableItem> items = new ArrayList<LocalVariableItem>(); + + public LocalVariableTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + + private void addLocalVariableItem(LocalVariableItem item) { + this.items.add(item); + } + + public static LocalVariableTable parse(ByteCodeIterator iter){ + + return null; + } + + + public String toString(ConstantPool pool){ + StringBuilder buffer = new StringBuilder(); + buffer.append("Local Variable Table:\n"); + for(LocalVariableItem item : items){ + buffer.append("startPC:"+item.getStartPC()).append(","); + buffer.append("name:"+pool.getUTF8String(item.getNameIndex())).append(","); + buffer.append("desc:"+pool.getUTF8String(item.getDescIndex())).append(","); + buffer.append("slotIndex:"+ item.getIndex()).append("\n"); + } + buffer.append("\n"); + return buffer.toString(); + } +} diff --git a/group24/Homework/6-SixWeek/jvm/attr/StackMapTable.java b/group24/Homework/6-SixWeek/jvm/attr/StackMapTable.java new file mode 100644 index 0000000000..18f2ad0360 --- /dev/null +++ b/group24/Homework/6-SixWeek/jvm/attr/StackMapTable.java @@ -0,0 +1,30 @@ +package com.coderising.jvm.attr; + + +import com.coderising.jvm.loader.ByteCodeIterator; + +public class StackMapTable extends AttributeInfo{ + + private String originalCode; + + public StackMapTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static StackMapTable parse(ByteCodeIterator iter){ + int index = iter.nextU2ToInt(); + int len = iter.nextU4ToInt(); + StackMapTable t = new StackMapTable(index,len); + + //后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 + String code = iter.nextUxToHexString(len); + t.setOriginalCode(code); + + return t; + } + + private void setOriginalCode(String code) { + this.originalCode = code; + + } +} diff --git a/group24/Homework/6-SixWeek/jvm/clz/AccessFlag.java b/group24/Homework/6-SixWeek/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..faae056835 --- /dev/null +++ b/group24/Homework/6-SixWeek/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/group24/Homework/6-SixWeek/jvm/clz/ClassFile.java b/group24/Homework/6-SixWeek/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..2a8dfb6123 --- /dev/null +++ b/group24/Homework/6-SixWeek/jvm/clz/ClassFile.java @@ -0,0 +1,102 @@ +package com.coderising.jvm.clz; + +import java.util.ArrayList; +import java.util.List; + +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.field.Field; +import com.coderising.jvm.method.Method; + +public class ClassFile { + + private int minorVersion; + private int majorVersion; + + private AccessFlag accessFlag; + private ClassIndex clzIndex; + private ConstantPool pool; + private List<Field> fields = new ArrayList<Field>(); + private List<Method> methods = new ArrayList<Method>(); + + 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 addField(Field f){ + this.fields.add(f); + } + public List<Field> getFields(){ + return this.fields; + } + public void addMethod(Method m){ + this.methods.add(m); + } + public List<Method> getMethods() { + return methods; + } + + + 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()); + + + } + + public String getClassName(){ + int thisClassIndex = this.clzIndex.getThisClassIndex(); + ClassInfo thisClass = (ClassInfo)this.getConstantPool().getConstantInfo(thisClassIndex); + return thisClass.getClassName(); + } + public String getSuperClassName(){ + ClassInfo superClass = (ClassInfo)this.getConstantPool().getConstantInfo(this.clzIndex.getSuperClassIndex()); + return superClass.getClassName(); + } + + public Method getMethod(String methodName, String paramAndReturnType){ + + + return null; + } + public Method getMainMethod(){ + + return null; + } +} diff --git a/group24/Homework/6-SixWeek/jvm/clz/ClassIndex.java b/group24/Homework/6-SixWeek/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..e424f284b3 --- /dev/null +++ b/group24/Homework/6-SixWeek/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/group24/Homework/6-SixWeek/jvm/constant/ClassInfo.java b/group24/Homework/6-SixWeek/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..c8e65ff493 --- /dev/null +++ b/group24/Homework/6-SixWeek/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(); + } + @Override + public void accept(Visitor visitor) { + visitor.visitClassInfo(this); + } +} diff --git a/group24/Homework/6-SixWeek/jvm/constant/ConstantInfo.java b/group24/Homework/6-SixWeek/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..88353df2d3 --- /dev/null +++ b/group24/Homework/6-SixWeek/jvm/constant/ConstantInfo.java @@ -0,0 +1,40 @@ +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); + } + + public abstract void accept(Visitor visitor); + + public static interface Visitor{ + public void visitClassInfo(ClassInfo info); + public void visitFieldRef(FieldRefInfo info); + public void visitMethodRef(MethodRefInfo info); + public void visitNameAndType(NameAndTypeInfo info); + public void visitString(StringInfo info); + public void visistUTF8(UTF8Info info); + + } +} diff --git a/group24/Homework/6-SixWeek/jvm/constant/ConstantPool.java b/group24/Homework/6-SixWeek/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..7130eb3a9f --- /dev/null +++ b/group24/Homework/6-SixWeek/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<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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 int getSize() { + return this.constantInfos.size() -1; + } + + +} diff --git a/group24/Homework/6-SixWeek/jvm/constant/FieldRefInfo.java b/group24/Homework/6-SixWeek/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..7ae71396ef --- /dev/null +++ b/group24/Homework/6-SixWeek/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(); + } + @Override + public void accept(Visitor visitor) { + visitor.visitFieldRef(this); + } +} diff --git a/group24/Homework/6-SixWeek/jvm/constant/MethodRefInfo.java b/group24/Homework/6-SixWeek/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..036e6d9055 --- /dev/null +++ b/group24/Homework/6-SixWeek/jvm/constant/MethodRefInfo.java @@ -0,0 +1,60 @@ +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(); + } + + @Override + public void accept(Visitor visitor) { + visitor.visitMethodRef(this); + } + + + +} diff --git a/group24/Homework/6-SixWeek/jvm/constant/NameAndTypeInfo.java b/group24/Homework/6-SixWeek/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..5cbbba6033 --- /dev/null +++ b/group24/Homework/6-SixWeek/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,51 @@ +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()+")"; + } + + @Override + public void accept(Visitor visitor) { + visitor.visitNameAndType(this); + + } +} diff --git a/group24/Homework/6-SixWeek/jvm/constant/NullConstantInfo.java b/group24/Homework/6-SixWeek/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..41e0fd7e7a --- /dev/null +++ b/group24/Homework/6-SixWeek/jvm/constant/NullConstantInfo.java @@ -0,0 +1,17 @@ +package com.coderising.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo(){ + + } + @Override + public int getType() { + return -1; + } + @Override + public void accept(Visitor visitor) { + + } + +} diff --git a/group24/Homework/6-SixWeek/jvm/constant/StringInfo.java b/group24/Homework/6-SixWeek/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..6bfcb47273 --- /dev/null +++ b/group24/Homework/6-SixWeek/jvm/constant/StringInfo.java @@ -0,0 +1,32 @@ +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); + } + + @Override + public void accept(Visitor visitor) { + visitor.visitString(this); + + } + +} diff --git a/group24/Homework/6-SixWeek/jvm/constant/UTF8Info.java b/group24/Homework/6-SixWeek/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..7db88a939e --- /dev/null +++ b/group24/Homework/6-SixWeek/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; + } + @Override + public void accept(Visitor visitor) { + visitor.visistUTF8(this); + + } + + + +} diff --git a/group24/Homework/6-SixWeek/jvm/field/Field.java b/group24/Homework/6-SixWeek/jvm/field/Field.java new file mode 100644 index 0000000000..c6eb0196f8 --- /dev/null +++ b/group24/Homework/6-SixWeek/jvm/field/Field.java @@ -0,0 +1,50 @@ +package com.coderising.jvm.field; + +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.UTF8Info; +import com.coderising.jvm.loader.ByteCodeIterator; + + +public class Field { + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + + + private ConstantPool pool; + + public Field( int accessFlag, int nameIndex, int descriptorIndex,ConstantPool pool) { + + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + this.pool = pool; + } + + public String toString() { + String name = ((UTF8Info)pool.getConstantInfo(this.nameIndex)).getValue(); + + String desc = ((UTF8Info)pool.getConstantInfo(this.descriptorIndex)).getValue(); + return name +":"+ desc; + } + + + public static Field parse(ConstantPool pool,ByteCodeIterator iter){ + + int accessFlag = iter.nextU2ToInt(); + int nameIndex = iter.nextU2ToInt(); + int descIndex = iter.nextU2ToInt(); + int attribCount = iter.nextU2ToInt(); + //System.out.println("field attribute count:"+ attribCount); + + Field f = new Field(accessFlag, nameIndex, descIndex,pool); + + if(attribCount > 0){ + throw new RuntimeException("Field Attribute has not been implemented"); + } + + return f; + } + +} diff --git a/group24/Homework/6-SixWeek/jvm/loader/ByteCodeIterator.java b/group24/Homework/6-SixWeek/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..6fb5570dff --- /dev/null +++ b/group24/Homework/6-SixWeek/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,57 @@ +package com.coderising.jvm.loader; + +import java.util.Arrays; + +import com.coderising.jvm.util.Util; + +public class ByteCodeIterator { + byte[] codes; + int pos = 0; + + ByteCodeIterator(byte[] codes) { + this.codes = codes; + } + + + + 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; + } + + 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 nextUxToHexString(int len) { + byte[] tmp = new byte[len]; + + for (int i = 0; i < len; i++) { + tmp[i] = codes[pos++]; + } + return Util.byteToHexString(tmp).toLowerCase(); + + } + + public void back(int n) { + this.pos -= n; + } +} diff --git a/group24/Homework/6-SixWeek/jvm/loader/ClassFileLoader.java b/group24/Homework/6-SixWeek/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..33185d8175 --- /dev/null +++ b/group24/Homework/6-SixWeek/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<String> clzPaths = new ArrayList<String>(); + + 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/group24/Homework/6-SixWeek/jvm/loader/ClassFileParser.java b/group24/Homework/6-SixWeek/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..a29d9572cd --- /dev/null +++ b/group24/Homework/6-SixWeek/jvm/loader/ClassFileParser.java @@ -0,0 +1,62 @@ +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; +import com.coderising.jvm.field.Field; +import com.coderising.jvm.method.Method; + +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; + } + private void parseInterfaces(ByteCodeIterator iter) { + int interfaceCount = iter.nextU2ToInt(); + + System.out.println("interfaceCount:" + interfaceCount); + + // TODO : 如果实现了interface, 这里需要解析 + } + + private void parseFileds(ClassFile clzFile, ByteCodeIterator iter) { + + + } + + private void parseMethods(ClassFile clzFile, ByteCodeIterator iter) { + + + + } + +} diff --git a/group24/Homework/6-SixWeek/jvm/method/Method.java b/group24/Homework/6-SixWeek/jvm/method/Method.java new file mode 100644 index 0000000000..b86c57ef90 --- /dev/null +++ b/group24/Homework/6-SixWeek/jvm/method/Method.java @@ -0,0 +1,80 @@ +package com.coderising.jvm.method; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.cmd.ByteCodeCommand; +import com.coderising.jvm.attr.AttributeInfo; +import com.coderising.jvm.attr.CodeAttr; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.UTF8Info; +import com.coderising.jvm.loader.ByteCodeIterator; + + + +public class Method { + + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private CodeAttr codeAttr; + + private ClassFile clzFile; + + + public ClassFile getClzFile() { + return clzFile; + } + + public int getNameIndex() { + return nameIndex; + } + public int getDescriptorIndex() { + return descriptorIndex; + } + + public CodeAttr getCodeAttr() { + return codeAttr; + } + + public void setCodeAttr(CodeAttr code) { + this.codeAttr = code; + } + + + + public Method(ClassFile clzFile,int accessFlag, int nameIndex, int descriptorIndex) { + this.clzFile = clzFile; + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + } + + + + + + public String toString() { + + ConstantPool pool = this.clzFile.getConstantPool(); + StringBuilder buffer = new StringBuilder(); + + String name = ((UTF8Info)pool.getConstantInfo(this.nameIndex)).getValue(); + + String desc = ((UTF8Info)pool.getConstantInfo(this.descriptorIndex)).getValue(); + + buffer.append(name).append(":").append(desc).append("\n"); + + buffer.append(this.codeAttr.toString(pool)); + + return buffer.toString(); + } + + public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ + return null; + + } + + public ByteCodeCommand[] getCmds() { + return this.getCodeAttr().getCmds(); + } +} diff --git a/group24/Homework/6-SixWeek/jvm/test/ClassFileloaderTest.java b/group24/Homework/6-SixWeek/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..f83d290e14 --- /dev/null +++ b/group24/Homework/6-SixWeek/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,282 @@ +package com.coderising.jvm.test; + +import java.util.List; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.clz.ClassIndex; +import com.coderising.jvm.cmd.BiPushCmd; +import com.coderising.jvm.cmd.ByteCodeCommand; +import com.coderising.jvm.cmd.OneOperandCmd; +import com.coderising.jvm.cmd.TwoOperandCmd; +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.field.Field; +import com.coderising.jvm.loader.ClassFileLoader; +import com.coderising.jvm.method.Method; + + + + + +public class ClassFileloaderTest { + + + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + + static String path1 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\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); + + } + + + @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(); + } + + /** + * ---------------------------------------------------------------------- + */ + + + @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("<init>", 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()); + } + + /** + * 下面是第三次JVM课应实现的测试用例 + */ + @Test + public void testReadFields(){ + + List<Field> fields = clzFile.getFields(); + Assert.assertEquals(2, fields.size()); + { + Field f = fields.get(0); + Assert.assertEquals("name:Ljava/lang/String;", f.toString()); + } + { + Field f = fields.get(1); + Assert.assertEquals("age:I", f.toString()); + } + } + @Test + public void testMethods(){ + + List<Method> methods = clzFile.getMethods(); + ConstantPool pool = clzFile.getConstantPool(); + + { + Method m = methods.get(0); + assertMethodEquals(pool,m, + "<init>", + "(Ljava/lang/String;I)V", + "2ab7000c2a2bb5000f2a1cb50011b1"); + + } + { + Method m = methods.get(1); + assertMethodEquals(pool,m, + "setName", + "(Ljava/lang/String;)V", + "2a2bb5000fb1"); + + } + { + Method m = methods.get(2); + assertMethodEquals(pool,m, + "setAge", + "(I)V", + "2a1bb50011b1"); + } + { + Method m = methods.get(3); + assertMethodEquals(pool,m, + "sayHello", + "()V", + "b2001c1222b60024b1"); + + } + { + Method m = methods.get(4); + assertMethodEquals(pool,m, + "main", + "([Ljava/lang/String;)V", + "bb000159122b101db7002d4c2bb6002fb1"); + } + } + + private void assertMethodEquals(ConstantPool pool,Method m , String expectedName, String expectedDesc,String expectedCode){ + String methodName = pool.getUTF8String(m.getNameIndex()); + String methodDesc = pool.getUTF8String(m.getDescriptorIndex()); + String code = m.getCodeAttr().getCode(); + Assert.assertEquals(expectedName, methodName); + Assert.assertEquals(expectedDesc, methodDesc); + Assert.assertEquals(expectedCode, code); + } + + + +} diff --git a/group24/Homework/6-SixWeek/jvm/test/EmployeeV1.java b/group24/Homework/6-SixWeek/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..12e3d7efdd --- /dev/null +++ b/group24/Homework/6-SixWeek/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/group24/Homework/6-SixWeek/jvm/util/Util.java b/group24/Homework/6-SixWeek/jvm/util/Util.java new file mode 100644 index 0000000000..0c4cc8c57c --- /dev/null +++ b/group24/Homework/6-SixWeek/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<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/group24/Homework/7-SevenWeek/InfixToPostfix.java b/group24/Homework/7-SevenWeek/InfixToPostfix.java new file mode 100644 index 0000000000..96a2194a67 --- /dev/null +++ b/group24/Homework/7-SevenWeek/InfixToPostfix.java @@ -0,0 +1,14 @@ +package com.coding.basic.stack.expr; + +import java.util.List; + +public class InfixToPostfix { + + public static List<Token> convert(String expr) { + + return null; + } + + + +} diff --git a/group24/Homework/7-SevenWeek/PostfixExpr.java b/group24/Homework/7-SevenWeek/PostfixExpr.java new file mode 100644 index 0000000000..dcbb18be4b --- /dev/null +++ b/group24/Homework/7-SevenWeek/PostfixExpr.java @@ -0,0 +1,18 @@ +package com.coding.basic.stack.expr; + +import java.util.List; +import java.util.Stack; + +public class PostfixExpr { +String expr = null; + + public PostfixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + return 0.0f; + } + + +} diff --git a/group24/Homework/7-SevenWeek/PostfixExprTest.java b/group24/Homework/7-SevenWeek/PostfixExprTest.java new file mode 100644 index 0000000000..c0435a2db5 --- /dev/null +++ b/group24/Homework/7-SevenWeek/PostfixExprTest.java @@ -0,0 +1,41 @@ +package com.coding.basic.stack.expr; + + + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + + +public class PostfixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + { + PostfixExpr expr = new PostfixExpr("6 5 2 3 + 8 * + 3 + *"); + Assert.assertEquals(288, expr.evaluate(),0.0f); + } + { + //9+(3-1)*3+10/2 + PostfixExpr expr = new PostfixExpr("9 3 1-3*+ 10 2/+"); + Assert.assertEquals(20, expr.evaluate(),0.0f); + } + + { + //10-2*3+50 + PostfixExpr expr = new PostfixExpr("10 2 3 * - 50 +"); + Assert.assertEquals(54, expr.evaluate(),0.0f); + } + } + +} diff --git a/group24/Homework/7-SevenWeek/README.txt b/group24/Homework/7-SevenWeek/README.txt new file mode 100644 index 0000000000..6adfb7dc34 --- /dev/null +++ b/group24/Homework/7-SevenWeek/README.txt @@ -0,0 +1,4 @@ +1. ָֽתΪjava Ҫʵֵࣺ CommandParser.java +2. ʵƵjavap ҪʵֵࣺClassFilePrinter.java +3. ݽṹ ʵǰ׺ʽPrefixExpr.java ׺ʽ PostfixExpr.java +׺ʽת׺ʽ InfixToPostfix.java \ No newline at end of file diff --git a/group24/Homework/7-SevenWeek/jvm/attr/AttributeInfo.java b/group24/Homework/7-SevenWeek/jvm/attr/AttributeInfo.java new file mode 100644 index 0000000000..88f60c77f6 --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/attr/AttributeInfo.java @@ -0,0 +1,19 @@ +package com.coderising.jvm.attr; + +public abstract class AttributeInfo { + public static final String CODE = "Code"; + public static final String CONST_VALUE = "ConstantValue"; + public static final String EXCEPTIONS = "Exceptions"; + public static final String LINE_NUM_TABLE = "LineNumberTable"; + public static final String LOCAL_VAR_TABLE = "LocalVariableTable"; + public static final String STACK_MAP_TABLE = "StackMapTable"; + int attrNameIndex; + int attrLen ; + public AttributeInfo(int attrNameIndex, int attrLen) { + + this.attrNameIndex = attrNameIndex; + this.attrLen = attrLen; + } + + +} diff --git a/group24/Homework/7-SevenWeek/jvm/attr/CodeAttr.java b/group24/Homework/7-SevenWeek/jvm/attr/CodeAttr.java new file mode 100644 index 0000000000..c4c0c4c6c5 --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/attr/CodeAttr.java @@ -0,0 +1,70 @@ +package com.coderising.jvm.attr; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.cmd.ByteCodeCommand; +import com.coderising.jvm.cmd.CommandParser; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.loader.ByteCodeIterator; + + +public class CodeAttr extends AttributeInfo { + private int maxStack ; + private int maxLocals ; + private int codeLen ; + private String code; + public String getCode() { + return code; + } + + private ByteCodeCommand[] cmds ; + public ByteCodeCommand[] getCmds() { + return cmds; + } + private LineNumberTable lineNumTable; + private LocalVariableTable localVarTable; + private StackMapTable stackMapTable; + + public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen,String code ,ByteCodeCommand[] cmds) { + super(attrNameIndex, attrLen); + this.maxStack = maxStack; + this.maxLocals = maxLocals; + this.codeLen = codeLen; + this.code = code; + this.cmds = cmds; + } + + public void setLineNumberTable(LineNumberTable t) { + this.lineNumTable = t; + } + + public void setLocalVariableTable(LocalVariableTable t) { + this.localVarTable = t; + } + + public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ + + return null; + } + + + public String toString(ConstantPool pool){ + StringBuilder buffer = new StringBuilder(); + //buffer.append("Code:").append(code).append("\n"); + for(int i=0;i<cmds.length;i++){ + buffer.append(cmds[i].toString(pool)).append("\n"); + } + buffer.append("\n"); + buffer.append(this.lineNumTable.toString()); + buffer.append(this.localVarTable.toString(pool)); + return buffer.toString(); + } + private void setStackMapTable(StackMapTable t) { + this.stackMapTable = t; + + } + + + + + +} diff --git a/group24/Homework/7-SevenWeek/jvm/attr/LineNumberTable.java b/group24/Homework/7-SevenWeek/jvm/attr/LineNumberTable.java new file mode 100644 index 0000000000..a31a1ff4d0 --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/attr/LineNumberTable.java @@ -0,0 +1,55 @@ +package com.coderising.jvm.attr; + +import java.util.ArrayList; +import java.util.List; + + +import com.coderising.jvm.loader.ByteCodeIterator; + +public class LineNumberTable extends AttributeInfo { + List<LineNumberItem> items = new ArrayList<LineNumberItem>(); + + private static class LineNumberItem{ + int startPC; + int lineNum; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLineNum() { + return lineNum; + } + public void setLineNum(int lineNum) { + this.lineNum = lineNum; + } + } + public void addLineNumberItem(LineNumberItem item){ + this.items.add(item); + } + public LineNumberTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + + } + + public static LineNumberTable parse(ByteCodeIterator iter){ + + return null; + } + + public String toString(){ + StringBuilder buffer = new StringBuilder(); + buffer.append("Line Number Table:\n"); + for(LineNumberItem item : items){ + buffer.append("startPC:"+item.getStartPC()).append(","); + buffer.append("lineNum:"+item.getLineNum()).append("\n"); + } + buffer.append("\n"); + return buffer.toString(); + + } + + + +} diff --git a/group24/Homework/7-SevenWeek/jvm/attr/LocalVariableItem.java b/group24/Homework/7-SevenWeek/jvm/attr/LocalVariableItem.java new file mode 100644 index 0000000000..962c3b8bc4 --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/attr/LocalVariableItem.java @@ -0,0 +1,39 @@ +package com.coderising.jvm.attr; + +public class LocalVariableItem { + private int startPC; + private int length; + private int nameIndex; + private int descIndex; + private int index; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getNameIndex() { + return nameIndex; + } + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + public int getDescIndex() { + return descIndex; + } + public void setDescIndex(int descIndex) { + this.descIndex = descIndex; + } + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } +} diff --git a/group24/Homework/7-SevenWeek/jvm/attr/LocalVariableTable.java b/group24/Homework/7-SevenWeek/jvm/attr/LocalVariableTable.java new file mode 100644 index 0000000000..14db5dca46 --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/attr/LocalVariableTable.java @@ -0,0 +1,42 @@ +package com.coderising.jvm.attr; + + +import java.util.ArrayList; +import java.util.List; + +import com.coderising.jvm.constant.ConstantPool; + +import com.coderising.jvm.loader.ByteCodeIterator; + +public class LocalVariableTable extends AttributeInfo{ + + List<LocalVariableItem> items = new ArrayList<LocalVariableItem>(); + + public LocalVariableTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + + private void addLocalVariableItem(LocalVariableItem item) { + this.items.add(item); + } + + public static LocalVariableTable parse(ByteCodeIterator iter){ + + return null; + } + + + public String toString(ConstantPool pool){ + StringBuilder buffer = new StringBuilder(); + buffer.append("Local Variable Table:\n"); + for(LocalVariableItem item : items){ + buffer.append("startPC:"+item.getStartPC()).append(","); + buffer.append("name:"+pool.getUTF8String(item.getNameIndex())).append(","); + buffer.append("desc:"+pool.getUTF8String(item.getDescIndex())).append(","); + buffer.append("slotIndex:"+ item.getIndex()).append("\n"); + } + buffer.append("\n"); + return buffer.toString(); + } +} diff --git a/group24/Homework/7-SevenWeek/jvm/attr/StackMapTable.java b/group24/Homework/7-SevenWeek/jvm/attr/StackMapTable.java new file mode 100644 index 0000000000..18f2ad0360 --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/attr/StackMapTable.java @@ -0,0 +1,30 @@ +package com.coderising.jvm.attr; + + +import com.coderising.jvm.loader.ByteCodeIterator; + +public class StackMapTable extends AttributeInfo{ + + private String originalCode; + + public StackMapTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static StackMapTable parse(ByteCodeIterator iter){ + int index = iter.nextU2ToInt(); + int len = iter.nextU4ToInt(); + StackMapTable t = new StackMapTable(index,len); + + //后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 + String code = iter.nextUxToHexString(len); + t.setOriginalCode(code); + + return t; + } + + private void setOriginalCode(String code) { + this.originalCode = code; + + } +} diff --git a/group24/Homework/7-SevenWeek/jvm/clz/AccessFlag.java b/group24/Homework/7-SevenWeek/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..faae056835 --- /dev/null +++ b/group24/Homework/7-SevenWeek/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/group24/Homework/7-SevenWeek/jvm/clz/ClassFile.java b/group24/Homework/7-SevenWeek/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..2a8dfb6123 --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/clz/ClassFile.java @@ -0,0 +1,102 @@ +package com.coderising.jvm.clz; + +import java.util.ArrayList; +import java.util.List; + +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.field.Field; +import com.coderising.jvm.method.Method; + +public class ClassFile { + + private int minorVersion; + private int majorVersion; + + private AccessFlag accessFlag; + private ClassIndex clzIndex; + private ConstantPool pool; + private List<Field> fields = new ArrayList<Field>(); + private List<Method> methods = new ArrayList<Method>(); + + 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 addField(Field f){ + this.fields.add(f); + } + public List<Field> getFields(){ + return this.fields; + } + public void addMethod(Method m){ + this.methods.add(m); + } + public List<Method> getMethods() { + return methods; + } + + + 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()); + + + } + + public String getClassName(){ + int thisClassIndex = this.clzIndex.getThisClassIndex(); + ClassInfo thisClass = (ClassInfo)this.getConstantPool().getConstantInfo(thisClassIndex); + return thisClass.getClassName(); + } + public String getSuperClassName(){ + ClassInfo superClass = (ClassInfo)this.getConstantPool().getConstantInfo(this.clzIndex.getSuperClassIndex()); + return superClass.getClassName(); + } + + public Method getMethod(String methodName, String paramAndReturnType){ + + + return null; + } + public Method getMainMethod(){ + + return null; + } +} diff --git a/group24/Homework/7-SevenWeek/jvm/clz/ClassIndex.java b/group24/Homework/7-SevenWeek/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..e424f284b3 --- /dev/null +++ b/group24/Homework/7-SevenWeek/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/group24/Homework/7-SevenWeek/jvm/cmd/BiPushCmd.java b/group24/Homework/7-SevenWeek/jvm/cmd/BiPushCmd.java new file mode 100644 index 0000000000..cd0fbd4848 --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/cmd/BiPushCmd.java @@ -0,0 +1,23 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantInfo; +import com.coderising.jvm.constant.ConstantPool; + + +public class BiPushCmd extends OneOperandCmd { + + public BiPushCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + + } + + @Override + public String toString(ConstantPool pool) { + + return this.getOffset()+": "+ this.getOpCode()+" " + this.getReadableCodeText() + " " + this.getOperand(); + } + + + +} diff --git a/group24/Homework/7-SevenWeek/jvm/cmd/ByteCodeCommand.java b/group24/Homework/7-SevenWeek/jvm/cmd/ByteCodeCommand.java new file mode 100644 index 0000000000..a3abeacc82 --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/cmd/ByteCodeCommand.java @@ -0,0 +1,128 @@ +package com.coderising.jvm.cmd; + +import java.util.HashMap; +import java.util.Map; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantInfo; +import com.coderising.jvm.constant.ConstantPool; + + +public abstract class ByteCodeCommand { + + String opCode; + ClassFile clzFile; + private int offset; + + private static Map<String,String> codeMap = new HashMap<String,String>(); + + static{ + codeMap.put("01", "aconst_null"); + + codeMap.put("BB", "new"); + codeMap.put("37", "lstore"); + codeMap.put("B7", "invokespecial"); + codeMap.put("B6", "invokevirtual"); + codeMap.put("B4", "getfield"); + codeMap.put("B5", "putfield"); + codeMap.put("B2", "getstatic"); + + codeMap.put("2A", "aload_0"); + codeMap.put("2B", "aload_1"); + codeMap.put("2C", "aload_2"); + + codeMap.put("10", "bipush"); + codeMap.put("15", "iload"); + codeMap.put("1A", "iload_0"); + codeMap.put("1B", "iload_1"); + codeMap.put("1C", "iload_2"); + codeMap.put("1D", "iload_3"); + + codeMap.put("25", "fload_3"); + + codeMap.put("1E", "lload_0"); + + codeMap.put("24", "fload_2"); + codeMap.put("4C", "astore_1"); + + codeMap.put("A2", "if_icmp_ge"); + codeMap.put("A4", "if_icmple"); + + codeMap.put("A7", "goto"); + + codeMap.put("B1", "return"); + codeMap.put("AC", "ireturn"); + codeMap.put("AE", "freturn"); + + codeMap.put("03", "iconst_0"); + codeMap.put("04", "iconst_1"); + + codeMap.put("3C", "istore_1"); + codeMap.put("3D", "istore_2"); + + codeMap.put("59", "dup"); + + codeMap.put("60", "iadd"); + codeMap.put("84", "iinc"); + + codeMap.put("12", "ldc"); + } + + + + + + protected ByteCodeCommand(ClassFile clzFile, String opCode){ + this.clzFile = clzFile; + this.opCode = opCode; + } + + protected ClassFile getClassFile() { + return clzFile; + } + + public int getOffset() { + return offset; + } + + public void setOffset(int offset) { + this.offset = offset; + } + protected ConstantInfo getConstantInfo(int index){ + return this.getClassFile().getConstantPool().getConstantInfo(index); + } + + protected ConstantPool getConstantPool(){ + return this.getClassFile().getConstantPool(); + } + + + + public String getOpCode() { + return opCode; + } + + public abstract int getLength(); + + + + + public String toString(){ + + StringBuffer buffer = new StringBuffer(); + buffer.append(this.opCode); + + return buffer.toString(); + } + public abstract String toString(ConstantPool pool); + + public String getReadableCodeText(){ + String txt = codeMap.get(opCode); + if(txt == null){ + return opCode; + } + return txt; + } + + //public abstract void execute(StackFrame frame,FrameResult result); +} diff --git a/group24/Homework/7-SevenWeek/jvm/cmd/CommandParser.java b/group24/Homework/7-SevenWeek/jvm/cmd/CommandParser.java new file mode 100644 index 0000000000..2bb36340f5 --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/cmd/CommandParser.java @@ -0,0 +1,85 @@ +package com.coderising.jvm.cmd; + +import java.util.ArrayList; +import java.util.List; + +import com.coderising.jvm.clz.ClassFile; + +public class CommandParser { + + public static final String aconst_null = "01"; + public static final String new_object = "BB"; + public static final String lstore = "37"; + public static final String invokespecial = "B7"; + public static final String invokevirtual = "B6"; + public static final String getfield = "B4"; + public static final String putfield = "B5"; + public static final String getstatic = "B2"; + public static final String ldc = "12"; + public static final String dup = "59"; + public static final String bipush = "10"; + public static final String aload_0 = "2A"; + public static final String aload_1 = "2B"; + public static final String aload_2 = "2C"; + public static final String iload = "15"; + public static final String iload_1 = "1B"; + public static final String iload_2 = "1C"; + public static final String iload_3 = "1D"; + public static final String fload_3 = "25"; + + public static final String voidreturn = "B1"; + public static final String ireturn = "AC"; + public static final String freturn = "AE"; + + public static final String astore_1 = "4C"; + public static final String if_icmp_ge = "A2"; + public static final String if_icmple = "A4"; + public static final String goto_no_condition = "A7"; + public static final String iconst_0 = "03"; + public static final String iconst_1 = "04"; + public static final String istore_1 = "3C"; + public static final String istore_2 = "3D"; + public static final String iadd = "60"; + public static final String iinc = "84"; + + public static ByteCodeCommand[] parse(ClassFile clzFile, String codes) { + + + return null; + } + + private static void calcuateOffset(List<ByteCodeCommand> cmds) { + + int offset = 0; + for (ByteCodeCommand cmd : cmds) { + cmd.setOffset(offset); + offset += cmd.getLength(); + } + + } + + private static class CommandIterator { + String codes = null; + int pos = 0; + + CommandIterator(String codes) { + this.codes = codes; + } + + public boolean hasNext() { + return pos < this.codes.length(); + } + + public String next2CharAsString() { + String result = codes.substring(pos, pos + 2); + pos += 2; + return result; + } + + public int next2CharAsInt() { + String s = this.next2CharAsString(); + return Integer.valueOf(s, 16).intValue(); + } + + } +} diff --git a/group24/Homework/7-SevenWeek/jvm/cmd/GetFieldCmd.java b/group24/Homework/7-SevenWeek/jvm/cmd/GetFieldCmd.java new file mode 100644 index 0000000000..2e6061edd2 --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/cmd/GetFieldCmd.java @@ -0,0 +1,22 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; + + +public class GetFieldCmd extends TwoOperandCmd { + + public GetFieldCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsField(pool); + } + + + + +} diff --git a/group24/Homework/7-SevenWeek/jvm/cmd/GetStaticFieldCmd.java b/group24/Homework/7-SevenWeek/jvm/cmd/GetStaticFieldCmd.java new file mode 100644 index 0000000000..e6cf9d5960 --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/cmd/GetStaticFieldCmd.java @@ -0,0 +1,23 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ClassInfo; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.FieldRefInfo; +import com.coderising.jvm.constant.UTF8Info; + + +public class GetStaticFieldCmd extends TwoOperandCmd { + + public GetStaticFieldCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsField(pool); + } + +} diff --git a/group24/Homework/7-SevenWeek/jvm/cmd/InvokeSpecialCmd.java b/group24/Homework/7-SevenWeek/jvm/cmd/InvokeSpecialCmd.java new file mode 100644 index 0000000000..ac228d0e4d --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/cmd/InvokeSpecialCmd.java @@ -0,0 +1,23 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.MethodRefInfo; + + +public class InvokeSpecialCmd extends TwoOperandCmd { + + public InvokeSpecialCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsMethod(pool); + } + + + +} diff --git a/group24/Homework/7-SevenWeek/jvm/cmd/InvokeVirtualCmd.java b/group24/Homework/7-SevenWeek/jvm/cmd/InvokeVirtualCmd.java new file mode 100644 index 0000000000..c15d827797 --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/cmd/InvokeVirtualCmd.java @@ -0,0 +1,22 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; + + +public class InvokeVirtualCmd extends TwoOperandCmd { + + public InvokeVirtualCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsMethod(pool); + } + + + + +} diff --git a/group24/Homework/7-SevenWeek/jvm/cmd/LdcCmd.java b/group24/Homework/7-SevenWeek/jvm/cmd/LdcCmd.java new file mode 100644 index 0000000000..ffb66f811c --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/cmd/LdcCmd.java @@ -0,0 +1,29 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantInfo; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.StringInfo; + +public class LdcCmd extends OneOperandCmd { + + public LdcCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + ConstantInfo info = (ConstantInfo)pool.getConstantInfo(this.getOperand()); + + String value = "TBD"; + if(info instanceof StringInfo){ + StringInfo strInfo = (StringInfo)info; + value = strInfo.toString(); + } + + return this.getOffset()+":"+this.getOpCode()+" " + this.getReadableCodeText() + " "+ value; + + } + +} diff --git a/group24/Homework/7-SevenWeek/jvm/cmd/NewObjectCmd.java b/group24/Homework/7-SevenWeek/jvm/cmd/NewObjectCmd.java new file mode 100644 index 0000000000..33813b5d59 --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/cmd/NewObjectCmd.java @@ -0,0 +1,19 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; + +public class NewObjectCmd extends TwoOperandCmd{ + + public NewObjectCmd(ClassFile clzFile, String opCode){ + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsClassInfo(pool); + } + + +} diff --git a/group24/Homework/7-SevenWeek/jvm/cmd/NoOperandCmd.java b/group24/Homework/7-SevenWeek/jvm/cmd/NoOperandCmd.java new file mode 100644 index 0000000000..56c28fefe2 --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/cmd/NoOperandCmd.java @@ -0,0 +1,23 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; + +public class NoOperandCmd extends ByteCodeCommand{ + + public NoOperandCmd(ClassFile clzFile, String opCode) { + super(clzFile, opCode); + } + + @Override + public String toString(ConstantPool pool) { + return this.getOffset()+":" +this.getOpCode() + " "+ this.getReadableCodeText(); + } + + + + public int getLength(){ + return 1; + } + +} diff --git a/group24/Homework/7-SevenWeek/jvm/cmd/OneOperandCmd.java b/group24/Homework/7-SevenWeek/jvm/cmd/OneOperandCmd.java new file mode 100644 index 0000000000..963d064257 --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/cmd/OneOperandCmd.java @@ -0,0 +1,27 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; + +public abstract class OneOperandCmd extends ByteCodeCommand { + + private int operand; + + public OneOperandCmd(ClassFile clzFile,String opCode) { + super(clzFile, opCode); + + } + public int getOperand() { + + return this.operand; + } + + public void setOperand(int oprand1) { + this.operand = oprand1; + + } + public int getLength(){ + return 2; + } + + +} diff --git a/group24/Homework/7-SevenWeek/jvm/cmd/PutFieldCmd.java b/group24/Homework/7-SevenWeek/jvm/cmd/PutFieldCmd.java new file mode 100644 index 0000000000..85bb369c19 --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/cmd/PutFieldCmd.java @@ -0,0 +1,19 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.constant.ConstantPool; + +public class PutFieldCmd extends TwoOperandCmd { + + public PutFieldCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsField(pool); + } + + +} diff --git a/group24/Homework/7-SevenWeek/jvm/cmd/TwoOperandCmd.java b/group24/Homework/7-SevenWeek/jvm/cmd/TwoOperandCmd.java new file mode 100644 index 0000000000..6c0cf53082 --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/cmd/TwoOperandCmd.java @@ -0,0 +1,67 @@ +package com.coderising.jvm.cmd; + +import com.coderising.jvm.clz.ClassFile; +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; + +public abstract class TwoOperandCmd extends ByteCodeCommand{ + + int oprand1 = -1; + int oprand2 = -1; + + public int getOprand1() { + return oprand1; + } + + public void setOprand1(int oprand1) { + this.oprand1 = oprand1; + } + + public void setOprand2(int oprand2) { + this.oprand2 = oprand2; + } + + public int getOprand2() { + return oprand2; + } + + public TwoOperandCmd(ClassFile clzFile,String opCode) { + super(clzFile, opCode); + } + + public int getIndex(){ + int oprand1 = this.getOprand1(); + int oprand2 = this.getOprand2(); + int index = oprand1 << 8 | oprand2; + return index; + } + + protected String getOperandAsClassInfo(ConstantPool pool){ + int index = getIndex(); + String codeTxt = getReadableCodeText(); + ClassInfo info = (ClassInfo)pool.getConstantInfo(index); + return this.getOffset()+":"+this.getOpCode()+" "+ codeTxt +" "+ info.getClassName(); + } + + protected String getOperandAsMethod(ConstantPool pool){ + int index = getIndex(); + String codeTxt = getReadableCodeText(); + ConstantInfo constInfo = this.getConstantInfo(index); + MethodRefInfo info = (MethodRefInfo)this.getConstantInfo(index); + return this.getOffset()+":"+this.getOpCode()+" " + codeTxt +" "+ info.toString(); + } + + protected String getOperandAsField(ConstantPool pool){ + int index = getIndex(); + + String codeTxt = getReadableCodeText(); + FieldRefInfo info = (FieldRefInfo)this.getConstantInfo(index); + return this.getOffset()+":"+this.getOpCode()+" " + codeTxt +" "+ info.toString(); + } + public int getLength(){ + return 3; + } +} diff --git a/group24/Homework/7-SevenWeek/jvm/constant/ClassInfo.java b/group24/Homework/7-SevenWeek/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..c8e65ff493 --- /dev/null +++ b/group24/Homework/7-SevenWeek/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(); + } + @Override + public void accept(Visitor visitor) { + visitor.visitClassInfo(this); + } +} diff --git a/group24/Homework/7-SevenWeek/jvm/constant/ConstantInfo.java b/group24/Homework/7-SevenWeek/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..88353df2d3 --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/constant/ConstantInfo.java @@ -0,0 +1,40 @@ +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); + } + + public abstract void accept(Visitor visitor); + + public static interface Visitor{ + public void visitClassInfo(ClassInfo info); + public void visitFieldRef(FieldRefInfo info); + public void visitMethodRef(MethodRefInfo info); + public void visitNameAndType(NameAndTypeInfo info); + public void visitString(StringInfo info); + public void visistUTF8(UTF8Info info); + + } +} diff --git a/group24/Homework/7-SevenWeek/jvm/constant/ConstantPool.java b/group24/Homework/7-SevenWeek/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..7130eb3a9f --- /dev/null +++ b/group24/Homework/7-SevenWeek/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<ConstantInfo> constantInfos = new ArrayList<ConstantInfo>(); + + + 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 int getSize() { + return this.constantInfos.size() -1; + } + + +} diff --git a/group24/Homework/7-SevenWeek/jvm/constant/FieldRefInfo.java b/group24/Homework/7-SevenWeek/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..7ae71396ef --- /dev/null +++ b/group24/Homework/7-SevenWeek/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(); + } + @Override + public void accept(Visitor visitor) { + visitor.visitFieldRef(this); + } +} diff --git a/group24/Homework/7-SevenWeek/jvm/constant/MethodRefInfo.java b/group24/Homework/7-SevenWeek/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..036e6d9055 --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/constant/MethodRefInfo.java @@ -0,0 +1,60 @@ +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(); + } + + @Override + public void accept(Visitor visitor) { + visitor.visitMethodRef(this); + } + + + +} diff --git a/group24/Homework/7-SevenWeek/jvm/constant/NameAndTypeInfo.java b/group24/Homework/7-SevenWeek/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..5cbbba6033 --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,51 @@ +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()+")"; + } + + @Override + public void accept(Visitor visitor) { + visitor.visitNameAndType(this); + + } +} diff --git a/group24/Homework/7-SevenWeek/jvm/constant/NullConstantInfo.java b/group24/Homework/7-SevenWeek/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..41e0fd7e7a --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/constant/NullConstantInfo.java @@ -0,0 +1,17 @@ +package com.coderising.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo(){ + + } + @Override + public int getType() { + return -1; + } + @Override + public void accept(Visitor visitor) { + + } + +} diff --git a/group24/Homework/7-SevenWeek/jvm/constant/StringInfo.java b/group24/Homework/7-SevenWeek/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..6bfcb47273 --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/constant/StringInfo.java @@ -0,0 +1,32 @@ +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); + } + + @Override + public void accept(Visitor visitor) { + visitor.visitString(this); + + } + +} diff --git a/group24/Homework/7-SevenWeek/jvm/constant/UTF8Info.java b/group24/Homework/7-SevenWeek/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..7db88a939e --- /dev/null +++ b/group24/Homework/7-SevenWeek/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; + } + @Override + public void accept(Visitor visitor) { + visitor.visistUTF8(this); + + } + + + +} diff --git a/group24/Homework/7-SevenWeek/jvm/field/Field.java b/group24/Homework/7-SevenWeek/jvm/field/Field.java new file mode 100644 index 0000000000..c6eb0196f8 --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/field/Field.java @@ -0,0 +1,50 @@ +package com.coderising.jvm.field; + +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.UTF8Info; +import com.coderising.jvm.loader.ByteCodeIterator; + + +public class Field { + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + + + private ConstantPool pool; + + public Field( int accessFlag, int nameIndex, int descriptorIndex,ConstantPool pool) { + + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + this.pool = pool; + } + + public String toString() { + String name = ((UTF8Info)pool.getConstantInfo(this.nameIndex)).getValue(); + + String desc = ((UTF8Info)pool.getConstantInfo(this.descriptorIndex)).getValue(); + return name +":"+ desc; + } + + + public static Field parse(ConstantPool pool,ByteCodeIterator iter){ + + int accessFlag = iter.nextU2ToInt(); + int nameIndex = iter.nextU2ToInt(); + int descIndex = iter.nextU2ToInt(); + int attribCount = iter.nextU2ToInt(); + //System.out.println("field attribute count:"+ attribCount); + + Field f = new Field(accessFlag, nameIndex, descIndex,pool); + + if(attribCount > 0){ + throw new RuntimeException("Field Attribute has not been implemented"); + } + + return f; + } + +} diff --git a/group24/Homework/7-SevenWeek/jvm/loader/ByteCodeIterator.java b/group24/Homework/7-SevenWeek/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..6fb5570dff --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,57 @@ +package com.coderising.jvm.loader; + +import java.util.Arrays; + +import com.coderising.jvm.util.Util; + +public class ByteCodeIterator { + byte[] codes; + int pos = 0; + + ByteCodeIterator(byte[] codes) { + this.codes = codes; + } + + + + 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; + } + + 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 nextUxToHexString(int len) { + byte[] tmp = new byte[len]; + + for (int i = 0; i < len; i++) { + tmp[i] = codes[pos++]; + } + return Util.byteToHexString(tmp).toLowerCase(); + + } + + public void back(int n) { + this.pos -= n; + } +} diff --git a/group24/Homework/7-SevenWeek/jvm/loader/ClassFileLoader.java b/group24/Homework/7-SevenWeek/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..33185d8175 --- /dev/null +++ b/group24/Homework/7-SevenWeek/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<String> clzPaths = new ArrayList<String>(); + + 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/group24/Homework/7-SevenWeek/jvm/loader/ClassFileParser.java b/group24/Homework/7-SevenWeek/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..a29d9572cd --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/loader/ClassFileParser.java @@ -0,0 +1,62 @@ +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; +import com.coderising.jvm.field.Field; +import com.coderising.jvm.method.Method; + +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; + } + private void parseInterfaces(ByteCodeIterator iter) { + int interfaceCount = iter.nextU2ToInt(); + + System.out.println("interfaceCount:" + interfaceCount); + + // TODO : 如果实现了interface, 这里需要解析 + } + + private void parseFileds(ClassFile clzFile, ByteCodeIterator iter) { + + + } + + private void parseMethods(ClassFile clzFile, ByteCodeIterator iter) { + + + + } + +} diff --git a/group24/Homework/7-SevenWeek/jvm/method/Method.java b/group24/Homework/7-SevenWeek/jvm/method/Method.java new file mode 100644 index 0000000000..b86c57ef90 --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/method/Method.java @@ -0,0 +1,80 @@ +package com.coderising.jvm.method; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.cmd.ByteCodeCommand; +import com.coderising.jvm.attr.AttributeInfo; +import com.coderising.jvm.attr.CodeAttr; +import com.coderising.jvm.constant.ConstantPool; +import com.coderising.jvm.constant.UTF8Info; +import com.coderising.jvm.loader.ByteCodeIterator; + + + +public class Method { + + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private CodeAttr codeAttr; + + private ClassFile clzFile; + + + public ClassFile getClzFile() { + return clzFile; + } + + public int getNameIndex() { + return nameIndex; + } + public int getDescriptorIndex() { + return descriptorIndex; + } + + public CodeAttr getCodeAttr() { + return codeAttr; + } + + public void setCodeAttr(CodeAttr code) { + this.codeAttr = code; + } + + + + public Method(ClassFile clzFile,int accessFlag, int nameIndex, int descriptorIndex) { + this.clzFile = clzFile; + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + } + + + + + + public String toString() { + + ConstantPool pool = this.clzFile.getConstantPool(); + StringBuilder buffer = new StringBuilder(); + + String name = ((UTF8Info)pool.getConstantInfo(this.nameIndex)).getValue(); + + String desc = ((UTF8Info)pool.getConstantInfo(this.descriptorIndex)).getValue(); + + buffer.append(name).append(":").append(desc).append("\n"); + + buffer.append(this.codeAttr.toString(pool)); + + return buffer.toString(); + } + + public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ + return null; + + } + + public ByteCodeCommand[] getCmds() { + return this.getCodeAttr().getCmds(); + } +} diff --git a/group24/Homework/7-SevenWeek/jvm/print/ClassFilePrinter.java b/group24/Homework/7-SevenWeek/jvm/print/ClassFilePrinter.java new file mode 100644 index 0000000000..14407bacbe --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/print/ClassFilePrinter.java @@ -0,0 +1,54 @@ +package com.coderising.jvm.print; + +import com.coderising.jvm.clz.ClassFile; +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.StringInfo; +import com.coderising.jvm.constant.UTF8Info; +import com.coderising.jvm.loader.ClassFileLoader; + +public class ClassFilePrinter { + ClassFile clzFile = null; + public ClassFilePrinter(ClassFile clzFile){ + this.clzFile = clzFile; + } + + public void print(){ + + if(clzFile.getAccessFlag().isPublicClass()){ + System.out.println("Access flag : public "); + } + System.out.println("Class Name:"+ clzFile.getClassName()); + + System.out.println("Super Class Name:"+ clzFile.getSuperClassName()); + + System.out.println("minor version:" + clzFile.getMinorVersion()); + + System.out.println("major version:" + clzFile.getMinorVersion()); + + ConstantPoolPrinter cnstPoolPrinter = new ConstantPoolPrinter(clzFile.getConstantPool()); + cnstPoolPrinter.print(); + + + + + } + + public static void main(String[] args){ + String path = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\mini-jvm\\bin"; + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path); + String className = "com.coderising.jvm.test.EmployeeV1"; + + ClassFile clzFile = loader.loadClass(className); + + ClassFilePrinter printer = new ClassFilePrinter(clzFile); + + printer.print(); + } +} diff --git a/group24/Homework/7-SevenWeek/jvm/print/ConstantPoolPrinter.java b/group24/Homework/7-SevenWeek/jvm/print/ConstantPoolPrinter.java new file mode 100644 index 0000000000..028161adc7 --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/print/ConstantPoolPrinter.java @@ -0,0 +1,25 @@ +package com.coderising.jvm.print; + +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.StringInfo; +import com.coderising.jvm.constant.UTF8Info; + +public class ConstantPoolPrinter { + ConstantPool pool; + ConstantPoolPrinter(ConstantPool pool){ + this.pool = pool; + } + public void print(){ + + System.out.println("Constant Pool:"); + + + + + } +} diff --git a/group24/Homework/7-SevenWeek/jvm/test/ClassFileloaderTest.java b/group24/Homework/7-SevenWeek/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..5657310e0d --- /dev/null +++ b/group24/Homework/7-SevenWeek/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,354 @@ +package com.coderising.jvm.test; + +import java.util.List; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.coderising.jvm.clz.ClassFile; +import com.coderising.jvm.clz.ClassIndex; +import com.coderising.jvm.cmd.BiPushCmd; +import com.coderising.jvm.cmd.ByteCodeCommand; +import com.coderising.jvm.cmd.OneOperandCmd; +import com.coderising.jvm.cmd.TwoOperandCmd; +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.field.Field; +import com.coderising.jvm.loader.ClassFileLoader; +import com.coderising.jvm.method.Method; + + + + + +public class ClassFileloaderTest { + + + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + + static String path1 = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\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); + + } + + + @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(); + } + + /** + * ---------------------------------------------------------------------- + */ + + + @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("<init>", 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()); + } + + /** + * 下面是第三次JVM课应实现的测试用例 + */ + @Test + public void testReadFields(){ + + List<Field> fields = clzFile.getFields(); + Assert.assertEquals(2, fields.size()); + { + Field f = fields.get(0); + Assert.assertEquals("name:Ljava/lang/String;", f.toString()); + } + { + Field f = fields.get(1); + Assert.assertEquals("age:I", f.toString()); + } + } + @Test + public void testMethods(){ + + List<Method> methods = clzFile.getMethods(); + ConstantPool pool = clzFile.getConstantPool(); + + { + Method m = methods.get(0); + assertMethodEquals(pool,m, + "<init>", + "(Ljava/lang/String;I)V", + "2ab7000c2a2bb5000f2a1cb50011b1"); + + } + { + Method m = methods.get(1); + assertMethodEquals(pool,m, + "setName", + "(Ljava/lang/String;)V", + "2a2bb5000fb1"); + + } + { + Method m = methods.get(2); + assertMethodEquals(pool,m, + "setAge", + "(I)V", + "2a1bb50011b1"); + } + { + Method m = methods.get(3); + assertMethodEquals(pool,m, + "sayHello", + "()V", + "b2001c1222b60024b1"); + + } + { + Method m = methods.get(4); + assertMethodEquals(pool,m, + "main", + "([Ljava/lang/String;)V", + "bb000159122b101db7002d4c2bb6002fb1"); + } + } + + private void assertMethodEquals(ConstantPool pool,Method m , String expectedName, String expectedDesc,String expectedCode){ + String methodName = pool.getUTF8String(m.getNameIndex()); + String methodDesc = pool.getUTF8String(m.getDescriptorIndex()); + String code = m.getCodeAttr().getCode(); + Assert.assertEquals(expectedName, methodName); + Assert.assertEquals(expectedDesc, methodDesc); + Assert.assertEquals(expectedCode, code); + } + + @Test + public void testByteCodeCommand(){ + { + Method initMethod = this.clzFile.getMethod("<init>", "(Ljava/lang/String;I)V"); + ByteCodeCommand [] cmds = initMethod.getCmds(); + + assertOpCodeEquals("0: aload_0", cmds[0]); + assertOpCodeEquals("1: invokespecial #12", cmds[1]); + assertOpCodeEquals("4: aload_0", cmds[2]); + assertOpCodeEquals("5: aload_1", cmds[3]); + assertOpCodeEquals("6: putfield #15", cmds[4]); + assertOpCodeEquals("9: aload_0", cmds[5]); + assertOpCodeEquals("10: iload_2", cmds[6]); + assertOpCodeEquals("11: putfield #17", cmds[7]); + assertOpCodeEquals("14: return", cmds[8]); + } + + { + Method setNameMethod = this.clzFile.getMethod("setName", "(Ljava/lang/String;)V"); + ByteCodeCommand [] cmds = setNameMethod.getCmds(); + + assertOpCodeEquals("0: aload_0", cmds[0]); + assertOpCodeEquals("1: aload_1", cmds[1]); + assertOpCodeEquals("2: putfield #15", cmds[2]); + assertOpCodeEquals("5: return", cmds[3]); + + } + + { + Method sayHelloMethod = this.clzFile.getMethod("sayHello", "()V"); + ByteCodeCommand [] cmds = sayHelloMethod.getCmds(); + + assertOpCodeEquals("0: getstatic #28", cmds[0]); + assertOpCodeEquals("3: ldc #34", cmds[1]); + assertOpCodeEquals("5: invokevirtual #36", cmds[2]); + assertOpCodeEquals("8: return", cmds[3]); + + } + + { + Method mainMethod = this.clzFile.getMainMethod(); + + ByteCodeCommand [] cmds = mainMethod.getCmds(); + + assertOpCodeEquals("0: new #1", cmds[0]); + assertOpCodeEquals("3: dup", cmds[1]); + assertOpCodeEquals("4: ldc #43", cmds[2]); + assertOpCodeEquals("6: bipush 29", cmds[3]); + assertOpCodeEquals("8: invokespecial #45", cmds[4]); + assertOpCodeEquals("11: astore_1", cmds[5]); + assertOpCodeEquals("12: aload_1", cmds[6]); + assertOpCodeEquals("13: invokevirtual #47", cmds[7]); + assertOpCodeEquals("16: return", cmds[8]); + } + + } + + private void assertOpCodeEquals(String expected, ByteCodeCommand cmd){ + + String acctual = cmd.getOffset()+": "+cmd.getReadableCodeText(); + + if(cmd instanceof OneOperandCmd){ + if(cmd instanceof BiPushCmd){ + acctual += " " + ((OneOperandCmd)cmd).getOperand(); + } else{ + acctual += " #" + ((OneOperandCmd)cmd).getOperand(); + } + } + if(cmd instanceof TwoOperandCmd){ + acctual += " #" + ((TwoOperandCmd)cmd).getIndex(); + } + Assert.assertEquals(expected, acctual); + } + +} diff --git a/group24/Homework/7-SevenWeek/jvm/test/EmployeeV1.java b/group24/Homework/7-SevenWeek/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..12e3d7efdd --- /dev/null +++ b/group24/Homework/7-SevenWeek/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/group24/Homework/7-SevenWeek/jvm/util/Util.java b/group24/Homework/7-SevenWeek/jvm/util/Util.java new file mode 100644 index 0000000000..0c4cc8c57c --- /dev/null +++ b/group24/Homework/7-SevenWeek/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<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 f33c43704415a5d775e06cb10b4936015999f522 Mon Sep 17 00:00:00 2001 From: sdnb <xgct0505@qq.com> Date: Mon, 17 Apr 2017 22:06:17 +0800 Subject: [PATCH 285/287] =?UTF-8?q?=E7=AC=AC=E5=85=AD=E5=91=A8=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coderising/jvm/attr/AttributeInfo.java | 19 +++ .../src/com/coderising/jvm/attr/CodeAttr.java | 89 ++++++++++++ .../coderising/jvm/attr/LineNumberTable.java | 52 +++++++ .../jvm/attr/LocalVariableItem.java | 39 ++++++ .../jvm/attr/LocalVariableTable.java | 39 ++++++ .../coderising/jvm/attr/StackMapTable.java | 30 +++++ .../src/com/coderising/jvm/clz/ClassFile.java | 41 ++++-- .../src/com/coderising/jvm/field/Field.java | 38 ++++++ .../jvm/loader/ByteCodeIterator.java | 22 ++- .../jvm/loader/ClassFileParser.java | 31 ++++- .../src/com/coderising/jvm/method/Method.java | 66 +++++++++ .../src/main/java/com/coding/weak1/Stack.java | 2 + .../java/com/coding/week6/expr/InfixExpr.java | 127 ++++++++++++++++++ .../java/com/coding/week6/expr/Token.java | 52 +++++++ .../mini_jvm/test/ClassFileloaderTest.java | 84 +++++++++++- .../coding/week6/expr/InfixExprTestTest.java | 77 +++++++++++ 16 files changed, 784 insertions(+), 24 deletions(-) create mode 100644 group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/AttributeInfo.java create mode 100644 group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/CodeAttr.java create mode 100644 group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/LineNumberTable.java create mode 100644 group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/LocalVariableItem.java create mode 100644 group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/LocalVariableTable.java create mode 100644 group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/StackMapTable.java create mode 100644 group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/field/Field.java create mode 100644 group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/method/Method.java create mode 100644 group24/494800949/src/main/java/com/coding/week6/expr/InfixExpr.java create mode 100644 group24/494800949/src/main/java/com/coding/week6/expr/Token.java create mode 100644 group24/494800949/src/test/java/com/coding/week6/expr/InfixExprTestTest.java diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/AttributeInfo.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/AttributeInfo.java new file mode 100644 index 0000000000..7db7a49c32 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/AttributeInfo.java @@ -0,0 +1,19 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.attr; + +public abstract class AttributeInfo { + public static final String CODE = "Code"; + public static final String CONST_VALUE = "ConstantValue"; + public static final String EXCEPTIONS = "Exceptions"; + public static final String LINE_NUM_TABLE = "LineNumberTable"; + public static final String LOCAL_VAR_TABLE = "LocalVariableTable"; + public static final String STACK_MAP_TABLE = "StackMapTable"; + int attrNameIndex; + int attrLen ; + public AttributeInfo(int attrNameIndex, int attrLen) { + + this.attrNameIndex = attrNameIndex; + this.attrLen = attrLen; + } + + +} diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/CodeAttr.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/CodeAttr.java new file mode 100644 index 0000000000..ee04b856d7 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/CodeAttr.java @@ -0,0 +1,89 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.attr; + + +import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassFile; +import com.coding.mini_jvm.src.com.coderising.jvm.loader.ByteCodeIterator; + +public class CodeAttr extends AttributeInfo { + private int maxStack ; + private int maxLocals ; + private int codeLen ; + private String code; + public String getCode() { + return code; + } + + //private ByteCodeCommand[] cmds ; + //public ByteCodeCommand[] getCmds() { + // return cmds; + //} + private LineNumberTable lineNumTable; + private LocalVariableTable localVarTable; + private StackMapTable stackMapTable; + + public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen,String code /*ByteCodeCommand[] cmds*/) { + super(attrNameIndex, attrLen); + this.maxStack = maxStack; + this.maxLocals = maxLocals; + this.codeLen = codeLen; + this.code = code; + //this.cmds = cmds; + } + + public void setLineNumberTable(LineNumberTable t) { + this.lineNumTable = t; + } + + public void setLocalVariableTable(LocalVariableTable t) { + this.localVarTable = t; + } + + public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ + + //回退2个字节 + iter.back(ByteCodeIterator.U2); + int attrNameIndex = iter.readTwoBytesToInt(); + int attrLen = iter.readFourBytesToInt(); + int maxStack = iter.readTwoBytesToInt(); + int maxLocal = iter.readTwoBytesToInt(); + int codeLen = iter.readFourBytesToInt(); + String code = iter.readBytesToString(codeLen); + CodeAttr codeAttr = new CodeAttr(attrNameIndex, attrLen, maxStack, maxLocal, codeLen, code); + + //异常表长度 + int exceptionTableLen = iter.readTwoBytesToInt(); + if (exceptionTableLen > 0) { + throw new RuntimeException("not impl yet"); + } + + //子属性个数 + int attrCount = iter.readTwoBytesToInt(); + for (int i = 0; i < attrCount; i++) { + attrNameIndex = iter.readTwoBytesToInt(); + String attrName = clzFile.getConstantPool().getUTF8String(attrNameIndex); + if ("LineNumberTable".equals(attrName)) { + LineNumberTable lineNumberTable = LineNumberTable.parse(iter); + codeAttr.setLineNumberTable(lineNumberTable); + } else if ("LocalVariableTable".equals(attrName)) { + LocalVariableTable localVariableTable = LocalVariableTable.parse(iter); + codeAttr.setLocalVariableTable(localVariableTable); + } else if ("StackMapTable".equals(attrName)) { + StackMapTable stackMapTable = StackMapTable.parse(iter); + codeAttr.setStackMapTable(stackMapTable); + } else { + throw new RuntimeException("not impl yet"); + } + } + + return codeAttr; + } + + private void setStackMapTable(StackMapTable t) { + this.stackMapTable = t; + } + + + + + +} diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/LineNumberTable.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/LineNumberTable.java new file mode 100644 index 0000000000..93e7d9b7a8 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/LineNumberTable.java @@ -0,0 +1,52 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.attr; + +import com.coding.mini_jvm.src.com.coderising.jvm.loader.ByteCodeIterator; + +import java.util.ArrayList; +import java.util.List; + + +public class LineNumberTable extends AttributeInfo { + List<LineNumberItem> items = new ArrayList<LineNumberItem>(); + + private static class LineNumberItem{ + int startPC; + int lineNum; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLineNum() { + return lineNum; + } + public void setLineNum(int lineNum) { + this.lineNum = lineNum; + } + } + public void addLineNumberItem(LineNumberItem item){ + this.items.add(item); + } + public LineNumberTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static LineNumberTable parse(ByteCodeIterator iter){ + iter.back(ByteCodeIterator.U2); + int attrNameIndex = iter.readTwoBytesToInt(); + int attrLen = iter.readFourBytesToInt(); + LineNumberTable lineNumberTable = new LineNumberTable(attrNameIndex, attrLen); + int itemCount = iter.readTwoBytesToInt(); + for (int i = 0; i < itemCount; i++) { + LineNumberItem lineNumberItem = new LineNumberItem(); + lineNumberItem.setStartPC(iter.readTwoBytesToInt()); + lineNumberItem.setLineNum(iter.readTwoBytesToInt()); + lineNumberTable.addLineNumberItem(lineNumberItem); + } + return lineNumberTable; + } + + + +} diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/LocalVariableItem.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/LocalVariableItem.java new file mode 100644 index 0000000000..9e9e1d9e21 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/LocalVariableItem.java @@ -0,0 +1,39 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.attr; + +public class LocalVariableItem { + private int startPC; + private int length; + private int nameIndex; + private int descIndex; + private int index; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getNameIndex() { + return nameIndex; + } + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + public int getDescIndex() { + return descIndex; + } + public void setDescIndex(int descIndex) { + this.descIndex = descIndex; + } + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } +} diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/LocalVariableTable.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/LocalVariableTable.java new file mode 100644 index 0000000000..2900349fa5 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/LocalVariableTable.java @@ -0,0 +1,39 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.attr; + + +import com.coding.mini_jvm.src.com.coderising.jvm.loader.ByteCodeIterator; + +import java.util.ArrayList; +import java.util.List; + +public class LocalVariableTable extends AttributeInfo{ + + List<LocalVariableItem> items = new ArrayList<LocalVariableItem>(); + + public LocalVariableTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static LocalVariableTable parse(ByteCodeIterator iter){ + iter.back(ByteCodeIterator.U2); + int attrNameIdex = iter.readTwoBytesToInt(); + int attrLen = iter.readFourBytesToInt(); + LocalVariableTable localVariableTable = new LocalVariableTable(attrNameIdex, attrLen); + int varCount = iter.readTwoBytesToInt(); + for (int i = 0; i < varCount; i++) { + LocalVariableItem item = new LocalVariableItem(); + item.setStartPC(iter.readTwoBytesToInt()); + item.setLength(iter.readTwoBytesToInt()); + item.setNameIndex(iter.readTwoBytesToInt()); + item.setDescIndex(iter.readTwoBytesToInt()); + item.setIndex(iter.readTwoBytesToInt()); + localVariableTable.addLocalVariableItem(item); + } + return localVariableTable; + } + private void addLocalVariableItem(LocalVariableItem item) { + this.items.add(item); + } + + +} diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/StackMapTable.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/StackMapTable.java new file mode 100644 index 0000000000..a6e55353f1 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/StackMapTable.java @@ -0,0 +1,30 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.attr; + + +import com.coding.mini_jvm.src.com.coderising.jvm.loader.ByteCodeIterator; + +public class StackMapTable extends AttributeInfo{ + + private String originalCode; + + public StackMapTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static StackMapTable parse(ByteCodeIterator iter){ + iter.back(ByteCodeIterator.U2); + int index = iter.readTwoBytesToInt(); + int len = iter.readFourBytesToInt(); + StackMapTable t = new StackMapTable(index,len); + + //后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 + String code = iter.readBytesToString(len); + t.setOriginalCode(code); + return t; + } + + private void setOriginalCode(String code) { + this.originalCode = code; + + } +} diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/clz/ClassFile.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/clz/ClassFile.java index 0d2525e416..047c65195f 100644 --- a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/clz/ClassFile.java +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/clz/ClassFile.java @@ -3,28 +3,50 @@ import com.coding.mini_jvm.src.com.coderising.jvm.constant.ClassInfo; import com.coding.mini_jvm.src.com.coderising.jvm.constant.ConstantPool; +import com.coding.mini_jvm.src.com.coderising.jvm.field.Field; +import com.coding.mini_jvm.src.com.coderising.jvm.method.Method; + +import java.util.ArrayList; +import java.util.List; public class ClassFile { - + private int minorVersion; private int majorVersion; - + private AccessFlag accessFlag; private ClassIndex clzIndex; private ConstantPool pool; - - + private List<Field> fields = new ArrayList<Field>(); + private List<Method> methods = new ArrayList<Method>(); + public ClassIndex getClzIndex() { return clzIndex; } + public AccessFlag getAccessFlag() { return accessFlag; } + public void setAccessFlag(AccessFlag accessFlag) { this.accessFlag = accessFlag; } - - + + public void addField(Field f) { + this.fields.add(f); + } + + public List<Field> getFields() { + return this.fields; + } + + public void addMethod(Method m) { + this.methods.add(m); + } + + public List<Method> getMethods() { + return methods; + } public ConstantPool getConstantPool() { return pool; @@ -49,19 +71,12 @@ 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(){ diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/field/Field.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/field/Field.java new file mode 100644 index 0000000000..18bcdb2851 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/field/Field.java @@ -0,0 +1,38 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.field; + + +import com.coding.mini_jvm.src.com.coderising.jvm.constant.ConstantPool; +import com.coding.mini_jvm.src.com.coderising.jvm.loader.ByteCodeIterator; + +public class Field { + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + + private ConstantPool pool; + + public Field(int accessFlag, int nameIndex, int descriptorIndex, ConstantPool pool) { + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + this.pool = pool; + } + + + public static Field parse(ConstantPool pool,ByteCodeIterator iter){ + int accessFlag = iter.readTwoBytesToInt(); + int nameIndex = iter.readTwoBytesToInt(); + int descIndex = iter.readTwoBytesToInt(); + int attributesCount = iter.readTwoBytesToInt(); + if (attributesCount > 0) + throw new RuntimeException("attributeCount of field not impl"); + return new Field(accessFlag, nameIndex, descIndex, pool); + } + + + @Override + public String toString() { + return pool.getUTF8String(nameIndex)+":"+pool.getUTF8String(descriptorIndex); + } +} diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java index 27d0c63af0..1fe59b5bdb 100644 --- a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java @@ -3,10 +3,10 @@ import com.coding.mini_jvm.src.com.coderising.jvm.util.Util; public class ByteCodeIterator { - private static final int U1 = 1; - private static final int U2 = 2; - private static final int U4 = 4; - private static final int U8 = 8; + public static final int U1 = 1; + public static final int U2 = 2; + public static final int U4 = 4; + public static final int U8 = 8; private byte[] bytes; private int cursor; @@ -33,6 +33,12 @@ public int readTwoBytesToInt() { return ret; } + public int readFourBytesToInt() { + int ret = Util.bytes2Int(bytes, cursor, U4); + cursor += U4; + return ret; + } + public int readByteToInt() { int ret = Util.bytes2Int(bytes, cursor, U1); cursor += U1; @@ -49,4 +55,12 @@ public int skip(int len) { cursor += len; return cursor; } + + public int back(int len) { + if (cursor + len < 0 || cursor + len > bytes.length - 1) { + throw new IndexOutOfBoundsException(); + } + cursor -= len; + return cursor; + } } diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/loader/ClassFileParser.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/loader/ClassFileParser.java index 542968c809..afe40a2156 100644 --- a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/loader/ClassFileParser.java +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/loader/ClassFileParser.java @@ -4,6 +4,8 @@ import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassFile; import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassIndex; import com.coding.mini_jvm.src.com.coderising.jvm.constant.*; +import com.coding.mini_jvm.src.com.coderising.jvm.field.Field; +import com.coding.mini_jvm.src.com.coderising.jvm.method.Method; public class ClassFileParser { @@ -18,11 +20,22 @@ public ClassFile parse(byte[] codes) { //主版本号 classFile.setMajorVersion(iterator.readTwoBytesToInt()); //解析常量池 - classFile.setConstPool(parseConstantPool(iterator)); + ConstantPool constantPool = parseConstantPool(iterator); + classFile.setConstPool(constantPool); //访问限制符 classFile.setAccessFlag(parseAccessFlag(iterator)); //当前类/父类 classFile.setClassIndex(parseClassIndex(iterator)); + + //接口数量暂时不实现 + int intefaceCount = iterator.readTwoBytesToInt(); + if (intefaceCount > 0) { + throw new RuntimeException(); + } + //解析字段 + parseFields(classFile,iterator, constantPool); + //解析方法 + parseMethod(classFile, iterator, constantPool); return classFile; } @@ -99,5 +112,19 @@ private ConstantPool parseConstantPool(ByteCodeIterator iterator) { return constantPool; } - + + private void parseFields(ClassFile classFile, ByteCodeIterator iterator, ConstantPool constantPool) { + int fieldCount = iterator.readTwoBytesToInt(); + for (int i = 0; i < fieldCount; i++) + classFile.addField(Field.parse(constantPool, iterator)); + } + + + private void parseMethod(ClassFile clzFile, ByteCodeIterator iter, ConstantPool pool) { + int methodCount = iter.readTwoBytesToInt(); + for (int i = 0; i < methodCount; i++) { + clzFile.addMethod(Method.parse(clzFile, iter)); + } + } + } diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/method/Method.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/method/Method.java new file mode 100644 index 0000000000..fd5734e6b6 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/method/Method.java @@ -0,0 +1,66 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.method; + + +import com.coding.mini_jvm.src.com.coderising.jvm.attr.CodeAttr; +import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassFile; +import com.coding.mini_jvm.src.com.coderising.jvm.loader.ByteCodeIterator; + +public class Method { + + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private CodeAttr codeAttr; + + private ClassFile clzFile; + + public ClassFile getClzFile() { + return clzFile; + } + + public int getNameIndex() { + return nameIndex; + } + + public int getDescriptorIndex() { + return descriptorIndex; + } + + public CodeAttr getCodeAttr() { + return codeAttr; + } + + public void setCodeAttr(CodeAttr code) { + this.codeAttr = code; + } + + public Method(ClassFile clzFile,int accessFlag, int nameIndex, int descriptorIndex) { + this.clzFile = clzFile; + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + } + + + public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ + int accessFlag = iter.readTwoBytesToInt(); + int nameIndex = iter.readTwoBytesToInt(); + int descIndex = iter.readTwoBytesToInt(); + Method method = new Method(clzFile, accessFlag, nameIndex, descIndex); + System.out.println(clzFile.getConstantPool().getUTF8String(descIndex)); + int attrCount = iter.readTwoBytesToInt(); + if (attrCount > 1) + throw new RuntimeException("other attrbute not impl yet"); + for (int i = 0; i < attrCount; i++) { + int attrNameIndex = iter.readTwoBytesToInt(); + if ("Code".equals(clzFile.getConstantPool().getUTF8String(attrNameIndex))) { + CodeAttr codeAttr = CodeAttr.parse(clzFile, iter); + method.setCodeAttr(codeAttr); + } else + throw new RuntimeException("not impl yet"); + } + return method; + } + +} diff --git a/group24/494800949/src/main/java/com/coding/weak1/Stack.java b/group24/494800949/src/main/java/com/coding/weak1/Stack.java index ffa00f99e7..0eecd9d684 100644 --- a/group24/494800949/src/main/java/com/coding/weak1/Stack.java +++ b/group24/494800949/src/main/java/com/coding/weak1/Stack.java @@ -18,6 +18,8 @@ public Object pop(){ } public Object peek(){ + if (size() == 0) + return null; return elementData.get(elementData.size()-1); } public boolean isEmpty(){ diff --git a/group24/494800949/src/main/java/com/coding/week6/expr/InfixExpr.java b/group24/494800949/src/main/java/com/coding/week6/expr/InfixExpr.java new file mode 100644 index 0000000000..34c1b15123 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/week6/expr/InfixExpr.java @@ -0,0 +1,127 @@ +package com.coding.week6.expr; + +import com.coding.weak1.Stack; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class InfixExpr { + String expr = null; + private Stack numberStack; + private Stack operatorStack; + private List<Token> tokens; + public InfixExpr(String expr) { + this.expr = expr; + this.numberStack = new Stack(); + this.operatorStack = new Stack(); + tokens = new ArrayList<>(); + } + + + public float evaluate() { + fillStack(); + while (!operatorStack.isEmpty()) { + char symbol = (char) operatorStack.pop(); + float operTop1 = (float) numberStack.pop(); + float operTop2 = (float) numberStack.pop(); + numberStack.push(caculate(symbol, operTop2, operTop1)); + } + return (float)numberStack.pop(); + } + + public void parseTokens() { + char[] chars = expr.toCharArray(); + for (int i = 0; i < chars.length; i++) { + char c = chars[i]; + if (Token.isOperator(c)) { + Token token = new Token(c+""); + tokens.add(token); + } else { + String t = ""; + while (Token.isDigit(c)){ + t += c; + i++; + if (i == chars.length) + break; + c = chars[i]; + } + Token token = new Token(t); + tokens.add(token); + i--; + } + } + } + + + public void fillStack() { + parseTokens(); + Iterator<Token> iterator = tokens.iterator(); + while (iterator.hasNext()) { + Token token = iterator.next(); + if (token.isNumber()) { + numberStack.push((float)token.parseInt()); + continue; + } + if (token.isOperator()) { + char operator = token.parseOperator(); + if (operatorStack.isEmpty()) { + operatorStack.push(operator); + }else { + char topSymbol = (char)operatorStack.peek(); + if (compare(operator, topSymbol) > 0) { + operatorStack.push(operator); + } else { + float operTop1 = (float) numberStack.pop(); + float operTop2 = (float) numberStack.pop(); + numberStack.push(caculate(topSymbol, operTop2, operTop1)); + operatorStack.pop(); + operatorStack.push(operator); + } + } + } + + } + } + + + private float caculate(char symbol, float oper1, float oper2) { + if ('*' == symbol) + return oper1 * oper2; + else if ('/' == symbol) + return oper1 / oper2; + else if ('+' == symbol) + return oper1 + oper2; + else if ('-' == symbol) + return oper1 - oper2; + else + throw new RuntimeException("this operation has not implement"); + } + + public int compare(char opertor1, char opertor2) { + if (!Token.isOperator(opertor1) ) + throw new IllegalArgumentException(opertor1 + "is not supported opertor"); + if (!Token.isOperator(opertor2)) + throw new IllegalArgumentException(opertor2 + "is not supported opertor"); + if (Token.isAddOrSub(opertor1)) { + if (Token.isAddOrSub(opertor2)) + return 0; + else + return -1; + } + else { + if (Token.isAddOrSub(opertor2)) + return 1; + else + return 0; + } + } + + public String printNumberStack() { + return numberStack.toString(); + } + + public String printOperatorStack() { + return operatorStack.toString(); + } +} diff --git a/group24/494800949/src/main/java/com/coding/week6/expr/Token.java b/group24/494800949/src/main/java/com/coding/week6/expr/Token.java new file mode 100644 index 0000000000..b58aa36968 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/week6/expr/Token.java @@ -0,0 +1,52 @@ +package com.coding.week6.expr; + +/** + * Created by Administrator on 2017/4/16 0016. + */ +public class Token { + + private String symbol; + + public Token(String symbol) { + this.symbol = symbol; + } + + public boolean isNumber() { + return symbol.matches("^\\d+$"); + } + + + public boolean isOperator() { + return symbol.matches("^[\\+|\\*|\\-|\\/]$"); + } + + public int parseInt() { + return Integer.valueOf(symbol); + } + + public char parseOperator() { + return symbol.charAt(0); + } + + + public static boolean isOperator(char c) { + return isAddOrSub(c) || isMulityOrDivide(c); + } + + public static boolean isAddOrSub(char c) { + return c == '+' || c == '-'; + } + + public static boolean isMulityOrDivide(char c) { + return c == '/' || c == '*'; + } + + public static boolean isDigit(char c) { + return c >= '0' && c <= '9'; + } + + @Override + public String toString(){ + return symbol; + } +} 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 index a03f29c0c3..00812bcd80 100644 --- 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 @@ -3,22 +3,22 @@ import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassFile; import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassIndex; import com.coding.mini_jvm.src.com.coderising.jvm.constant.*; +import com.coding.mini_jvm.src.com.coderising.jvm.field.Field; import com.coding.mini_jvm.src.com.coderising.jvm.loader.ClassFileLoader; +import com.coding.mini_jvm.src.com.coderising.jvm.method.Method; import com.coding.mini_jvm.src.com.coderising.jvm.util.Util; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; - - - +import java.util.List; public class ClassFileloaderTest { - static String path1 = "H:\\sourceCode\\coding2017\\group24\\494800949\\build\\classes\\test"; + static String path1 = "H:\\sourceCode\\coding2017\\group24\\494800949"; static String path2 = "C:\temp"; private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; @@ -27,7 +27,7 @@ public class ClassFileloaderTest { static { ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); - String className = "com.coding.mini_jvm.test.EmployeeV1"; + String className = "EmployeeV1"; clzFile = loader.loadClass(className); // clzFile.print(); @@ -170,4 +170,78 @@ public void testClassIndex(){ Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); } + + + + /** + * 下面是第三次JVM课应实现的测试用例 + */ + @Test + public void testReadFields(){ + + List<Field> fields = clzFile.getFields(); + Assert.assertEquals(2, fields.size()); + { + Field f = fields.get(0); + Assert.assertEquals("name:Ljava/lang/String;", f.toString()); + } + { + Field f = fields.get(1); + Assert.assertEquals("age:I", f.toString()); + } + } + @Test + public void testMethods(){ + + List<Method> methods = clzFile.getMethods(); + ConstantPool pool = clzFile.getConstantPool(); + + { + Method m = methods.get(0); + assertMethodEquals(pool,m, + "<init>", + "(Ljava/lang/String;I)V", + "2ab7000c2a2bb5000f2a1cb50011b1"); + + } + { + Method m = methods.get(1); + assertMethodEquals(pool,m, + "setName", + "(Ljava/lang/String;)V", + "2a2bb5000fb1"); + + } + { + Method m = methods.get(2); + assertMethodEquals(pool,m, + "setAge", + "(I)V", + "2a1bb50011b1"); + } + { + Method m = methods.get(3); + assertMethodEquals(pool,m, + "sayHello", + "()V", + "b2001c1222b60024b1"); + + } + { + Method m = methods.get(4); + assertMethodEquals(pool,m, + "main", + "([Ljava/lang/String;)V", + "bb000159122b101db7002d4c2bb6002fb1"); + } + } + + private void assertMethodEquals(ConstantPool pool,Method m , String expectedName, String expectedDesc,String expectedCode){ + String methodName = pool.getUTF8String(m.getNameIndex()); + String methodDesc = pool.getUTF8String(m.getDescriptorIndex()); + String code = m.getCodeAttr().getCode(); + Assert.assertEquals(expectedName, methodName); + Assert.assertEquals(expectedDesc, methodDesc); + Assert.assertEquals(expectedCode, code); + } } diff --git a/group24/494800949/src/test/java/com/coding/week6/expr/InfixExprTestTest.java b/group24/494800949/src/test/java/com/coding/week6/expr/InfixExprTestTest.java new file mode 100644 index 0000000000..7ef4b9ccfa --- /dev/null +++ b/group24/494800949/src/test/java/com/coding/week6/expr/InfixExprTestTest.java @@ -0,0 +1,77 @@ +package com.coding.week6.expr; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * Created by Administrator on 2017/4/16 0016. + */ +public class InfixExprTestTest { + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + //InfixExpr expr = new InfixExpr("300*20+12*5-20/4"); + + { + InfixExpr expr = new InfixExpr("2+3*4+5"); + Assert.assertEquals(19.0, expr.evaluate(), 0.001f); + } + { + InfixExpr expr = new InfixExpr("3*20+12*5-40/2"); + Assert.assertEquals(100.0, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("3*20/2"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("20/2*3"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("10-30+50"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + } + + + @Test + public void testFillStack() { + InfixExpr expr = new InfixExpr("10-30+50"); + expr.fillStack(); + Assert.assertEquals(expr.printNumberStack(), "50.0,-20.0"); + Assert.assertEquals(expr.printOperatorStack(), "+"); + expr = new InfixExpr("3*20+12*5-40/2"); + expr.fillStack(); + Assert.assertEquals(expr.printNumberStack(), "2.0,40.0,60.0,60.0"); + Assert.assertEquals(expr.printOperatorStack(), "/,-,+"); + expr = new InfixExpr("3*20/2"); + expr.fillStack(); + Assert.assertEquals(expr.printNumberStack(), "2.0,60.0"); + Assert.assertEquals(expr.printOperatorStack(), "/"); + expr = new InfixExpr("20/2*3"); + expr.fillStack(); + Assert.assertEquals(expr.printNumberStack(), "3.0,10.0"); + Assert.assertEquals(expr.printOperatorStack(), "*"); + expr = new InfixExpr("10-30+50"); + expr.fillStack(); + Assert.assertEquals(expr.printNumberStack(), "50.0,-20.0"); + Assert.assertEquals(expr.printOperatorStack(), "+"); + } + + + +} \ No newline at end of file From 7fbba66921c3761f6bf009a0d12abd15e1f9217a Mon Sep 17 00:00:00 2001 From: macvis_qq75939388 <macvis@126.com> Date: Tue, 18 Apr 2017 13:14:04 +0800 Subject: [PATCH 286/287] =?UTF-8?q?=E4=BD=9C=E4=B8=9A=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E4=BF=9D=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/basic/dataStructure/ArrayList.java | 115 ++++++ .../java/basic/dataStructure/ArrayUtil.java | 245 +++++++++++++ .../basic/dataStructure/BinaryTreeNode.java | 58 +++ .../java/basic/dataStructure/LinkedList.java | 341 ++++++++++++++++++ .../main/java/basic/dataStructure/List.java | 12 + .../main/java/basic/dataStructure/Queue.java | 72 ++++ .../main/java/basic/dataStructure/Stack.java | 41 +++ .../java/basic/liteStruts/LoginAction.java | 39 ++ .../main/java/basic/liteStruts/ReadXML.java | 28 ++ .../main/java/basic/liteStruts/Struts.java | 78 ++++ .../src/main/java/basic/liteStruts/View.java | 23 ++ .../src/main/java/miniJVM/Demo.java | 7 + .../java/thread/download/DownloadThread.java | 39 ++ .../java/thread/download/FileDownloader.java | 106 ++++++ .../java/thread/download/api/Connection.java | 23 ++ .../download/api/ConnectionException.java | 8 + .../download/api/ConnectionManager.java | 10 + .../thread/download/api/DownloadListener.java | 5 + .../thread/download/impl/ConnectionImpl.java | 93 +++++ .../download/impl/ConnectionManagerImpl.java | 20 + .../java/data_structure/ArrayListTest.java | 69 ++++ .../java/data_structure/ArrayUtilTest.java | 67 ++++ .../data_structure/BinaryNodeTreeTest.java | 29 ++ .../java/data_structure/LinkedListTest.java | 151 ++++++++ .../test/java/data_structure/QueueTest.java | 50 +++ .../test/java/data_structure/StackTest.java | 49 +++ .../java/download/FileDownloaderTest.java | 54 +++ .../src/test/java/liteStruts/StrutsTest.java | 42 +++ 28 files changed, 1874 insertions(+) create mode 100644 group24/75939388/learning2017/src/main/java/basic/dataStructure/ArrayList.java create mode 100644 group24/75939388/learning2017/src/main/java/basic/dataStructure/ArrayUtil.java create mode 100644 group24/75939388/learning2017/src/main/java/basic/dataStructure/BinaryTreeNode.java create mode 100644 group24/75939388/learning2017/src/main/java/basic/dataStructure/LinkedList.java create mode 100644 group24/75939388/learning2017/src/main/java/basic/dataStructure/List.java create mode 100644 group24/75939388/learning2017/src/main/java/basic/dataStructure/Queue.java create mode 100644 group24/75939388/learning2017/src/main/java/basic/dataStructure/Stack.java create mode 100644 group24/75939388/learning2017/src/main/java/basic/liteStruts/LoginAction.java create mode 100644 group24/75939388/learning2017/src/main/java/basic/liteStruts/ReadXML.java create mode 100644 group24/75939388/learning2017/src/main/java/basic/liteStruts/Struts.java create mode 100644 group24/75939388/learning2017/src/main/java/basic/liteStruts/View.java create mode 100644 group24/75939388/learning2017/src/main/java/miniJVM/Demo.java create mode 100644 group24/75939388/learning2017/src/main/java/thread/download/DownloadThread.java create mode 100644 group24/75939388/learning2017/src/main/java/thread/download/FileDownloader.java create mode 100644 group24/75939388/learning2017/src/main/java/thread/download/api/Connection.java create mode 100644 group24/75939388/learning2017/src/main/java/thread/download/api/ConnectionException.java create mode 100644 group24/75939388/learning2017/src/main/java/thread/download/api/ConnectionManager.java create mode 100644 group24/75939388/learning2017/src/main/java/thread/download/api/DownloadListener.java create mode 100644 group24/75939388/learning2017/src/main/java/thread/download/impl/ConnectionImpl.java create mode 100644 group24/75939388/learning2017/src/main/java/thread/download/impl/ConnectionManagerImpl.java create mode 100644 group24/75939388/learning2017/src/test/java/data_structure/ArrayListTest.java create mode 100644 group24/75939388/learning2017/src/test/java/data_structure/ArrayUtilTest.java create mode 100644 group24/75939388/learning2017/src/test/java/data_structure/BinaryNodeTreeTest.java create mode 100644 group24/75939388/learning2017/src/test/java/data_structure/LinkedListTest.java create mode 100644 group24/75939388/learning2017/src/test/java/data_structure/QueueTest.java create mode 100644 group24/75939388/learning2017/src/test/java/data_structure/StackTest.java create mode 100644 group24/75939388/learning2017/src/test/java/download/FileDownloaderTest.java create mode 100644 group24/75939388/learning2017/src/test/java/liteStruts/StrutsTest.java diff --git a/group24/75939388/learning2017/src/main/java/basic/dataStructure/ArrayList.java b/group24/75939388/learning2017/src/main/java/basic/dataStructure/ArrayList.java new file mode 100644 index 0000000000..8ae862da33 --- /dev/null +++ b/group24/75939388/learning2017/src/main/java/basic/dataStructure/ArrayList.java @@ -0,0 +1,115 @@ +package basic.dataStructure; + +/** + * Created by macvi on 2017/4/2. + */ +public class ArrayList implements List { + private int size = 10; + //每次扩容的长度,默认为10 + private int extendSize = 10; + + private Object[] data = new Object[size]; + + public ArrayList(Object o) { + this.add(o); + } + + public ArrayList(){} + + public void add(Object o) { + if (this.size() == this.size) { + this.size += extendSize; + Object[] newData = new Object[this.size]; + System.arraycopy(this.data, 0, newData, 0, this.data.length); + this.data = newData; + } + + for (int i = 0; i < this.data.length; i++) { + if (data[i] == null) { + data[i] = o; + break; + } else continue; + } + } + + public void add(int index, Object o) { + if (index > this.size() || index < 0) { + throw new IndexOutOfBoundsException(); + } + + if(this.size() == this.size){ + this.size += extendSize; + } + + Object[] newData = new Object[this.size]; + + System.arraycopy(this.data, 0, newData, 0, index); + newData[index] = o; + System.arraycopy(this.data, index, newData, index + 1, this.size() - index); + + this.data = newData; + } + + public Object get(int index) { + if(index > this.size() || index < 0){ + throw new IndexOutOfBoundsException(); + } + for(int i = 0; i < this.size(); i ++){ + if(index == i){ + return this.data[i]; + } + } + + return null; + } + + public Object remove(int index) { + if(index > this.size() || index < 0){ + throw new IndexOutOfBoundsException(); + } + + Object[] newData = new Object[this.size]; + Object removed = this.get(index); + + System.arraycopy(this.data, 0, newData, 0, index); + System.arraycopy(this.data, index + 1, newData, index, this.size() - index); + this.data = newData; + return removed; + } + + public int size() { + int size = 0; + for(Object obj : this.data){ + if(obj != null){ + size += 1; + } + } + + return size; + } + + public boolean contains(Object obj){ + for(int i = 0; i < this.size(); i++){ + if(obj == this.get(i)){ + return true; + } + } + + return false; + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + for(Object obj : data){ + if(obj != null){ + sb.append(obj.toString()).append(","); + }else { +// sb.append("null,"); + continue; + } + } + + return sb.toString(); + } +} diff --git a/group24/75939388/learning2017/src/main/java/basic/dataStructure/ArrayUtil.java b/group24/75939388/learning2017/src/main/java/basic/dataStructure/ArrayUtil.java new file mode 100644 index 0000000000..22bccaaf5b --- /dev/null +++ b/group24/75939388/learning2017/src/main/java/basic/dataStructure/ArrayUtil.java @@ -0,0 +1,245 @@ +package basic.dataStructure; + +/** + * @author : 温友朝 + * @date : 2017/4/5 + */ +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[] reversed = new int[length]; + for (int i = length - 1; i >= 0; i--) { + reversed[length - i - 1] = origin[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 length = oldArray.length; + int[] arr = new int[length]; + int index = 0; + for (int i = 0; i < length; i++) { + if (oldArray[i] != 0) { + arr[index] = oldArray[i]; + index++; + } + } + //非0的数据个数 + int[] newArr = new int[index]; + System.arraycopy(arr, 0, newArr, 0, index); + return newArr; + } + + public static Object[] remove(Object[] oldArray, Object value){ + int length = oldArray.length; + Object[] arr = new Object[length]; + int index = 0; + for (int i = 0; i < length; i++) { + if (oldArray[i] != value) { + arr[index] = oldArray[i]; + index++; + } + } + Object[] newArr = new Object[index]; + System.arraycopy(arr, 0, newArr, 0, index); + 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] , 注意: 已经消除了重复 + * + * @param array1 + * @param array2 + * @return + */ + + public int[] merge(int[] array1, int[] array2) { + int length1 = array1.length; + int length2 = array2.length; + int[] arr = new int[length1 + length2]; + + System.arraycopy(array1, 0, arr, 0, length1); + System.arraycopy(array2, 0, arr, length1, length2); + + //去重 + for(int i = 0; i < arr.length; i++){ + for(int j = 0; j < arr.length; j++){ + if(i != j && arr[i] == arr[j]){ + arr[j] = 0; + } + } + } + + + int[] data = removeZero(arr); + int length = data.length; + + //排序 + for (int i = 0; i < length; i++) { + for(int j = 0; j < length; j++){ + if(data[i] < data[j]){ + int tmp = data[i]; + data[i] = data[j]; + data[j] = tmp; + } + } + } + return data; + } + + + /** + * 把一个已经存满数据的数组 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[] arr = new int[oldArray.length + size]; + System.arraycopy(oldArray, 0, arr, 0, oldArray.length); + return arr; + } + + /** + * 斐波那契数列为:1,1,2,3,5,8,13,21...... ,给定一个最大值, 返回小于该值的数列 + * 例如, max = 15 , 则返回的数组应该为 [1,1,2,3,5,8,13] + * max = 1, 则返回空数组 [] + * F(0)=0,F(1)=1, F(n)=F(n-1)+F(n-2)(n>=2,n∈N*) + * @param max + * @return + */ + public int[] fibonacci(int max) { + int[] empty = {}; + int[] arr2 = {1, 1}; + + switch (max){ + case 0 : return empty; + case 1 : return empty; + case 2 : return arr2; + default: { + int[] data = arr2; + int d = data[0] + data[1]; + while (d < max){ + int length = data.length; + d = data[length - 1] + data[length - 2]; + if(d > max){ + return data; + } + int[] temp = new int[data.length + 1]; + System.arraycopy(data, 0, temp, 0, length); + temp[length] = d; + + data = temp; + } + } + } + + return null; + } + + /** + * 返回小于给定最大值max的所有素数数组 + * 例如max = 23, 返回的数组为[2,3,5,7,11,13,17,19] + * + * @param max + * @return + */ + public int[] getPrimes(int max) { + int[] data = new int[max]; + int index = 0; + for(int i = 1; i < max; i++){ + int divided = 0; + for(int j = i; j >= 1; j--){ + if(i % j == 0){ + divided++; + } + if(divided > 2){ + break; + }else if(j == 1 && divided == 2){ + data[index] = i; + index ++; + } + } + } + + int[] result = new int[index]; + System.arraycopy(data, 0, result, 0, index); + return result; + + } + + /** + * 所谓“完数”, 是指这个数恰好等于它的因子之和,例如6=1+2+3 + * 给定一个最大值max, 返回一个数组, 数组中是小于max 的所有完数 + * + * @param max + * @return + */ + public int[] getPerfectNumbers(int max) { + int[] perfd = new int[max]; + int perfIndex = 0; + for(int i = 1; i <= max; i++){ + int index = 0; + int[] data = new int[i]; + for(int j = i - 1; j >= 1; j--){ + if(i % j == 0){ + data[index] = j; + index ++; + } + + if(j == 1 && getSum(data) == i){ + perfd[perfIndex] = i; + perfIndex++; + } + } + } + + return removeZero(perfd); + } + + private int getSum(int[] arr){ + int sum = 0; + for(int i : arr){ + sum += i; + } + return sum; + } + + /** + * 用seperator 把数组 array给连接起来 + * 例如array= [3,8,9], seperator = "-" + * 则返回值为"3-8-9" + * + * @param array + * @param seperator + * @return + */ + public String join(int[] array, String seperator) { + StringBuffer sb = new StringBuffer(); + for(int i : array){ + sb.append(i).append(seperator); + } + return sb.substring(0, sb.length() - 1).toString(); + } +} diff --git a/group24/75939388/learning2017/src/main/java/basic/dataStructure/BinaryTreeNode.java b/group24/75939388/learning2017/src/main/java/basic/dataStructure/BinaryTreeNode.java new file mode 100644 index 0000000000..5050ae3c95 --- /dev/null +++ b/group24/75939388/learning2017/src/main/java/basic/dataStructure/BinaryTreeNode.java @@ -0,0 +1,58 @@ +package basic.dataStructure; + +/** + * Created by macvi on 2017/4/4. + */ +public class BinaryTreeNode { + private int data; + private BinaryTreeNode left; + private BinaryTreeNode right; + + private BinaryTreeNode(){} + + public BinaryTreeNode(int data){ + this.data = data; + this.left = null; + this.right = null; + } + + public void setData(int data){ + BinaryTreeNode node = new BinaryTreeNode(data); + if(compareTo(data)){ + if(this.left == null){ + this.left = node; + }else{ + this.left.setData(data); + } + }else{ + if(this.right == null){ + this.right = node; + }else{ + this.right.setData(data); + } + } + } + + public int getData(){ + return data; + } + + private boolean compareTo(int d) { + System.out.println("data=" + this.data + ", d=" + d); + return this.data > d; + } + + private StringBuffer dataStr = new StringBuffer(); + private int index = 0; +// public String toString(BinaryTreeNode node) { +// while (node.left != null || node.right != null){ +// dataStr.append(index + "层,数据=").append(node.data).append("|"); +// if(node.left != null){ +// dataStr.append(node.left.data) +// } +// index ++; +// } +// +// return dataStr.toString(); +// } +} diff --git a/group24/75939388/learning2017/src/main/java/basic/dataStructure/LinkedList.java b/group24/75939388/learning2017/src/main/java/basic/dataStructure/LinkedList.java new file mode 100644 index 0000000000..3ac85ad37b --- /dev/null +++ b/group24/75939388/learning2017/src/main/java/basic/dataStructure/LinkedList.java @@ -0,0 +1,341 @@ +package basic.dataStructure; + +/** + * Created by macvi on 2017/4/3. + */ +public class LinkedList implements List { + private Node head; + + public LinkedList() { + this.head = new Node(); + } + + public void add(Object o) { + if (this.head.data == null) { + this.head = new Node(o, null); + } else { + Node temp = this.head; + while (temp.next != null) { + temp = temp.next; + } + temp.next = new Node(o, null); + } + } + + public void add(int index, Object o) { + if (index > this.size() || index < 0) { + throw new IndexOutOfBoundsException(); + } + + if(index == 0){ + Node newNode = new Node(o, this.head); + this.head = newNode; + return; + } + + if(index == this.size()){ + this.add(o); + return; + } + + Node before = getNode(index - 1); + Node next = getNode(index); + Node newNode = new Node(o, next); + before.next = newNode; + + } + + private Node getNode(int index) { + int i = 0; + Node temp = this.head; + while (temp.data != null) { + if (index == i) { + return temp; + } + + if (temp.next != null) { + temp = temp.next; + } else break; + + i++; + } + + return null; + } + + public Object get(int index) { + if (index > this.size() || index < 0) { + throw new IndexOutOfBoundsException(); + } + + return this.getNode(index).data; + } + + public Object remove(int index) { + if(index > this.size() || index < 0){ + throw new IndexOutOfBoundsException(); + } + + Object removed = get(index); + + Node before = getNode(index - 1); + Node next = getNode(index + 1); + before.next = next; + + return removed; + } + + public int size() { + int size = 0; + Node temp = this.head; + while (temp.data != null) { + size++; + if (temp.next != null) { + temp = temp.next; + } else break; + } + + return size; + } + + public void asList(Object[] array){ + LinkedList list = new LinkedList(); + for(int i = 0; i < array.length; i++){ + list.add(array[i]); + } + + this.head = list.head; + } + + public Object[] toArray(LinkedList list){ + int size = list.size(); + Object[] arr = new Object[size]; + for(int i = 0; i < size; i++){ + arr[i] = list.get(i); + } + + return arr; + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + Node temp = this.head; + while (temp.data != null) { + sb.append(temp.data.toString()).append(","); + if (temp.next != null) { + temp = temp.next; + } else break; + } + + return sb.toString(); + } + + private static class Node { + Object data; + Node next; + + public Node() {} + + public Node(Object obj, Node next) { + this.data = obj; + this.next = next; + } + + } + + + /** + * 把该链表逆置 + * 例如链表为 3->7->10 , 逆置后变为 10->7->3 + */ + public void reverse(){ + int size = this.size(); + + if(size == 1){ + return; + } + + Object[] data = new Object[size]; + for(int i = 0; i < size; i++){ + data[i] = this.get(i); + } + + this.head = new Node(); + + for(int i = size - 1; i >= 0; i--){ + this.add(data[i]); + } + } + + /** + * 删除一个单链表的前半部分 + * 例如:list = 2->5->7->8 , 删除以后的值为 7->8 + * 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10 + + */ + public void removeFirstHalf(){ + int size = this.size(); + int index = this.size()/2; + ArrayList al = new ArrayList(); + for(int i = index; i < size; i++){ + al.add(this.get(i)); + } + + this.head = new Node(); + + for(int i = 0; i < al.size(); i++){ + this.add(al.get(i)); + } + } + + /** + * 从第i个元素开始, 删除length 个元素 , 注意i从0开始 + * @param i + * @param length + */ + public void remove(int i, int length){ + for(int j = i; j < i + length; j++){ + this.remove(i); + } + } + /** + * 假定当前链表和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 size = list.size(); + int[] arr = new int[size]; + for(int i = 0; i < size; i++){ + int index = (Integer) list.get(i); + arr[i] = (Integer) this.get(index); + } + + return arr; + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 从当前链表中中删除在listB中出现的元素 + + * @param list + */ + + public void subtract(LinkedList list){ + Object[] arr1 = toArray(this); + Object[] arr2 = toArray(list); + for(int i = 0; i < arr2.length; i++){ + arr1 = ArrayUtil.remove(arr1, arr2[i]); + } + + asList(arr1); + } + + /** + * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) + */ + public void removeDuplicateValues(){ + int size = this.size(); + ArrayList indexList = new ArrayList(); + ArrayList valueList = new ArrayList(); + for(int i = 0; i < size; i ++){ + int valueI = (Integer)this.get(i); + int index = 0; + for(int j = i + 1; j < size; j++){ + if(valueList.contains(valueI)){ + continue; + } + int valueJ = (Integer) this.get(j); + if(valueJ == valueI){ + index++; + } + + if(index > 0){ + indexList.add(j); + valueList.add(valueJ); + } + } + } + + Object[] arr = new Object[size]; + for(int i = 0; i < size; i++){ + arr[i] = indexList.contains(i) ? false : this.get(i); + } + + ArrayUtil au = new ArrayUtil(); + arr = au.remove(arr, false); + + asList(arr); + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 试写一高效的算法,删除表中所有值大于min且小于max的元素(若表中存在这样的元素) + * @param min + * @param max + */ + public void removeRange(int min, int max){ + int size = this.size(); + int[] range = new int[max - min]; + int index = 0; + for(int i = 0; i < size; i++){ + int value = (Integer) this.get(i); + if(value > min && value < max){ + range[index] = value; + index++; + } + } + + Object[] arr = new Object[size]; + for(int i = 0; i < size; i++){ + arr[i] = this.get(i); + } + + for(int i = 0; i < range.length; i++){ + arr = ArrayUtil.remove(arr, range[i]); + } + + asList(arr); + } + + /** + * 假设当前链表和参数list指定的链表均以元素依值递增有序排列(同一表中的元素值各不相同) + * 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列 + * @param list + */ + public LinkedList intersection( LinkedList list){ + //组合成新的链表 + int listSize = list.size(); + for(int i = 0 ; i < listSize; i ++){ + this.add(list.get(i)); + } + + //转化成数组 + int size = this.size(); + int[] arr = new int[size]; + for(int i = 0; i < size; i++){ + arr[i] = (Integer)this.get(i); + } + //排序 + for(int i = 0; i < size - 1; i ++){ + for(int j = 0; j < size - i - 1; j ++){ + if(arr[j] >= arr[j + 1]){ + int temp = arr[j]; + arr[j] = arr[j + 1]; + arr[j + 1] = temp; + } + } + } + + //组装 + LinkedList li = new LinkedList(); + for(int i = 0; i < size; i ++){ + li.add(arr[i]); + } + return li; + } +} diff --git a/group24/75939388/learning2017/src/main/java/basic/dataStructure/List.java b/group24/75939388/learning2017/src/main/java/basic/dataStructure/List.java new file mode 100644 index 0000000000..dc2a62aab3 --- /dev/null +++ b/group24/75939388/learning2017/src/main/java/basic/dataStructure/List.java @@ -0,0 +1,12 @@ +package basic.dataStructure; + +/** + * Created by macvi on 2017/4/2. + */ +public interface List { + void add(Object o); + void add(int index, Object o); + Object get(int index); + Object remove(int index); + int size(); +} diff --git a/group24/75939388/learning2017/src/main/java/basic/dataStructure/Queue.java b/group24/75939388/learning2017/src/main/java/basic/dataStructure/Queue.java new file mode 100644 index 0000000000..36ca7e9647 --- /dev/null +++ b/group24/75939388/learning2017/src/main/java/basic/dataStructure/Queue.java @@ -0,0 +1,72 @@ +package basic.dataStructure; + +/** + * Created by macvi on 2017/4/4. + */ +public class Queue { + private Object[] data; + + private int size = 10; + + private int extendedSize = 10; + + public Queue(){ + this.data = new Object[size]; + } + + public Queue(Object o){ + this.data = new Object[size]; + data[0] = o; + } + + public void enQueue(Object o){ + //被添加的位置 + int index = this.size(); + if(this.size() == this.size){ + this.size += extendedSize; + Object[] newData = new Object[this.size]; + System.arraycopy(this.data, 0, newData, 0, index); + newData[index] = o; + this.data = newData; + }else{ + this.data[index] = o; + } + } + + public Object deQueue(){ + Object[] newData = new Object[this.size]; + Object d = this.data[0]; + System.arraycopy(this.data, 1, newData, 0, this.size - 1); + this.data = newData; + + return d; + } + + public Object peek(){ + return this.data[0]; + } + + public boolean isEmpty(){ + return peek() == null; + } + + public int size(){ + int size = 0; + for(Object obj : this.data){ + size += obj == null ? 0 : 1; + } + + return size; + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + for(Object obj : this.data){ + if(obj != null){ + sb.append(obj.toString()).append(","); + }else break; + } + return sb.toString(); + } +} diff --git a/group24/75939388/learning2017/src/main/java/basic/dataStructure/Stack.java b/group24/75939388/learning2017/src/main/java/basic/dataStructure/Stack.java new file mode 100644 index 0000000000..bea16033fa --- /dev/null +++ b/group24/75939388/learning2017/src/main/java/basic/dataStructure/Stack.java @@ -0,0 +1,41 @@ +package basic.dataStructure; + +/** + * Created by macvi on 2017/4/4. + */ +public class Stack { + + private ArrayList elementData = new ArrayList(); + + public void push(Object o){ + this.elementData.add(o); + } + + public Object pop(){ + int index = elementData.size() - 1; + Object obj = elementData.remove(index); + + return obj; + } + + public Object peek(){ + int index = elementData.size() - 1; + return elementData.get(index); + } + public boolean isEmpty(){ + return peek() == null; + } + public int size(){ + return elementData.size(); + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + for(int i = this.size() - 1; i >= 0; i--){ + sb.append(elementData.get(i).toString()).append(","); + } + + return sb.toString(); + } +} diff --git a/group24/75939388/learning2017/src/main/java/basic/liteStruts/LoginAction.java b/group24/75939388/learning2017/src/main/java/basic/liteStruts/LoginAction.java new file mode 100644 index 0000000000..14b8aba8e2 --- /dev/null +++ b/group24/75939388/learning2017/src/main/java/basic/liteStruts/LoginAction.java @@ -0,0 +1,39 @@ +package basic.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/group24/75939388/learning2017/src/main/java/basic/liteStruts/ReadXML.java b/group24/75939388/learning2017/src/main/java/basic/liteStruts/ReadXML.java new file mode 100644 index 0000000000..458b247e18 --- /dev/null +++ b/group24/75939388/learning2017/src/main/java/basic/liteStruts/ReadXML.java @@ -0,0 +1,28 @@ +package basic.liteStruts; + +import org.dom4j.Document; +import org.dom4j.io.SAXReader; + +import java.io.File; + +/** + * @author : 温友朝 + * @date : 2017/4/10 + */ +public class ReadXML { + Document document; + + public ReadXML(String filePath) throws Exception{ + SAXReader reader = new SAXReader(); + document = reader.read(new File(ReadXML.class.getResource("/").getFile()) + filePath); + } + + public String getActionClass(String actionName){ + return document.selectSingleNode("//action[@name='" + actionName + "']").valueOf("@class"); + } + + public String getJspPage(String actionName, String result){ + return document.selectSingleNode("//action[@name='" + actionName + "']") + .selectSingleNode("//result[@name='" + result + "']").getText(); + } +} diff --git a/group24/75939388/learning2017/src/main/java/basic/liteStruts/Struts.java b/group24/75939388/learning2017/src/main/java/basic/liteStruts/Struts.java new file mode 100644 index 0000000000..3b28f2bf60 --- /dev/null +++ b/group24/75939388/learning2017/src/main/java/basic/liteStruts/Struts.java @@ -0,0 +1,78 @@ +package basic.liteStruts; + +import java.lang.reflect.Method; +import java.util.Map; + + +public class Struts { + /** + * 0. 读取配置文件struts.xml + * <p> + * 1. 根据actionName找到相对应的class , 例如LoginAction, 通过反射实例化(创建对象) + * 据parameters中的数据,调用对象的setter方法, 例如parameters中的数据是 + * ("name"="test" , "password"="1234") , + * 那就应该调用 setName和setPassword方法 + * <p> + * 2. 通过反射调用对象的exectue 方法, 并获得返回值,例如"success" + * <p> + * 3. 通过反射找到对象的所有getter方法(例如 getMessage), + * 通过反射来调用, 把值和属性形成一个HashMap , 例如 {"message": "登录成功"} , + * 放到View对象的parameters + * <p> + * 4. 根据struts.xml中的 <result> 配置,以及execute的返回值, 确定哪一个jsp, + * 放到View对象的jsp字段中。 + */ + public static View runAction(String actionName, Map<String, String> parameters) { + try{ + //0. 读取配置文件struts.xml + ReadXML read = new ReadXML("/resources/struts.xml"); + //1. 找到对应的class + String className = read.getActionClass(actionName); + Class clz = Class.forName(className); + //得到对象 + Object la = clz.newInstance(); + setNameAndPassword(clz, la, parameters); + //2. 调用execute方法 + String result = invokeExecute(clz, la); + //3. 找到对象的所有getter方法 + getResultMap(clz, la, parameters); + //4. 确定使用哪一个jsp + String viewName = read.getJspPage(actionName, result); + View view = new View(); + view.setJsp(viewName); + view.setParameters(parameters); + return view; + }catch(Exception e){ + e.printStackTrace(); + return null; + } + } + + private static void setNameAndPassword(Class clz, Object la, Map<String, String> parameters) throws Exception { + Method setName = clz.getDeclaredMethod("setName", String.class); + setName.invoke(la, parameters.get("name")); + + Method setPassword = clz.getDeclaredMethod("setPassword", String.class); + setPassword.invoke(la, parameters.get("password")); + } + + private static String invokeExecute(Class clz, Object la)throws Exception{ + Method execute = clz.getDeclaredMethod("execute", null); + Method getMessage = clz.getDeclaredMethod("getMessage", null); + execute.invoke(la, null); + return getMessage.invoke(la, null).toString(); + } + + private static void getResultMap(Class clz, Object la, Map<String, String> parameters) throws Exception{ + Method[] methods = clz.getMethods(); + for(Method me : methods){ + if(me.getName().startsWith("get")){ + String info = me.invoke(la, null).toString(); + String method= me.getName(); + String key = method.substring(3, method.length()).toLowerCase(); + parameters.put(key, info); + }else continue; + } + + } +} diff --git a/group24/75939388/learning2017/src/main/java/basic/liteStruts/View.java b/group24/75939388/learning2017/src/main/java/basic/liteStruts/View.java new file mode 100644 index 0000000000..777380b8f9 --- /dev/null +++ b/group24/75939388/learning2017/src/main/java/basic/liteStruts/View.java @@ -0,0 +1,23 @@ +package basic.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/group24/75939388/learning2017/src/main/java/miniJVM/Demo.java b/group24/75939388/learning2017/src/main/java/miniJVM/Demo.java new file mode 100644 index 0000000000..565983ab06 --- /dev/null +++ b/group24/75939388/learning2017/src/main/java/miniJVM/Demo.java @@ -0,0 +1,7 @@ +package miniJVM; + +/** + * Created by macvi on 2017/4/11. + */ +public class Demo { +} diff --git a/group24/75939388/learning2017/src/main/java/thread/download/DownloadThread.java b/group24/75939388/learning2017/src/main/java/thread/download/DownloadThread.java new file mode 100644 index 0000000000..190cae6423 --- /dev/null +++ b/group24/75939388/learning2017/src/main/java/thread/download/DownloadThread.java @@ -0,0 +1,39 @@ +package thread.download; + + +import thread.download.api.Connection; + +import java.io.RandomAccessFile; +import java.util.concurrent.CyclicBarrier; + +public class DownloadThread extends Thread{ + + Connection conn; + int startPos; + int endPos; + + String localFile = ""; + + CyclicBarrier barrier; + + public DownloadThread(Connection conn, int startPos, int endPos, String localFileName, CyclicBarrier barrier){ + this.localFile = localFileName; + this.conn = conn; + this.startPos = startPos; + this.endPos = endPos; + this.barrier = barrier; + } + public void run(){ + try{ + RandomAccessFile file = new RandomAccessFile(localFile, "rw"); + byte[] buffer = this.conn.read(this.startPos, this.endPos); + file.seek(startPos); + file.write(buffer); + file.close(); + this.conn.close(); + barrier.await(); + }catch(Exception e){ + e.printStackTrace(); + } + } +} diff --git a/group24/75939388/learning2017/src/main/java/thread/download/FileDownloader.java b/group24/75939388/learning2017/src/main/java/thread/download/FileDownloader.java new file mode 100644 index 0000000000..f50560b8be --- /dev/null +++ b/group24/75939388/learning2017/src/main/java/thread/download/FileDownloader.java @@ -0,0 +1,106 @@ +package thread.download; + +import thread.download.api.Connection; +import thread.download.api.ConnectionManager; +import thread.download.api.DownloadListener; + +import java.io.File; +import java.io.RandomAccessFile; +import java.util.concurrent.CyclicBarrier; + +public class FileDownloader { + + String url; + String fileLocation; + DownloadListener listener; + ConnectionManager cm; + + RandomAccessFile file; + + int length; + + private static final int MAX_THREAD_NUM = 5; + + + public FileDownloader(String _url, String fileLocation) { + this.url = _url; + this.fileLocation = fileLocation; + } + + 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 { + CyclicBarrier barrier = new CyclicBarrier(MAX_THREAD_NUM, new Runnable() { + public void run() { + listener.notifyFinished(); + } + }); + + conn = cm.open(this.url); + this.length = conn.getContentLength(); + + file = getEmptyFile(); + + int divided = length/MAX_THREAD_NUM; + int[] pos = new int[MAX_THREAD_NUM + 1]; + for(int i = 0; i < MAX_THREAD_NUM; i++){ + pos[i] = i == 0 ? 0 : divided * i; + } + pos[MAX_THREAD_NUM] = length; + + for(int i = 0; i < MAX_THREAD_NUM; i++){ + new DownloadThread(conn, pos[i], pos[i + 1] - 1, this.fileLocation, barrier).start(); + } + + + File file2 = new File(fileLocation); + System.out.println("file.length=" + file2.length()); + } catch (Exception e) { + e.printStackTrace(); + }finally{ + if(conn != null){ + conn.close(); + } + } + } + + public RandomAccessFile getEmptyFile(){ + try{ + RandomAccessFile file = new RandomAccessFile(this.fileLocation, "rw"); + byte[] empty = new byte[this.length]; + file.write(empty); + file.close(); + return file; + }catch(Exception e){ + e.printStackTrace(); + } + return null; + } + + 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/75939388/learning2017/src/main/java/thread/download/api/Connection.java b/group24/75939388/learning2017/src/main/java/thread/download/api/Connection.java new file mode 100644 index 0000000000..08a85b35dd --- /dev/null +++ b/group24/75939388/learning2017/src/main/java/thread/download/api/Connection.java @@ -0,0 +1,23 @@ +package thread.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/75939388/learning2017/src/main/java/thread/download/api/ConnectionException.java b/group24/75939388/learning2017/src/main/java/thread/download/api/ConnectionException.java new file mode 100644 index 0000000000..e8fac91d1e --- /dev/null +++ b/group24/75939388/learning2017/src/main/java/thread/download/api/ConnectionException.java @@ -0,0 +1,8 @@ +package thread.download.api; + +public class ConnectionException extends Exception { + + public ConnectionException(String msg){ + super(msg); + } +} diff --git a/group24/75939388/learning2017/src/main/java/thread/download/api/ConnectionManager.java b/group24/75939388/learning2017/src/main/java/thread/download/api/ConnectionManager.java new file mode 100644 index 0000000000..f5f6c2ff70 --- /dev/null +++ b/group24/75939388/learning2017/src/main/java/thread/download/api/ConnectionManager.java @@ -0,0 +1,10 @@ +package thread.download.api; + +public interface ConnectionManager { + /** + * 给定一个url , 打开一个连接 + * @param url + * @return + */ + Connection open(String url) throws ConnectionException; +} diff --git a/group24/75939388/learning2017/src/main/java/thread/download/api/DownloadListener.java b/group24/75939388/learning2017/src/main/java/thread/download/api/DownloadListener.java new file mode 100644 index 0000000000..16393c4dd9 --- /dev/null +++ b/group24/75939388/learning2017/src/main/java/thread/download/api/DownloadListener.java @@ -0,0 +1,5 @@ +package thread.download.api; + +public interface DownloadListener { + void notifyFinished(); +} diff --git a/group24/75939388/learning2017/src/main/java/thread/download/impl/ConnectionImpl.java b/group24/75939388/learning2017/src/main/java/thread/download/impl/ConnectionImpl.java new file mode 100644 index 0000000000..2e2544ab27 --- /dev/null +++ b/group24/75939388/learning2017/src/main/java/thread/download/impl/ConnectionImpl.java @@ -0,0 +1,93 @@ +package thread.download.impl; + +import thread.download.api.Connection; +import thread.download.api.ConnectionException; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.ConnectException; +import java.net.HttpURLConnection; +import java.net.URL; + +public class ConnectionImpl implements Connection { + + private int length = 0; + + private URL url; + + private HttpURLConnection conn; + + private InputStream is; + + private ByteArrayOutputStream baos; + + private ConnectionImpl() {} + + public ConnectionImpl(URL url) { + this.url = url; + try { + this.conn = (HttpURLConnection) url.openConnection(); + this.conn.setRequestMethod("GET"); + this.conn.setReadTimeout(5000); + int responseCode = this.conn.getResponseCode(); + System.out.println("连接状态=" + responseCode); + if (responseCode != 200) { + throw new ConnectionException("连接到" + url.toURI() + "失败"); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public byte[] read(int startPos, int endPos) throws IOException { + try { + //设置读取段落 + this.conn = (HttpURLConnection) url.openConnection(); + this.conn.setRequestMethod("GET"); + this.conn.setReadTimeout(5000); + this.conn.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos); + //获取返回值 + int response = conn.getResponseCode(); + if(response != 200 && response != 206){ + throw new ConnectException("没有连接上" + url.toURI() + ", 状态码为" + response); + } + //开始读取 + int length = endPos - startPos + 1; + this.is = conn.getInputStream(); + byte[] buffer = new byte[1024]; + baos = new ByteArrayOutputStream(length); + while(-1 != is.read(buffer)){ + baos.write(buffer); + } + System.out.println(startPos + "-" + endPos + "文件段读取完成"); + return baos.toByteArray(); + } catch (Exception e) { + e.printStackTrace(); + return null; + } finally { + this.close(); + } + } + + public int getContentLength() { + try { + this.length = this.conn.getContentLength(); + System.out.println("获取的文件长度=" + length); + return this.length; + } catch (Exception e) { + e.printStackTrace(); + return -1; + } + } + + public void close() { + try { + if(is != null){ + is.close(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/group24/75939388/learning2017/src/main/java/thread/download/impl/ConnectionManagerImpl.java b/group24/75939388/learning2017/src/main/java/thread/download/impl/ConnectionManagerImpl.java new file mode 100644 index 0000000000..ede8ccac00 --- /dev/null +++ b/group24/75939388/learning2017/src/main/java/thread/download/impl/ConnectionManagerImpl.java @@ -0,0 +1,20 @@ +package thread.download.impl; + +import thread.download.api.Connection; +import thread.download.api.ConnectionException; +import thread.download.api.ConnectionManager; + +import java.net.URL; + +public class ConnectionManagerImpl implements ConnectionManager { + + public Connection open(String url) throws ConnectionException { + Connection conn = null; + try{ + conn = new ConnectionImpl(new URL(url)); + }catch(Exception e){ + e.printStackTrace(); + } + return conn; + } +} diff --git a/group24/75939388/learning2017/src/test/java/data_structure/ArrayListTest.java b/group24/75939388/learning2017/src/test/java/data_structure/ArrayListTest.java new file mode 100644 index 0000000000..ee8ee6b0d0 --- /dev/null +++ b/group24/75939388/learning2017/src/test/java/data_structure/ArrayListTest.java @@ -0,0 +1,69 @@ +package data_structure; + +import org.junit.Test; +import basic.dataStructure.ArrayList; + +/** + * Created by macvi on 2017/4/2. + */ +public class ArrayListTest { + + @Test + public void TestAdd(){ + ArrayList al = new ArrayList(); + for(int i = 0; i < 32; i++){ + al.add(i + ""); + } + + System.out.println("ArrayList.content-->" + al.toString()); + } + + + @Test + public void testIndexAdd(){ + ArrayList al = new ArrayList(); + for(int i = 0; i < 17; i ++){ + al.add(i + ""); + } + + al.add(3, "xxoo"); + al.add(11, "abcd"); + al.add(0, "efgh"); + al.add(al.size(), "ijkl"); + + System.out.println("al.toString-->" + al.toString()); + System.out.println("size-->" + al.size()); + } + + @Test + public void testGet(){ + ArrayList al = new ArrayList(); + for(int i = 0; i < 18; i ++){ + al.add(i + "zxcd"); + } + + System.out.println("get-->" + al.get(13)); + } + + @Test + public void testRemove(){ + ArrayList al = new ArrayList(); + for(int i = 0; i < 18; i ++){ + al.add(i + ""); + } + System.out.println("size1-->" + al.size()); + System.out.println("al.toString1-->" + al.toString()); + String re = (String)al.remove(12); + System.out.println("remove index=12 :"); + System.out.println("re-->" + re); + System.out.println("size2-->" + al.size()); + System.out.println("al.toString2-->" + al.toString()); + + String re1 = (String)al.remove(1); + System.out.println("remove index=1 :"); + System.out.println("re-->" + re1); + System.out.println("size2-->" + al.size()); + System.out.println("al.toString2-->" + al.toString()); + } + +} diff --git a/group24/75939388/learning2017/src/test/java/data_structure/ArrayUtilTest.java b/group24/75939388/learning2017/src/test/java/data_structure/ArrayUtilTest.java new file mode 100644 index 0000000000..1dc1a6f263 --- /dev/null +++ b/group24/75939388/learning2017/src/test/java/data_structure/ArrayUtilTest.java @@ -0,0 +1,67 @@ +package data_structure; + +import org.junit.Test; +import basic.dataStructure.ArrayUtil; + +import java.util.Arrays; + +/** + * @author : 温友朝 + * @date : 2017/4/5 + */ +public class ArrayUtilTest { + ArrayUtil au = new ArrayUtil(); + + @Test + public void testReverse(){ + int[] arr = {1, 2, 3, 4, 5}; + this.au.reverseArray(arr); + } + + @Test + public void testTrim(){ + int oldArr[]={1,3,4,5,0,0,6,6,0,5,4,7,6,7,0,5}; + int[] arr = this.au.removeZero(oldArr); + System.out.println(Arrays.toString(arr)); + } + + @Test + public void testMerge(){ + int[] a1 = {3, 5, 7,8}; + int[] a2 = {4, 5, 6,7}; + + int[] arr = this.au.merge(a1, a2); + System.out.println(Arrays.toString(arr)); + } + + @Test + public void testGrow(){ + int[] arr = {1, 2, 3, 4, 5}; + int[] arr2 = this.au.grow(arr, 4); + System.out.println(Arrays.toString(arr2)); + } + + @Test + public void testFibonacci(){ + int[] arr = this.au.fibonacci(100); + System.out.println(Arrays.toString(arr)); + } + + @Test + public void testPrimes(){ + int[] arr = this.au.getPrimes(100000); + System.out.println(Arrays.toString(arr)); + } + + @Test + public void testPerfectNumbers(){ + int[] arr = this.au.getPerfectNumbers(10000); + System.out.println(Arrays.toString(arr)); + } + + @Test + public void testJoin(){ + int[] arr = this.au.getPerfectNumbers(10000); + System.out.println(this.au.join(arr, "-")); + } +} diff --git a/group24/75939388/learning2017/src/test/java/data_structure/BinaryNodeTreeTest.java b/group24/75939388/learning2017/src/test/java/data_structure/BinaryNodeTreeTest.java new file mode 100644 index 0000000000..df976147e3 --- /dev/null +++ b/group24/75939388/learning2017/src/test/java/data_structure/BinaryNodeTreeTest.java @@ -0,0 +1,29 @@ +package data_structure; + +import org.junit.Test; +import basic.dataStructure.BinaryTreeNode; + +/** + * @author : 温友朝 + * @date : 2017/4/5 + */ +public class BinaryNodeTreeTest { + +// @Test +// public BinaryTreeNode getTree(){ +// BinaryTreeNode btn = new BinaryTreeNode(5); +// btn.setData(3); +// +// return btn; +// } + + @Test + public void testAdd(){ + BinaryTreeNode btn = new BinaryTreeNode(5); + btn.setData(3); + btn.setData(7); + btn.setData(10); + btn.setData(6); + btn.setData(4); + } +} diff --git a/group24/75939388/learning2017/src/test/java/data_structure/LinkedListTest.java b/group24/75939388/learning2017/src/test/java/data_structure/LinkedListTest.java new file mode 100644 index 0000000000..c98a305623 --- /dev/null +++ b/group24/75939388/learning2017/src/test/java/data_structure/LinkedListTest.java @@ -0,0 +1,151 @@ +package data_structure; + +import basic.dataStructure.LinkedList; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; + +/** + * Created by macvi on 2017/4/3. + */ +public class LinkedListTest { + + LinkedList ll = new LinkedList(); + + @Before + public void init(){ + for(int i = 0; i < 10; i++){ + ll.add(i); + } + } + + @After + public void print(){ + + } + + + @Test + public void testLinkedListAdd(){ + LinkedList ll = new LinkedList(); + ll.add("123"); + ll.add("456"); + ll.add("asdf"); + ll.add("zxcv"); + + + System.out.println("ll.toString-->" + ll); + System.out.println("ll.size--->" + ll.size()); + } + + @Test + public void testLinkedListIndexAdd(){ + System.out.println("12345"); + } + + @Test + public void testGet(){ + LinkedList ll = new LinkedList(); + for(int i = 0; i < 10; i ++){ + ll.add(i + ""); + } + + System.out.println("get-->" + ll.get(9)); + System.out.println("ll.toString-->" + ll.toString() + "\nsize-->" + ll.size()); + } + + @Test + public void testIndexAdd(){ + LinkedList ll = new LinkedList(); + for(int i = 0; i < 5; i ++){ + ll.add(i + ""); + } + + ll.add(5, "xxoo"); + System.out.println("index get-->" + ll.get(0)); + System.out.println("ll.toString2-->" + ll.toString() + "\nsize-->" + ll.size()); + } + + @Test + public void testRemove(){ + LinkedList ll = new LinkedList(); + for(int i = 0; i < 6; i ++){ + ll.add(i + ""); + } + + Object removed = ll.remove(-1); + System.out.println("ll.toString-->" + ll.toString() + "\nsize-->" + ll.size()); + System.out.println("removed-->" + removed.toString()); + } + + @Test + public void testReverse(){ + ll.reverse(); + System.out.println("ll.reverse-->" + ll.toString()); + } + + @Test + public void testRemoveFirstHalf(){ + ll.removeFirstHalf(); + System.out.println("ll.removeFirstHalf-->" + ll.toString()); + } + + @Test + public void testRemoveL(){ + ll.remove(2, 5); + System.out.println("ll.toString-->" + ll.toString()); + } + + @Test + public void testGetElements(){ + LinkedList l2 = new LinkedList(); + l2.add(3); + l2.add(5); + l2.add(9); + l2.add(0); + + int[] arr = ll.getElements(l2); + System.out.println("arr->" + Arrays.toString(arr)); + } + + @Test + public void testRemoveDuplicate(){ + ll.add(1); + ll.add(3); + ll.add(4); + ll.add(10); + ll.add(11); + ll.removeDuplicateValues(); + System.out.println("ll.toString-->" + ll.toString()); + } + + @Test + public void testRemoveRange(){ + ll.removeRange(2, 6); + System.out.println("ll.toString-->" + ll.toString()); + } + + @Test + public void testSubtract(){ + LinkedList list = new LinkedList(); + list.add(1); + list.add(2); + list.add(5); + + ll.subtract(list); + System.out.println("ll.toString-->" + ll); + } + + @Test + public void testIntersection(){ + LinkedList list = new LinkedList(); + list.add(1); + list.add(2); + list.add(5); + + LinkedList list2 = ll.intersection(list); + System.out.println(list2); + } +} diff --git a/group24/75939388/learning2017/src/test/java/data_structure/QueueTest.java b/group24/75939388/learning2017/src/test/java/data_structure/QueueTest.java new file mode 100644 index 0000000000..3db6d82e49 --- /dev/null +++ b/group24/75939388/learning2017/src/test/java/data_structure/QueueTest.java @@ -0,0 +1,50 @@ +package data_structure; + +import org.junit.Assert; +import org.junit.Test; +import basic.dataStructure.Queue; + +/** + * Created by macvi on 2017/4/4. + */ +public class QueueTest { + + private Queue newQueue(){ + Queue q = new Queue(); + for(int i = 0; i < 13; i++){ + q.enQueue(i + ""); + } + + return q; + } + + @Test + public void testEnqueue(){ + Queue q = newQueue(); + q.enQueue(10 + ""); + q.enQueue( "xxoo"); + System.out.println("queue-->" + q.toString()); + } + + @Test + public void testSize(){ + Queue q = newQueue(); + + Assert.assertEquals(13, q.size()); + } + + @Test + public void testDequeue(){ + Queue q = newQueue(); + Object obj = q.deQueue(); + + Assert.assertEquals("0", obj); + } + + @Test + public void testIsEmpty(){ + Queue q = newQueue(); + + Assert.assertEquals(false, q.isEmpty()); + } +} diff --git a/group24/75939388/learning2017/src/test/java/data_structure/StackTest.java b/group24/75939388/learning2017/src/test/java/data_structure/StackTest.java new file mode 100644 index 0000000000..b933b8b63e --- /dev/null +++ b/group24/75939388/learning2017/src/test/java/data_structure/StackTest.java @@ -0,0 +1,49 @@ +package data_structure; + +import org.junit.Assert; +import org.junit.Test; +import basic.dataStructure.Stack; + +/** + * Created by macvi on 2017/4/4. + */ +public class StackTest { + + private Stack getStack(){ + Stack s = new Stack(); + for(int i = 0; i < 14; i ++){ + s.push(i + ""); + } + + return s; + } + + @Test + public void pushTest(){ + Stack s = getStack(); + + System.out.println("stack-->" + s.toString()); + } + + @Test + public void testSize(){ + Stack s = getStack(); + + Assert.assertEquals(14, s.size()); + } + + @Test + public void testPeek(){ + Stack s = getStack(); + + Assert.assertEquals("13", s.peek()); + } + + @Test + public void testPop(){ + Stack s = getStack(); + + Assert.assertEquals("13", s.pop()); + Assert.assertEquals(13, s.size()); + } +} diff --git a/group24/75939388/learning2017/src/test/java/download/FileDownloaderTest.java b/group24/75939388/learning2017/src/test/java/download/FileDownloaderTest.java new file mode 100644 index 0000000000..0dc8536269 --- /dev/null +++ b/group24/75939388/learning2017/src/test/java/download/FileDownloaderTest.java @@ -0,0 +1,54 @@ +package download; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import thread.download.FileDownloader; +import thread.download.api.ConnectionManager; +import thread.download.api.DownloadListener; +import thread.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 = "https://www.baidu.com/img/bd_logo1.png"; + String fileLocation = "D:\\Tee\\JavaLearnin\\test.png"; + FileDownloader downloader = new FileDownloader(url, fileLocation); + + ConnectionManager cm = new ConnectionManagerImpl(); + downloader.setConnectionManager(cm); + + downloader.setListener(new DownloadListener() { + 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/75939388/learning2017/src/test/java/liteStruts/StrutsTest.java b/group24/75939388/learning2017/src/test/java/liteStruts/StrutsTest.java new file mode 100644 index 0000000000..4477c5f51b --- /dev/null +++ b/group24/75939388/learning2017/src/test/java/liteStruts/StrutsTest.java @@ -0,0 +1,42 @@ +package liteStruts; + +import org.junit.Assert; +import org.junit.Test; +import basic.liteStruts.Struts; +import basic.liteStruts.View; + +import java.util.HashMap; +import java.util.Map; + + +public class StrutsTest { + + @Test + public void testLoginActionSuccess() { + + String actionName = "login"; + + Map<String,String> params = new HashMap<String,String>(); + 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<String,String> params = new HashMap<String,String>(); + 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 dca236eb2b7752ecdd3e8f14c6e3dcca28d3ce24 Mon Sep 17 00:00:00 2001 From: DonaldY <448641125@qq.com> Date: Tue, 18 Apr 2017 19:50:06 +0800 Subject: [PATCH 287/287] Infix Postfix Prefix finished --- .../donaldy/basic/expr/InfixToPostfix.java | 59 ++++++++++++++++ .../basic/expr/InfixToPostfixTest.java | 22 ++++++ .../com/donaldy/basic/expr/PostfixExpr.java | 67 ++++++++++++++++++ .../donaldy/basic/expr/PostfixExprTest.java | 41 +++++++++++ .../com/donaldy/basic/expr/PrefixExpr.java | 69 +++++++++++++++++++ .../donaldy/basic/expr/PrefixExprTest.java | 45 ++++++++++++ .../src/com/donaldy/basic/expr/Token.java | 50 ++++++++++++++ .../com/donaldy/basic/expr/TokenParser.java | 57 +++++++++++++++ .../donaldy/basic/expr/TokenParserTest.java | 41 +++++++++++ 9 files changed, 451 insertions(+) create mode 100644 group24/448641125/src/com/donaldy/basic/expr/InfixToPostfix.java create mode 100644 group24/448641125/src/com/donaldy/basic/expr/InfixToPostfixTest.java create mode 100644 group24/448641125/src/com/donaldy/basic/expr/PostfixExpr.java create mode 100644 group24/448641125/src/com/donaldy/basic/expr/PostfixExprTest.java create mode 100644 group24/448641125/src/com/donaldy/basic/expr/PrefixExpr.java create mode 100644 group24/448641125/src/com/donaldy/basic/expr/PrefixExprTest.java create mode 100644 group24/448641125/src/com/donaldy/basic/expr/Token.java create mode 100644 group24/448641125/src/com/donaldy/basic/expr/TokenParser.java create mode 100644 group24/448641125/src/com/donaldy/basic/expr/TokenParserTest.java diff --git a/group24/448641125/src/com/donaldy/basic/expr/InfixToPostfix.java b/group24/448641125/src/com/donaldy/basic/expr/InfixToPostfix.java new file mode 100644 index 0000000000..54666845de --- /dev/null +++ b/group24/448641125/src/com/donaldy/basic/expr/InfixToPostfix.java @@ -0,0 +1,59 @@ +package com.donaldy.basic.expr; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +public class InfixToPostfix { + + public static List<Token> convert(String expr) { + + Stack<Token> opStack = new Stack<>(); + + TokenParser parser = new TokenParser(); + List<Token> tokens = parser.parse(expr); + + List<Token> newTokens = new ArrayList<>(); + + for (Token token : tokens) { + + if (token.isOperator()) { + + while (true) { + if (opStack.isEmpty()) { + opStack.push(token); + + break; + } + + if (token.hasHigherPriority(opStack.peek())) { + + opStack.push(token); + + break; + } + + newTokens.add(opStack.pop()); + + } + + + } + + if (token.isNumber()) { + newTokens.add(token); + } + + } + + while (!opStack.isEmpty()) { + newTokens.add(opStack.pop()); + } + + + return newTokens; + } + + + +} diff --git a/group24/448641125/src/com/donaldy/basic/expr/InfixToPostfixTest.java b/group24/448641125/src/com/donaldy/basic/expr/InfixToPostfixTest.java new file mode 100644 index 0000000000..f6dda0ee18 --- /dev/null +++ b/group24/448641125/src/com/donaldy/basic/expr/InfixToPostfixTest.java @@ -0,0 +1,22 @@ +package com.donaldy.basic.expr; + +import org.junit.Assert; +import org.junit.Test; + +/** + * Created by DonaldY on 2017/4/18. + */ +public class InfixToPostfixTest { + + @Test + public void test() { + + String expr = "9 + 3-1 *3+10/2"; + //Assert.assertEquals("9 3 1-3*+ 10 2/+", InfixToPostfix.convert(expr)); + + expr = "10-2*3+50"; + Assert.assertEquals("[10, 2, 3, *, -, 50, +]", InfixToPostfix.convert(expr).toString()); + + } + +} diff --git a/group24/448641125/src/com/donaldy/basic/expr/PostfixExpr.java b/group24/448641125/src/com/donaldy/basic/expr/PostfixExpr.java new file mode 100644 index 0000000000..ec175d192c --- /dev/null +++ b/group24/448641125/src/com/donaldy/basic/expr/PostfixExpr.java @@ -0,0 +1,67 @@ +package com.donaldy.basic.expr; + + +import java.util.List; +import java.util.Stack; + +/** + * 从左到右遍历, + * 1. 若为数字,则入栈 + * 2. 若为运算符,则calculate + */ +public class PostfixExpr { + + String expr = null; + + public PostfixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + + + TokenParser parser = new TokenParser(); + List<Token> tokens = parser.parse(this.expr); + + Stack<Float> numStack = new Stack<>(); + + + for(Token token : tokens){ + + if (token.isOperator()){ + + Float f2 = numStack.pop(); + Float f1 = numStack.pop(); + numStack.push(calculate(token.toString(), f1,f2)); + + } + + if(token.isNumber()){ + numStack.push(new Float(token.getIntValue())); + } + } + + + return numStack.pop().floatValue(); + } + + private Float calculate(String op, Float f1, Float f2){ + if(op.equals("+")){ + return f1+f2; + } + if(op.equals("-")){ + return f1-f2; + } + if(op.equals("*")){ + return f1*f2; + } + if(op.equals("/")){ + return f1/f2; + } + throw new RuntimeException(op + " is not supported"); + } + + + + +} diff --git a/group24/448641125/src/com/donaldy/basic/expr/PostfixExprTest.java b/group24/448641125/src/com/donaldy/basic/expr/PostfixExprTest.java new file mode 100644 index 0000000000..3195c7b3b2 --- /dev/null +++ b/group24/448641125/src/com/donaldy/basic/expr/PostfixExprTest.java @@ -0,0 +1,41 @@ +package com.donaldy.basic.expr; + + + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + + +public class PostfixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + { + PostfixExpr expr = new PostfixExpr("6 5 2 3 + 8 * + 3 + *"); + Assert.assertEquals(288, expr.evaluate(),0.0f); + } + { + //9+(3-1)*3+10/2 + PostfixExpr expr = new PostfixExpr("9 3 1-3*+ 10 2/+"); + Assert.assertEquals(20, expr.evaluate(),0.0f); + } + + { + //10-2*3+50 + PostfixExpr expr = new PostfixExpr("10 2 3 * - 50 +"); + Assert.assertEquals(54, expr.evaluate(),0.0f); + } + } + +} diff --git a/group24/448641125/src/com/donaldy/basic/expr/PrefixExpr.java b/group24/448641125/src/com/donaldy/basic/expr/PrefixExpr.java new file mode 100644 index 0000000000..aaee04d871 --- /dev/null +++ b/group24/448641125/src/com/donaldy/basic/expr/PrefixExpr.java @@ -0,0 +1,69 @@ +package com.donaldy.basic.expr; + +import java.util.List; +import java.util.Stack; + +/** + * 从右到左遍历 + * 1. 若为数字,则入栈 + * 2. 若为符号,则calculate + */ +public class PrefixExpr { + + String expr = null; + + public PrefixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + + + TokenParser parser = new TokenParser(); + List<Token> tokens = parser.parse(this.expr); + + Stack<Float> numStack = new Stack<>(); + Stack<String> opStack = new Stack<>(); + + for(int i = tokens.size() - 1; i >= 0 ; --i){ + Token token = tokens.get(i); + + if (token.isOperator()){ + opStack.push(token.toString()); + Float f1 = numStack.pop(); + Float f2 = numStack.pop(); + numStack.push(calculate(opStack.pop(), f1,f2)); + } + + if(token.isNumber()){ + numStack.push(new Float(token.getIntValue())); + } + } + + while (!opStack.isEmpty()) { + Float f1 = numStack.pop(); + Float f2 = numStack.pop(); + numStack.push(calculate(opStack.pop(), f1,f2)); + } + + return numStack.pop().floatValue(); + } + + private Float calculate(String op, Float f1, Float f2){ + if(op.equals("+")){ + return f1+f2; + } + if(op.equals("-")){ + return f1-f2; + } + if(op.equals("*")){ + return f1*f2; + } + if(op.equals("/")){ + return f1/f2; + } + throw new RuntimeException(op + " is not supported"); + } + + +} diff --git a/group24/448641125/src/com/donaldy/basic/expr/PrefixExprTest.java b/group24/448641125/src/com/donaldy/basic/expr/PrefixExprTest.java new file mode 100644 index 0000000000..435a82d8b1 --- /dev/null +++ b/group24/448641125/src/com/donaldy/basic/expr/PrefixExprTest.java @@ -0,0 +1,45 @@ +package com.donaldy.basic.expr; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class PrefixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + { + // 2*3+4*5 + PrefixExpr expr = new PrefixExpr("+ * 2 3 * 4 5"); + Assert.assertEquals(26, expr.evaluate(),0.001f); + } + { + // 4*2 + 6+9*2/3 -8 + PrefixExpr expr = new PrefixExpr("- + + 6 / * 2 9 3 * 4 2 8"); + Assert.assertEquals(12, expr.evaluate(),0.001f); + } + { + //(3+4)*5-6 + PrefixExpr expr = new PrefixExpr("- * + 3 4 5 6"); + Assert.assertEquals(29, expr.evaluate(),0.001f); + } + { + //1+((2+3)*4)-5 + PrefixExpr expr = new PrefixExpr("- + 1 * + 2 3 4 5"); + Assert.assertEquals(16, expr.evaluate(),0.001f); + } + + + } + +} diff --git a/group24/448641125/src/com/donaldy/basic/expr/Token.java b/group24/448641125/src/com/donaldy/basic/expr/Token.java new file mode 100644 index 0000000000..db639bcbcf --- /dev/null +++ b/group24/448641125/src/com/donaldy/basic/expr/Token.java @@ -0,0 +1,50 @@ +package com.donaldy.basic.expr; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +class Token { + public static final List<String> OPERATORS = Arrays.asList("+", "-", "*", "/"); + private static final Map<String,Integer> priorities = new HashMap<>(); + static { + priorities.put("+", 1); + priorities.put("-", 1); + priorities.put("*", 2); + priorities.put("/", 2); + } + static final int OPERATOR = 1; + static final int NUMBER = 2; + String value; + int type; + public Token(int type, String value){ + this.type = type; + this.value = value; + } + + public boolean isNumber() { + return type == NUMBER; + } + + public boolean isOperator() { + return type == OPERATOR; + } + + public int getIntValue() { + return Integer.valueOf(value).intValue(); + } + public String toString(){ + return value; + } + + public boolean hasHigherPriority(Token t){ + if(!this.isOperator() && !t.isOperator()){ + throw new RuntimeException("numbers can't compare priority"); + } + return priorities.get(this.value) - priorities.get(t.value) > 0; + } + + + +} \ No newline at end of file diff --git a/group24/448641125/src/com/donaldy/basic/expr/TokenParser.java b/group24/448641125/src/com/donaldy/basic/expr/TokenParser.java new file mode 100644 index 0000000000..38d5225c4f --- /dev/null +++ b/group24/448641125/src/com/donaldy/basic/expr/TokenParser.java @@ -0,0 +1,57 @@ +package com.donaldy.basic.expr; + +import java.util.ArrayList; +import java.util.List; + +public class TokenParser { + + + public List<Token> parse(String expr) { + List<Token> tokens = new ArrayList<>(); + + int i = 0; + + while (i < expr.length()) { + + char c = expr.charAt(i); + + if (isOperator(c)) { + + Token t = new Token(Token.OPERATOR, String.valueOf(c)); + tokens.add(t); + i++; + + } else if (Character.isDigit(c)) { + + int nextOperatorIndex = indexOfNextOperator(i, expr); + String value = expr.substring(i, nextOperatorIndex); + Token t = new Token(Token.NUMBER, value); + tokens.add(t); + i = nextOperatorIndex; + + } else{ + System.out.println("char :["+c+"] is not number or operator,ignore"); + i++; + } + + } + return tokens; + } + + private int indexOfNextOperator(int i, String expr) { + + while (Character.isDigit(expr.charAt(i))) { + i++; + if (i == expr.length()) { + break; + } + } + return i; + + } + + private boolean isOperator(char c) { + String sc = String.valueOf(c); + return Token.OPERATORS.contains(sc); + } +} diff --git a/group24/448641125/src/com/donaldy/basic/expr/TokenParserTest.java b/group24/448641125/src/com/donaldy/basic/expr/TokenParserTest.java new file mode 100644 index 0000000000..03d3146213 --- /dev/null +++ b/group24/448641125/src/com/donaldy/basic/expr/TokenParserTest.java @@ -0,0 +1,41 @@ +package com.donaldy.basic.expr; + +import static org.junit.Assert.*; + +import java.util.List; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class TokenParserTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void test() { + + TokenParser parser = new TokenParser(); + List<Token> tokens = parser.parse("300*20+12*5-20/4"); + + Assert.assertEquals(300, tokens.get(0).getIntValue()); + Assert.assertEquals("*", tokens.get(1).toString()); + Assert.assertEquals(20, tokens.get(2).getIntValue()); + Assert.assertEquals("+", tokens.get(3).toString()); + Assert.assertEquals(12, tokens.get(4).getIntValue()); + Assert.assertEquals("*", tokens.get(5).toString()); + Assert.assertEquals(5, tokens.get(6).getIntValue()); + Assert.assertEquals("-", tokens.get(7).toString()); + Assert.assertEquals(20, tokens.get(8).getIntValue()); + Assert.assertEquals("/", tokens.get(9).toString()); + Assert.assertEquals(4, tokens.get(10).getIntValue()); + } + +}