201521123091 《Java程序设计》第2周学习总结

Java 第二周总结

第二周的作业。

一个简陋的目录
1.本章学习总结
2.Java Q&A
3.使用码云管理Java代码
4.PTA实验
5.小任务


1.本章学习总结

基本数据类型

  • String类
  • Java的标准输入输出和文件输入输出
  • Java控制执行流程
  • Java数组的使用
  • 类管理机制:包

2.Java Q&A

1.使用Eclipse关联jdk源代码(截图),并查看String对象的源代码?简单分析String对象的设计思路。

  1. 从“Window (菜单项目)”上选择“Preferences (菜单项目)”
  2. 展开“Java (框线项目)”(位于“Preferences”中)
  3. 选择“Installed JREs (框线项目)”(位于“Preferences”中)
  4. 选中当前JRE,并且点击Edit按钮
  5. 展开JRE系统库的第二项,选中展开后的第一项,点击“Source Attachment”按钮
  6. 打开JDK目录,选中src.zip,最后一路确定出去

  7. ctrl+鼠标左键选中某一个类,或者选中类之后按F3,源代码文件弹出,第一问就搞定了

到此为止,只是这一问的第一小问结束了0.0(各位看官不急,我还在码)

String对象的设计思路(我们可以看到在源代码文档里面已经有说了,所以我们要做的仅仅是翻译一下,当然英文不好的同学(比如我这种),可以借助类似金山词霸之类的划译)

我们可以看到就是这点,字符串是常量,往下翻翻我们就会看到private final char value[];,用一个final修饰的字符数组来实现这个字符串的

2.为什么要尽量频繁的对字符串的修改操作应该是用StringBuilder而不是String?
这个东西我们就有讲头了,不妨来看几个String类自带的方法吧。

//这是一个字符串连接的方法
public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        return new String(buf, true);
    }
//这是一个替换的方法
public String replace(char oldChar, char newChar) {
        if (oldChar != newChar) {
            int len = value.length;
            int i = -1;
            char[] val = value; /* avoid getfield opcode */

            while (++i < len) {
                if (val[i] == oldChar) {
                    break;
                }
            }
            if (i < len) {
                char buf[] = new char[len];
                for (int j = 0; j < i; j++) {
                    buf[j] = val[j];
                }
                while (i < len) {
                    char c = val[i];
                    buf[i] = (c == oldChar) ? newChar : c;
                    i++;
                }
                return new String(buf, true);
            }
        }
        return this;
    }

在对字符串进行相应修改(例如替换或者是连接)的时候,我们可以发现最后都返回了一个新的字符串常量。所以我们可以想见,如果有大量的字符串拼接的话,那么我们的代码一定会new出很多的String变量,然后又会有很多的垃圾回收。这样的话,代码的效率就会有所降低。

这边来看个代码吧(当然是从Thinking in Java上抄下来的。。。)

public class Concatenation{
	public static void main(String[] args) {
		String mango = "mango";
		String s = "abc" + mango + "def" + 47;
		System.out.println(s);
	}
}

然后使用javap进行反汇编看看发生了什么。。。

Compiled from "Concatenation.java"
public class Concatenation {
  public Concatenation();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String mango
       2: astore_1
       3: new           #3                  // class java/lang/StringBuilder
       6: dup
       7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      10: ldc           #5                  // String abc
      12: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/Stri
ngBuilder;
      15: aload_1
      16: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/Stri
ngBuilder;
      19: ldc           #7                  // String def
      21: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/Stri
ngBuilder;
      24: bipush        47
      26: invokevirtual #8                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      29: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      32: astore_2
      33: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
      36: aload_2
      37: invokevirtual #11                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      40: return
}

好了,我们看到这个编译器自动引入了一个叫做StringBuilder的东西,,使用它来进行字符串的拼接。这当然是因为StringBuilder更好了,我们刚才说String是immutable的,那这个StringBuilder是专门为字符串修改而生的,在Java SE5引入。所以编译器很聪明的对代码进行了优化。那也就是说,我可以随意使用String,等着代码优化吗?当然不行咯,Java编程思想又给我们举了个反例,来看看。

哦,对了,在String的源文档里面有这样一句话,一样的意思

String concatenation is implemented through the {@code StringBuilder}(or {@code StringBuffer}) class and its {@code append} method.

