首页 > 代码库 > java学习笔记3

java学习笔记3

I/O

  • 输出用System.out的方法,输入是不是用System.in呢?答案是…………NO!我去……
  • 普通输入可以用Scanner类,它属于java.util,所以用之前要

    import java.util.*;

    用法是

    Scanner in = new Scanner(System.in);

    然后用这个Scanner对象的方法来读

  • 读一行用nextLine(),读一个词用next(),读一个整数用nextInt(),读一个浮点数用nextDouble()

  • 要读密码不想明文显示,可以用

    Console cons = System.console();char[] pw = cons.readPassword("Password: ");

注意console的这个readPassword出于安全原因返回的不是String,是char[]。另外它可以接受字符串做prompt

  • Console只能一次读一行
  • %s 可以用来输出任何implement了Formattable这个interface并且override了formatTo()的类,或者implement了toString()也行
  • Java还新加了用来输出时间的%t以及各种组合,还有各种各样的方便输出,参见Formatter
  • 输出时间的转换符是有locale的,如果有n个都用的是同一个Date,可以用%n$来指定是format string后的第几个参数,n从1数起
  • 静态方法String.format可以用来合成format过的String

文件IO

  • 输入用

    Scanner in = new Scanner(Path.get("test.txt"));

    这样,注意Scanner的构造函数的参数不是一个String,是一个Path,如果是一个String,那么读入的不是文件内容,而就是那个String。各种构造函数的区别看这里.

  • 输出用

    PrintWriter out = new PrintWriter("test.txt");

    这回可以直接传String进去了,简直太不对称了= = 而且要注意这东西是在java.io下面的

  • 文件目录相对于执行起Java程序时的工作目录来算
  • 因为文件IO可能会抛异常(文件不存在啦,文件创建不了啦之类的),在Java里要对这些操作所在的函数声明你知道会出现这些异常,写法类似于

    public static void main(String[] args) throws FileNotFoundException {...}

如果跑java程序的时候用重定向符加上了IO用的文件就可以不用担心这些异常。

控制流

  • Java没有goto,虽然goto是它的保留字= =
  • Java用{}来定block scope
  • Java里没有nested scope的shadowing,能看到同一个scope的就不许有同名变量(果然是防猪队友专用语言),除非这些同名变量定义在for的那句里
  • while和if跟C/C++家族的基本差不多
  • Java的浮点数也是不能直接比较的
  • Java里依然存在那个很无聊的switch,如果怕出现手误写了个不想要的fall through,可以在编译的时候用

    javac -Xlint:fallthrough ...

    来开lint警告自己。如果某些函数又要用到fall through,可以加上

    @Suppress-Warnings("fallthrough")

    来绕过警告

  • 如果被switch的是一个enum类型,在case后面的值不用加上enum类型的前缀

大数

  • Java自带一个BigInteger来处理超大整数
  • 静态函数BigInteger.valueOf可以用来将普通的数字转换成BigInteger对象
  • BigInteger不能用加减乘除运算符,因为Java没有运算符重载这种东西,唯一的例外是String的+,不知道Java的设计者们到底是什么脑回路……加减乘除要用add、subtract、multiply、divide这种方法,取余用mod,比较用compareTo(注意返回的不是布尔值,0代表等于之类这样)
  • 还有一个对应的BigDecimal来处理超大浮点数,除法还要用上一个RoundingMode,valueOf还支持用个scale来修改数值

数组

  • Java里声明数组可以把[]放在类型那边,像这样

    int[] a;

    这是推荐的写法,虽然也可以像C/C++一样写

    int a[];
  • 初始化可以用

    array = new Type[size];

    的形式,和C/C++不一样的是,这里的size可以是变量,也就是数组大小可以到运行时再确定。这样初始化的数组里面的值是

    • 数字就是都0
    • 布尔值就都是false
    • 对象,包括String,全是null

    不会有垃圾值,再一次防止被猪队友坑……

  • 声明和初始化写在一起可以

    Type[] array = new Type[size];

    或者

    Type[] array = {t1, t2, ..}
  • 数组对应的类叫Arrays,注意有个s
  • 一次性填充值可以这样

    Arrays.fill(array, value);
  • 数组的长度可以用array.length获取(和JS一样~)。Java允许长度为0的数组
  • 数组除了可以用new重新赋值以外,还可将先显式初始化匿名数组拿来赋值

    array = new Type[] {t1, t2, ...};
  • 将一个数组赋给另一个数组是shallow copy,它们会共享一个引用,这点和JS是一样的。Java的数组都放在堆上。
  • 如果要得到deep copy,可以用Arrays.copyOf

    array1 = Arrays.copyOf(array2, size);

    这里的size可以超过array2的大小,多出来的部分会按照初始化的规则填充

  • 如果经常要改动数组大小,不如用ArrayList替代
  • Java有类似C++新特性的

    for(variable : collection)

    的语法,只不过连auto都不用了,会自己做类型推导

  • 数组的toString方法可以将数组转换成类似于

    "[1,2,3]"

    这样的字符串

  • []运算符会自动检查是否越界,Java也没有指针算术这种黑魔法
  • main函数的String[]类型的命令行参数里,没有运行程序的名字,像这样

    java prog -h

    那么命令行参数的第0个元素就是"-h",前面的不算

  • Java的数组自带sort方法,用的是改进过的快排,还自带binarySearch,也有equals来做比较

多维数组

  • Java也是支持二维数组的,声明方法类似于

    Type[][] matrix;

    初始化用

    matrix = new Type[size1][size2];

    或者

    matrix = { {...}, {...}, {...}...};

    注意用花括号嵌套区分行

  • for-each loop也要套两遍,且套行的那遍要写类型

    for (Type[] row : matrix)    for (cell : row) { ... }
  • Arrays有一个deepToString可以把二维数组也转换成字符串,用嵌套的[]和逗号标明

  • 其实Java的多维数组也和C/C++一样,是用一维数组伪装的,但是一行行底层不必连续存储,所以不必固定行的宽度。在Java里可以直接将行交换(其实就是换引用)

    matrx[1] = matrix[2]

    要得到长度不同的行也很容易,先声明有多少行

    Type[][] matrix = new Type[size1][];

    然后每行赋值一个长度不同的数组就行了,比如

    matrix[0] = new Type[50];matrix[1] = new Type[20];

    这样也是OK的