第1题:方法中的内部类能不能访问方法中的局部变量,为什么?
答:方法中的内部类可以访问方法中的final修饰的局部变量, 因为final定义的变量相当于常量,该变量的生命周期也就延长了,这样就算方法撤销了,也能保证其内部类 还能访问到final类型的方法的局部变量。
备注:在以下程序说明的时候发现不用final修饰也是可以访问的,于是我首想到的是java新特性(我不久前刚换的jdk1.8),最后上网看后,了解了了一些,jdk1.8后局部变量默认加final的.
public class Test1 { public static void main(String[] args) { new Out().fun();//16 } } class Out{ final int j = 10; private int x = 0; public void fun(){ final int k = 6; class In{ public void inMethod(){ x = k; System.out.println(x + j); } } new In().inMethod(); } }
第2题:一个ArrayList对象aList中存有若干个字符串元素,现欲遍历该ArrayList对象,删除其中所有值为"abc"的字符串元素,请用代码实现。
public class Test2 { public static void main(String[] args){ //定义一个ArrayList集合 ArrayList al = new ArrayList(); //往集合中添加元素 al.add("bac"); al.add("abc"); al.add("acb"); al.add("abc"); al.add("abcd"); //打印原集合 System.out.println(al);//[bac, abc, acb, abc, abcd] //调用opList方法,对集合进行操作 List list = opList(al); //打印删除值为"abc"的字符串元素后的新集合 System.out.println(list);//[bac, acb, abcd] } /** * 删除传入集合中所有值为"abc"的元素*/ public static List opList(List list){ //遍历集合 for(Iterator it = list.listIterator(); it.hasNext();){ String str = (String)it.next(); //如果元素的值为abc,则移除 if("abc".equals(str)){ it.remove(); } } return list; } }
第3题 :写一个方法,此方法可将obj对象中名为propertyName的属性的值设置为value.
public void setProperty(Object obj, String propertyName, Object value){}
public class Test3 { public static void main(String[] args){ TestDemo td = new TestDemo(); new Test3().setProperty(td, "propertyName", "itheima"); System.out.println(td.getPropertyName());//itheima } //此方法可将obj对象中名为propertyName的属性的值设置为value public void setProperty(Object obj, String propertyName, Object value){ try { //获取obj对象的.class(字节码文件) Class clazz = obj.getClass(); //获取obj对象中名为propertyName的属性 Field field = clazz.getDeclaredField(propertyName); //设置可以访问全部属性 field.setAccessible(true); //将obj对象中的名为propertyName的属性的值设置为value field.set(obj, value); } catch (Exception e) { e.printStackTrace(); } } } /** * 测试类 * */ class TestDemo{ private String propertyName; public String getPropertyName() { return propertyName; } public void setPropertyName(String propertyName) { this.propertyName = propertyName; } @Override public String toString() { return "TestDemo [propertyName=" + propertyName + "]"; } }
第4题:有五个学生,每个学生有3门课(语文、数学、英语)的成绩,写一个程序接收从键盘输入学生的信息, 输入格式为:name,30,30,30(姓名,三门课成绩),然后把输入的学生信息按总分从高到低的顺序写入到一个名称"stu.txt"文件中。要求:stu.txt文件的格式要比较直观,打开这个文件,就可以很清楚的看到学生的信息。
思路:创建Stedent类,读取键盘输入的数据,并把数据封装到Student对象中
再把Student对象存入集合中,因为需要对Student对象排序,所以选用TreeSet集合最后把Set集合用流保存到本地硬盘上
public class Test4 { public static void main(String[] args) throws IOException { Set<Student> stus = StudentOp.getStudents(); StudentOp.outputInf(stus); } } /** * 学生类 因为学生需要排序,所以使用TreeSet集合存储学生信息 * 所以需要实现Comparable接口 * */ class Student implements Comparable<Student> { private String name; private int cn,math,en; private int sum; Student(String name,int math,int cn,int en) { this.name = name; this.math = math; this.cn = cn; this.en = en; sum = math + cn + en; } //为了避免Hashset集合中出现重复元素,所以覆盖hashCode方法和equals方法 public int hashCode() { //使用姓名和总分来判断是否出现重复 return name.hashCode() + sum*23+100; } //覆盖equals方法 public boolean equals(Object obj) { //判断传入的类型是否为Student类 if(!(obj instanceof Student)) throw new ClassCastException("传入的类型不匹配!"); Student s = (Student)obj; //通过比较姓名和总分判断俩个实例是否相等 return this.name.equals(s.name) && this.sum == s.sum; } //覆盖toString方法 public String toString() { return "姓名:" + name + " | 语文:"+ cn +" | 数学:" + math +" | 英语:" + en; } //get和set方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getSum() { return sum; } public void setSum(int sum) { this.sum = sum; } //重写比较器中的方法给学生类进行排序 @Override public int compareTo(Student s) { //因为是需要按照总分从高到底的顺序进行排序,所以需要用参数中的对象和当前对象比较 int num = new Integer(s.sum).compareTo(new Integer(this.sum)); //如果总分相等,再根据姓名排序 if(num == 0) return this.name.compareTo(s.name); return num; } } /** * 接收键盘输入的数据,并吧数据封装到Student对象中,再把student对象存入set集合中 * */ class StudentOp { public static Set<Student> getStudents() { //接收键盘的输入的数据 BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); String line = null; //创建一个带有泛型的set集合 Set<Student> set = new TreeSet<Student>(); try { while((line = bufr.readLine()) != null) { if("over".equals(line)) break; String[] inf = line.split(","); //把键盘输入的数据封装到student对象中 Student stu = new Student(inf[0], Integer.parseInt(inf[1]), Integer.parseInt(inf[2]), Integer.parseInt(inf[3])); //把封装好的Student对象存入set集合中 set.add(stu); } } catch (NumberFormatException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally{ try { bufr.close(); } catch (IOException e) { throw new RuntimeException("读取流资源释放失败"); } } return set; } /** * 把set集合中的数据写到本地硬盘上 * */ public static void outputInf(Set<Student> set) { BufferedWriter bufw = null; try { //创建一个写入流对象 bufw = new BufferedWriter(new FileWriter("E:" + File.separator + "itheimaExam" + File.separator + "test4.txt")); //把set集合中的数据写入到本地硬盘上 for(Student stu : set) { bufw.write(stu.toString()); bufw.write(" |总分:" + "(" + stu.getSum() + ")"); bufw.newLine(); bufw.flush(); } } catch (IOException e) { throw new RuntimeException("写入文件失败"); } finally{ try { if(bufw != null){ bufw.close(); } } catch (IOException e) { throw new RuntimeException("写入流资源释放失败"); } } } }
第5题:统计一个文本文件中字符出现的次数,结果存入另外的一个文本文件中。例如:
a : 21 次
b : 15 次
c : 15 次
d : 7 次
e : 9 次
f : 3 次
g : 30 次
思路:1.将字符串转换成每一个字母,因为要对每一个字符进行操作
2.因为字符和其对应的次数是键值对,所以定义一个map集合来存储
3.遍历字符数组,将每一个字符作为键去查询Map集合,
若Map集合中没有这个键,则将这个字符作为键,1作为值存入map集合中
若map集合中的键存在当前的字符,则键该键对应的值取出,进行自增操作后重行吧该字符和进行自增后的值
存入集合
4.将map集合的键值按照指定格式存储到指定文件中
public class Test5 { public static void main(String[] args){ output(stat(input())); } /** * 读取硬盘上指定文件中的数据,并转换成一个字符串 * */ public static String input(){ //创建一个文件对象,从硬盘上读取文件 File f = new File("E:" + File.separator + "itheimaExam" + File.separator + "test5.txt"); //因为操作的是字符对象,且为了提高效率,用缓冲流BufferedReader BufferedReader br = null; //创建一个StringBuilder对象 StringBuilder sb = new StringBuilder(); try { br = new BufferedReader(new FileReader(f)); String line = null; //去读硬盘上文件的内容 while((line = br.readLine()) != null){ //把文件上读取到的内容添加到StringBuilder对象里 sb.append(line); } } catch (IOException e) { throw new RuntimeException("读取文件失败"); } finally{ if(br != null){ try{ br.close(); }catch(IOException e){ throw new RuntimeException("读取流资源释放失败"); } } } //把StringBuileder里面的内容转换成一个字符串 String str = sb.toString(); return str; } /** * 统计传入字符串中字母出现的次数,并把字符作为键,次数作为值存入map集合中 * */ public static Map stat(String str){ //把字符串对象转换成字符数组 char[] cArray = str.toCharArray(); //创建一个TreeMap对象 Map<Character,Integer> map = new HashMap<Character,Integer>(); //创建一个计数器 int count = 0; //遍历字符数组 for(char c : cArray){ //如果字符数组不在a-z或者A-Z则返回继续遍历 if(!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')){ continue; } //遍历到的字符作为键,获取其对应在map集合中的值 Integer value = map.get(c); //如果值不为空,则说明该字符已经出现过,则把该值传给计数器 if(value != null){ count = value; } count ++ ; //把新的字符数组和值重行存入map集合中 map.put(c, count); //把计数器清0 count = 0; } return map; } /** * 遍历map集合,并把里面的键和值按照规定的格式写到指定的文件中 * */ public static void output(Map map){ //通过enretSet()方法获取Map集合的键值对映射 Set<Map.Entry<Character, Integer>> setEntry = map.entrySet(); //声明一个BufferedWriter BufferedWriter bw = null; try{ //创建一个文件对象 File file = new File("E:" + File.separator + "itheimaExam" + File.separator + "result5.txt"); bw = new BufferedWriter(new FileWriter(file)); //获取map集合的键值并按规定的格式写入文件 for(Iterator<Map.Entry<Character, Integer>> it = setEntry.iterator(); it.hasNext();){ Map.Entry<Character, Integer> mapEntry = it.next(); bw.write(mapEntry.getKey() + ":" + mapEntry.getValue() + "次"); bw.newLine(); bw.flush(); } } catch(IOException e){ throw new RuntimeException("写入文件失败!"); } finally { if(bw != null){ try { bw.close(); } catch (IOException e) { throw new RuntimeException("写入流资源释放失败!"); } } } } }
第6题:编写一个类,增加一个实例方法用于打印一条字符串。并使用反射手段创建该类的对象,并调用该对象中的方法。
public class Test6 { public static void main(String [] args) throws Exception{ //获取类的字节码对象 Class clazz = PrintDemo.class; //创建类的实例对象 PrintDemo pt = (PrintDemo) clazz.newInstance(); //获取对象中名为sop的方法,并调用 clazz.getDeclaredMethod("sop", String.class).invoke(pt, "itheima"); } } /** * 测试类 * */ class PrintDemo{ //将字符串打印到控制台 public void sop(String str){ System.out.println(str);//itheima } }
第7题:使用TCP协议写一个可以上传文件的服务器和客户端。
思路:因为时刻有客户端需要连接到服务端,所以服务端要为每一个连接进来的客户端创建一个线程
/** * 客户端 * */ public class Test7 { public static void main(String[] args) { Socket s = null; FileInputStream fis = null; try { // 创建一个流套接字并将其连接到指定 IP地址的指定端口号 s = new Socket("127.0.0.1", 8888); // 创建一个文件对象 File file = new File("E:" + File.separator + "itheimaExam" + File.separator + "test7_client.txt"); // 创建一个文件输出流对象 fis = new FileInputStream(file); // 获取流套接字的输出流 OutputStream out = s.getOutputStream(); // 向流中输出数据 byte[] buf = new byte[1024]; int len = 0; while ((len = fis.read(buf)) != -1) { out.write(buf, 0, len); } // 告诉服务端数据已经写完 s.shutdownOutput(); // 获取套接字的输入流对象 InputStream in = s.getInputStream(); // 获取服务端的反馈信息,并打印到控制台 byte[] bufIn = new byte[1024]; int num = in.read(bufIn); System.out.println(new String(bufIn, 0, num)); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (fis != null) { fis.close(); } } catch (IOException e) { throw new RuntimeException("输入流资源释放失败"); } finally { try { if (s != null) { s.close(); } } catch (IOException e) { throw new RuntimeException("客户端关闭失败"); } } } } } /** * 服务端线程类 * */ class TcpClient implements Runnable { private Socket s; // 创建服务端类的构造器,在生成服务端对象时传入一个端点(套接字); TcpClient(Socket s) { this.s = s; } public void run() { // 为了避免客户端上传重名的文件,创建一个计数器,有重名则在其名字后加上计数器中存储的数再存入 int count = 1; // 获取连接进来客户端的的ip String ip = s.getInetAddress().getHostAddress(); try { // 当有客户端连接进来,在控制台打印其ip System.out.println(ip + "....connected"); // 获取连接进来客户端的输入流 InputStream in = s.getInputStream(); // 创建一个文件对象 File file = new File("E:" + File.separator + "itheimaExam" + File.separator + "test7_server.txt"); // 若果客户端上传与服务端重名的文件,则在其名字后面按上传的顺序加上数字 while (file.exists()) file = new File("E:" + File.separator + "itheimaExam" + File.separator + "test7_server" + count++ + ".txt"); // 创建文件输出流对象 FileOutputStream fos = new FileOutputStream(file); byte[] buf = new byte[1024]; // 把客户单传进来的文件输出到本地硬盘上 int len = 0; while ((len = in.read(buf)) != -1) { fos.write(buf, 0, len); } // 获取连接进来的客户端输出流对象 OutputStream out = s.getOutputStream(); // 给客户端回复应答信息 out.write("上传成功".getBytes()); // 关闭流对象 fos.close(); // 关闭客户端对象 s.close(); } catch (Exception e) { throw new RuntimeException("文件上传失败"); } } } /** * 服务端 * */ class TcpServer { public static void main(String[] args) { // 创建服务端的端点(套接字) ServerSocket ss; try { // 创建服务端的端点(套接字),并绑定到指定的本地端口上 ss = new ServerSocket(8888); while (true) { // 获取连接进来的客户端对象 Socket s = ss.accept(); // 开启服务端线程 new Thread(new TcpClient(s)).start(); } } catch (IOException e) { e.printStackTrace(); } } }
第8题:编写一个程序,它先将键盘上输入的一个字符串转换成十进制整数,然后打印出这个十进制整数对应的二进制形式。
这个程序要考虑输入的字符串不能转换成一个十进制整数的情况,并对转换失败的原因要区分出是数字太大,还是其中包含有非数字字符的情况。
提示:十进制数转二进制数的方式是用这个数除以2,余数就是二进制数的最低位,接着再用得到的商作为被除数去除以2,这次得到的余数就是次低位,如此循环,直到被除数为0为止。
其实,只要明白了打印出一个十进制数的每一位的方式(不断除以10,得到的余数就分别是个位,十位,百位),就很容易理解十进制数转二进制数的这种方式。
public class Test8 { public static void main(String[] args) { test(); } public static void test(){ //定义俩个int变量,分别表示键盘上获取的数字和余数 int num = 0, mod; System.out.println("请输入:"); //创建一个字符缓冲流对象用于接收键盘输入的字符 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String str = null; try { //从键盘上读取一行数据 str = br.readLine(); //把键盘上读取到的数据转换成字符数组 char[] ch = str.toCharArray(); //判断是否存在非数字的字符 for (char c : ch) { if (!Character.isDigit(c)) { System.out.println("输入的字符有非数字字符!程序退出"); return ; } } }catch (IOException e) { e.printStackTrace(); } //把字符串转换成整形数 num = Integer.parseInt(str); //判断数字是否超出范围 if(num > Integer.MAX_VALUE){ System.out.println("数字超出范围"); return ; } //定义一个字符串对象,用于把每次的余数串接起来 String s = ""; //不断用二除,直到除不开,再把余数倒置 while (num != 0) { mod = num % 2; num = num / 2; s = mod + s; } //把最终的二进制数打印到控制台 System.out.println(s); } } 请输入: 100 1100100
第9题:金额转换,阿拉伯数字转换成中国传统形式。
例如:101000001010 转换为 壹仟零壹拾亿零壹仟零壹拾圆整
public class Test9 { public static void main(String[] args){ new Switch().switchNum(1234);//壹仟贰佰叁拾肆圆整 } } class Switch{ //构建汉字的字符数组 private char[] chineseNum = {'零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖' }; private char[] chinese = {'圆', '拾', '佰', '仟'}; public void switchNum(int number){ int qian,bai,shi,ge; //分别取千位,百位,十位,个位 qian = number / 1000; bai = (number % 1000) / 100; shi = (number % 100) /10; ge = number % 10; //把取到的各位到字符数组中查找各自对应的汉字 char[] newChar = {chineseNum[qian], chinese[3], chineseNum[bai], chinese[2],chineseNum[shi],chinese[1],chineseNum[ge],chinese[0]}; //打印输出 for(char c : newChar){ System.out.print(c); } System.out.println("整"); } }
第10题:28人买可乐喝,3个可乐瓶盖可以换一瓶可乐,那么要买多少瓶可乐,够28人喝?假如是50人,又需要买多少瓶可乐?(需写出分析思路)
结果:经本程序运行:28个人需要19瓶可乐,50个人需要34瓶可乐
思路:可乐可分为俩类,1:花钱买的,2:瓶盖换的,而最后需要输出的是花钱买的可乐数量
最终不变的原则是要为每一个人分一瓶可乐,不管这瓶可乐是花钱买的还是瓶盖换的
所以,利用for循环遍历每一个人,for循环中为当前的人分一瓶可乐即可
如果瓶盖数量不够三个,则为当前遍历到的那个人买一瓶可乐,则花钱买的可乐总数加1,相应的瓶盖总数也加1。
如果瓶盖的数量够三个了,则用着三个瓶盖为当前遍历的人换一瓶可乐,这样,花钱买的可乐数量不增加,瓶盖数量变为1个
public class Test10 { public static void main(String[] args) { System.out.println("需要买" + cokeNum(50) + "瓶");//需要买34瓶 } public static int cokeNum(int personNum){ //定义一个变量bCap表示瓶盖数量 int bCap = 0; //cokeSum表示需要可乐的总数 int cokeSum = 0; //遍历当前的每一个人 for(int i = 0; i < personNum; i++){ //瓶盖数量不为3 if(bCap != 3){ //花钱买的可乐数量加1 cokeSum++; //瓶盖数量加1 bCap ++; } //瓶盖数量够三个了 else if(bCap == 3){ //用三个瓶盖为当前的人换一瓶可乐,则瓶盖数量变为1 bCap = 1; } } return cokeSum; } }