利用循环来进行字符串的拼接

//输入一个n,从0-n的数字转成字符串进行拼接
public class Main{
	public static void main(String[] args) {
		int n = 5;
		String result1 = "";
		for (int i = 0; i < n; i++) {
			result1 += i;
		}
		System.out.println(result1);
		
		StringBuilder result2 = new StringBuilder();
		for (int i = 0; i < n; i++) {
			result2.append(i);
		}
		System.out.println(result2.toString());
	}
}

我们再来反汇编(* * *大法好,虽然我不是很懂)

Compiled from "Main.java"
public class Main {
  public Main();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_5
       1: istore_1
       2: ldc           #2                  // String
       4: astore_2
       5: iconst_0
       6: istore_3
       7: iload_3
       8: iload_1
       9: if_icmpge     37
      12: new           #3                  // class java/lang/StringBuilder
      15: dup
      16: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      19: aload_2
      20: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/Stri
ngBuilder;
      23: iload_3
      24: invokevirtual #6                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      27: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      30: astore_2
      31: iinc          3, 1
      34: goto          7
      37: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
      40: aload_2
      41: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      44: new           #3                  // class java/lang/StringBuilder
      47: dup
      48: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      51: astore_3
      52: iconst_0
      53: istore        4
      55: iload         4
      57: iload_1
      58: if_icmpge     74
      61: aload_3
      62: iload         4
      64: invokevirtual #6                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      67: pop
      68: iinc          4, 1
      71: goto          55
      74: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
      77: aload_3
      78: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      81: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      84: return
}

代码中9-34行是第一个循环(用String的那个),我们可以看到,每次循环开始都会new一个StringBuilder变量,58-71行是第二个循环(用StringBuilder的那个),当然是只在我们一开始new了一个。这个循环更简短,效率当然更高。

3.比较两个字符串的值是否相等?为什么不能用==直接进行比较?

因为用进行比较并不能保证结果总是正确的(假设下面的情况字符串的内容都是相同的),比较的是两个对象的引用

  • 首先如果两个字符串都是以 String xxx = "xxxxx";的方式创建出来的,在第一个字符串如此创建时,JVM就会在字符串池中维护这么一个String的实例,那么以后只要有内容完全相同的字符串,就直接指向这个实例,所以引用会相同

  • 只要有一个是以new的方式创建新的实例,就会创建一个新的对象,当然就有不一样的引用,所以这时候==的两边是不同的引用,当然会返回false

综上所述,我们要对两个字符串进行内容的比较的话,我们要选用一种不是==的方法,那就是equals()方法,看下面的具体实现,没毛病

 public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

但是不是所有的equals()方法都是比较内容,我们这边可以举个小小的反例

class Value{
	int i;
}



public class EqualsMethod2 {
	public static void main(String[] args) {
		Value v1 = new Value();
		Value v2 = new Value();
		v1.i = v2.i = 100;
		System.out.println(v1.equals(v2));
	}
}

输出结果是false,这是因为equals()的默认行为是比较引用,只是Java类库当中的许多类都已经自己实现了equals()方法,显然我们这边并没有重写这个equals()的方法,所以这边还是只是比较引用

4.尝试使用字符串池的概念解释如下程序段输出结果,并回答这段代码创建了几个字符串对象:

String str1 ="hi", str2="hi";
String str3 = new String(str1);
System.out.println(str1==str2);

最后输出true
分析在前面已经说过了,一共会有两个对象,str1创建的时候,字符串池里面会有一个,也就是str2直接指向字符串池中的那个实例。
然后str3在字符串池外面又new了个

5.Integer i = 100;//100是基本类型,i是引用类型,为什么可以将100赋值给i

public class Main {
  public Main();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: bipush        100
       2: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       5: astore_1
       6: return
}

同样看到反汇编,我们就可以看到只是调用了Integer类的valueOf的方法而已,然后这个方法是public static Integer valueOf(int i)这样子的,返回一个Integer

6.尝试分析下面代码输出结果

Integer i1 = 127;Integer i2 = 127;
i1 == i2;//true of false?
Integer i1 = 128;Integer i2 = 128;
i1 == i2;//true of false

