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

时间:2021-06-03 14:35:23

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按钮

    201521123091 《Java程序设计》第2周学习总结
  5. 展开JRE系统库的第二项,选中展开后的第一项,点击“Source Attachment”按钮

    201521123091 《Java程序设计》第2周学习总结
  6. 打开JDK目录,选中src.zip,最后一路确定出去

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

    201521123091 《Java程序设计》第2周学习总结
  7. ctrl+鼠标左键选中某一个类,或者选中类之后按F3,源代码文件弹出,第一问就搞定了

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

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

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

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

我们可以看到就是这点,字符串是常量,往下翻翻我们就会看到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下面

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

编写Main.java,在第一行加上package edu.jmu,编译后再次生成相应字节码文件

然后再用java命令执行,结果如截图

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

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

    目录结构如下所示:
    • D
      • lib
        • com
          • ibm
            • StringUtil.class
      • test
        • edu
          • jmu
            • Main.class

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

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

  • 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.选做:公交卡里应该还有多少钱?请分析原因

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

-0.1(元)参考腾讯新闻

可能是无符号浮点数下溢了。

不过……

新闻里说是这台闸机的问题,所以其他的闸机肯定是能正常显示的,那至于这个为什么不对,就不清楚了。

3.使用码云管理Java代码

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


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();
}
}

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

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

看的不过瘾的请点下面

回到顶部


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