输出结果分别是truefalse
上回我们刚刚谈到,我们用到了valueOf()这个方法,去给这个Integer进行赋值,so我们需要研究一下这个方法,贴上JDK源码。

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

!这是什么东西,对于不同的范围还区别对待?
是这样的,这个IntegerCache,整数缓存是?再贴源代码(截取部分)

private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

好了,这样我们就知道了,这个IntegerCache是通过Cache数组来实现的,然后-128-127这256个数就被放在了这个数组里,当我valueOf()方法的参数在这个范围内的话,我就将数组中的值返回去,也就是说一开始i1和i2都指向了数组的同一位置,所以当然是相等的咯
然后这个128就相当的尴尬了,因为他正好就在这个范围之外了,所以我们用最朴素的方法创建这个Integer对象,那么就像我们之前所说,通过new来创建的对象具有不同的引用,so传回了false

7.package与javac、 java、 -classpath、 -d
在 com.ibm包中编写 StringUtil类,内有一方法

public static void foo1(){
 System.out.println(StringUtil.class+" method:foo1");
}
  • 尝试用命令行进行编译并运行,截图使用javac -d. StringUtil.java使用-d编译选项,建立了相应的文件,将生成的字节码放在了\com\ibm下面

编写Main.java,在第一行加上package edu.jmu,编译后再次生成相应字节码文件
然后再用java命令执行,结果如截图

  • 将生成的StringUtil.class放到d:\lib正确的目录结构下,将Main.class在d:\test正确的目录结构,尝试在命令行下运行,并截图。
    目录结构如下所示:
    • D
      • lib
        • com
          • ibm
            • StringUtil.class
      • test
        • edu
          • jmu
            • Main.class

之前用powershell搞了很久,怼不出来。最后换成cmder就成功了

  • Eclipse中源代码放在哪个目录、class文件放在哪个目录。在Eclipse项目中按一下ctrl+f11就可以直接运行Main,尝试分析背后实现的原理

源代码放在src里面,class放在bin文件夹中。

8.自己在这门课的目标与计划

  • 请描述一下你的技术基础(会什么语言,都写了多少行代码)

    • C 有上万吗,可能有,可能没有吧
    • Matlab 上一千行,应该是有了
    • Python 上百行
  • 一周准备花多少时间在这门课上?一周准备写多少行代码?采用怎样的学习方式?遇到困难打算怎样解决?

    • 具体多长时间不清楚,毕竟还得顾着我的蓝桥杯
    • 一周写个一百多行什么的,还是可以的吧,具体的代码量同样还是不清楚
    • 遇到困难
      • 百度、谷歌……
      • 看书
      • 问老师
      • 放弃,我不搞了,开玩笑的
  • 关于这门课的smart目标
    首先这个是SMART

S pecific:具体的,无二义性的,能描述 “成功” 是什么样的。
M otivating: 目标能激发对目标的兴趣么?实现目标对学生来说说意味着什么?他们会为之自豪么?
A chievable: 能做到么?是挟泰山以超北海?还是把墙角一堆砖头搬走?
R elevant: 和学生来到大学的大方向、目标吻合
T rackable: 能衡量进度的,和有些资料提到的 Measurable 相似。

要不就姑且试试Java web?虽然别人说这都是套框架,可是我连框架都不会套……

这让我想到职业规划的SWOT(S trengths, W eaknesses, O pportunities, T hreats)。那我就分门别类的说下吧。

  • 我觉得对于一门语言来说,怎么算是学成功了呢,应该就是能够使用这门语言真的做一件有实际用途的事情,可能主要是做开发之类的吧(现在还不是很清楚)
  • 分情况,假如我刚开始学编程的时候,会打printf("%d", a + b);我都会很开心。然而我们不可能总是停留在这个层次,我们总是需要向上走
  • 至于可行性,如果暂且把目标放的低一点,做一些简单功能的实现,我觉得还是可以的吧,不能一口吃成一个大胖子,也不能推得太慢吧。
  • 没什么大方向,也没什么具体的目标吧。很惭愧,感觉还是把现在的事情做好了再说。
  • 没试过啊,进度什么的先放着吧,要是凡事都能有个进度条就好了,很可惜并不是

话再说回来,很想在这个学期继续打牢计算机以及数学基础。不然就可以直接去培训机构,三个月上岗,而不用来大学了

9.选做:公交卡里应该还有多少钱?请分析原因

-0.1(元)参考腾讯新闻
可能是无符号浮点数下溢了。
不过……
新闻里说是这台闸机的问题,所以其他的闸机肯定是能正常显示的,那至于这个为什么不对,就不清楚了。

3.使用码云管理Java代码


4.PTA实验

  • 第一题,是函数调用,就是要注意需要sort的数组需要在循环输入选项的代码块外面就创建,如果在sort数组里面临时创建,当然其它选项是找不到的啦
  • 第二题,StringBuilder类的基本使用,就是一开始的时间限制压得很死,所以一会能A,一会又不能A。
  • 第三题,就是要自己去实现一下Comparator,然后就很流畅了
  • 第四题,for循环也可以,就是要一个二维数组,因为数据量不是很大,所以我是直接初始化了
  • 第五题,使用BigDecimal类来实现浮点数的精准计算,当然也可以用数组的方式来实现。不过既然有现成的,就用现成的好了
  • 第六题,枚举的基本使用
  • 第七题,可以用BigInteger实现的东西,就是学会用
  • 第八题,ArrayList的基本使用,相当于数据结构中提到的链表

5.小任务

代码有点丑陋……不过效果还行吧

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.Scanner;

public class Main {
	//用来找第一个不是空格的字符
	private static int firstCharNotSpace(String string) {
		int i;
		for (i = 0; i < string.length(); i++) {
			if (string.charAt(i) != ' ') {
				break;
			}
		}
		return i;
	}
	//如果是ABCD或是数字啥的,那么前面有空格就要删
	private static Boolean needToDeleteSpace(char ch) {
		if (Character.isDigit(ch) || ch >= 'A' && ch <= 'D') {
			return true;
		}
		return false;
	}
	public static void main(String[] args) throws FileNotFoundException {
		Scanner sc = new Scanner(new File("C:/Users/LJL36/Desktop/choice.txt"));
	    PrintWriter printWriter = new PrintWriter("C:/Users/LJL36/Desktop/output.txt");
	    int res = 0;//记录有多少道题目
	    
	    //这边很蠢的先统计了一下题目
	    while (sc.hasNextLine()) {
	    	String string = sc.nextLine();
	    	if (string.trim().length() == 0) {
	    		continue;
	    	}
	    	int index = firstCharNotSpace(string);
	    	if (Character.isDigit(string.charAt(index))) {
	    		res++;
			}
		}
	    printWriter.println(res);
	    
	    //重新打开文件
	    sc = new Scanner(new File("C:/Users/LJL36/Desktop/choice.txt"));
	    while(sc.hasNextLine()){
	    	StringBuilder stringBuilder = new StringBuilder(sc.nextLine());
	    	String string = stringBuilder.toString();
	    	//如果是空格串,就跳过
	    	if (string.trim().length() == 0) {
				continue;
			}
	    	//删空格
	    	int index = firstCharNotSpace(string);
	    	if (needToDeleteSpace(string.charAt(index))) {
				stringBuilder.delete(0, index);
			}
	    	
	    	//将答案在后面用pta要求格式输出
	    	index = string.lastIndexOf('。');
	    	if (index != -1 && index != string.length()) {
	    		boolean flag = false;
	    		String string2 = "@[";
	    		for (int i = index + 1; i < string.length(); i++) {
	    			if (Character.isLetter(string.charAt(i))) {
	    				flag = true;
						string2 += Character.toUpperCase(string.charAt(i));
					}
	    		}
	    		string2 += "](2)";
	    		
	    		stringBuilder.delete(index + 1, string.length());
	    		
	    		if (flag) {
	    			stringBuilder.append(string2);
				}
	    	}
	    		
	    	stringBuilder.append("  ");
	    	printWriter.println(stringBuilder.toString());
	    }
	    sc.close();
	    printWriter.close();
	}
}

下面贴一下最后的运行结果

看的不过瘾的请点下面
回到顶部


最后总是要说句废话什么的,有同学和我说我的排版太丑陋了。嗯……我只能顾上眼前的苟且了,非常感谢偷偷看我博客的同学,可是能不能粉我一下,我也会回粉你们的,谢谢~

posted @ 2017-03-02 19:13  学Java救不了中国人  阅读(799)  评论(24编辑  收藏  举报