Java核心技术·卷一·第三章笔记

Java核心技术·卷一

第三章:Java的基本程序设计结构

3.1一个简单的Java应用程序

类名应该首字母大写,并采用驼峰命名法

public class 名应该与文件名相同,(才注意到原来自己写的class全是public的)

main函数也应是public的

与c++不同Java中的所有函数都必须是某个类的方法,main函数也不例外(所以mian函数会有一个外壳类)

因为main函数为void的,所以都会返回0,若想返回其他代码,需要使用System.exit方法。

public class Application {
    public static void main(String[] args) {
        System.out.println("Test");
        System.exit(-1);
    }
}

3.2注释

/** */ 可以自动生成文档

3.3数据类型

3.3.1整型

Java没有任何无符号整型

long a = 8L;
int b = 4;
short c = 2;
byte d = 1;
a = 100_000_000;//编译器会去掉这些下划线。
3.3.2浮点类型

默认为double类型,float类型需要在后面加f

Double.POSITIVE_INFINITY,Double.NEGETIVE_INFINITY,Doubel.NaN,即正无穷大,负无穷大,不是一个数字。他们不能用于比较,要检测是不是,只能使用方法

if(x==Double.NaN) //is never true
if(Double.isNaN(x))//可
3.3.3char类型

\u0000 ~ \uFFFF转义序列可以出现在加引号的字符常量和字符串之外

public static void main(String\u005B\u005D args)
    //完全符合语法规则,\u005B\u005D分别为[]的转义序列

一些特殊的转义字符

\b:退格,\t:Tab,\n,\r回车,\",\,\’

**注意:**Unicode转义序列会在解析代码之前得到处理,可以立即为宏的处理方式,而且很可能带来隐式的错误

例如

"\u0022+\u0022" //不会得到"+",而是""+"",即空字符串
//一定要消息注释里面的/u
// \u000A is a newline 会产生一个语法错误,因为提前处理之后,\u000A被替换成了一个换行符
// look inside c:\users 也会产生一个语法错误,因为\u之后并没有跟着一个4位16进制数

UnionCode的码点解决方案:没看懂,反正建议不要用char类型

3.3.5boolean类型

不能与0,1直接比较

3.4变量与常量

不要使用$字符,这是编译器用的

Java中不区分变量的定义与声明

int i = 0 ;//定义
extern int i;//声明

对于局部变量,如果在初始化的时候便可判断其类型,可以使用var关键字

var a = 12;
var b = "wuhu";

用final关键字设置常量,const关键字被保留了,但是没有使用,还是必须使用final

3.5运算符

strictfp:严格浮点运算,采用64位截断的浮点运算。例如intel的80位寄存器会先储存80位,运算后在截断为64位,这种称之为扩展的精度计算,可能会造成移植性问题。

例如标记为: public static strictfp main(String[] args)。但是这个仅作了解即可

StrictMath类在牺牲性能的前提下解决了Math类欠缺的在不同机器上运算结果可能不同的缺陷

Math的**Exact方法解决了溢出却不报错的问题:multiplyExact,addExact…

不要在boolean类型与任何一个其他类型强制转换

&& ||有短路性,|与&没有

”>>>"会使用0来填充高位,而“>>"会使用符号位来填充

3.6字符串

3.6.1字串

substring方法substring(start,end),从start开始,到end结束,但是不包括end。

3.6.2拼接

直接连接,而且会自动转换成string类型(例如int,boolean什么的)

String all = String.join("/","S","M","L","XL");
// resule is "S/M/L/XL"
String repeated = "Java".repeat(3);
// result is "JavaJavaJava"
3.6.3不可变字符串

不能修改字符串中的单个字符,String类对象是不可变的的,类似于常量“4”等等

但是可以修改变量

String gereting = "hello";
greeting = greeting.substring(0,3)+"p";
// result is "help"

不可变带来的是共享的高效率,字符串变量指向公共的储存池里面的字符串常量

得益于垃圾回收机制,对string赋新值并不会产生内存泄漏

3.6.4检测字符串是否相等

equals方法,与常量比较时应该调用常量的equals方法,这样可以减少空指针异常

不能用==来比较两个字符串是否相等,比较的实际上为他们的位置(上面讲的string类似于char *)

String example = "hello";
if("hello" == example)
    //probably true
if("hel" == example.substring(0,3))
    //probably false

如果虚拟机始终将相同的字符串共享,那么就可以用 == 来比较,但是实际上用+,substring等获得的字符串并不共享。

3.6.5空串与null串
3.6.6码点与代码单元

用char[i]指向的是代码单元,而辅助字符一个码点会包括两个代码单元,这会造成一些错误

(可能这也是哔哩哔哩禁用emoji字符的原因之一吧)

但是基本上码点和代码单元都是相等的

apl文档:Java™ EE 7 Specification APIs (oracle.com)

3.6.9构建字符串

需要由较短的字符串持续的构造字符串(例如从键盘读入),使用+,因为会不停的构造新的对象,效率较低。

可以使用StringBuilder类来解决这个问题

StringBuilder bulider = new StringBuilder();
builder.append(ch);
bulider.append(str);
//finished
String result = bulider.toString();

3.7输入与输出

3.7.1读取输入

Scanner对象

Scanner scanner = new Scanner(System.in);
System.out.println("Input test1");
String test1 = scanner.nextLine();//nextLine方法读取一行,不忽略空格
System.out.println("Input test2");
String test2 = scanner.next();//next遇到空格会停止读入
System.out.println("Input int a");
int a = scanner.nextInt();

注意:当使用的类不是java.lang包里面的,需要import导包(String是util里面的)

可以使用console类来实现密码输入(因为显示的密码输入不安全)

但是绝大多数ide会屏蔽console造成空指针异常;

import java.io.Console;

public class Test {
    public static void main(String[] args) {
        Console console = System.console();
        String username = console.readLine("Username:");
        char[] password = console.readPassword("Password:");
        System.out.println("Username:"+username+"password:"+password);
    }
}
3.7.2格式化输出

可以使用C语言的printf函数。具体的使用这里不做阐述

3.7.3文件输入与输出
//构造scanner对象输入
Scanner in = new Scanner(Path.of("myfile.txt"),StandardCharsets.UTF_8);//似乎不行
Scanner in = new Scanner(new File("myfile.txt"),StandardCharsets.UTF_8);
//输出
PrintWriter out = new PrintWriter("myfile.txt",StandardCharsets.UTF_8);

特别注意,可以构造一个带有字符参数的Scanner对象,但是Scanner会把这个字符参数解释为数据,而不是文件名

Scanner test = new Scanner("myfile");
test.nextLine();//result is "myfile";

文件的位置:文件位于相对于Java虚拟机启动的位置,如果使用ide,启动目录由ide控制

String dir = System.getProperty("myfile");
//可以使用这个获得绝对路径

3.8循环控制流程

Java不能在两个嵌套的块中声明两个同名的变量

public class Test {
    public int m = 0 ;
    public void test1(int m) {
        this.m = m;
        //Java中这里是 . 而不是-> ,不要被c++腐蚀了
        //注意,这里的两个m并没有在嵌套的块中,所以是被允许的
    }
}
public class Test {
    public static void main(String[] args) {
        int m = 0 ;
        if(m>=0) {
            int m;
        }
        //而这里就会报错了,两个m在嵌套的块中
    }
}

for循环中定义的变量的作用域为for循环块,出了代码块就没了。

在switch中使用枚举常量时,不必再每个标签中指明枚举名

没有goto语句,但是有带标签的break。

break_tag:
//break标签需要紧跟一个循环语句
for(int i = 0; i<10; i++){
    System.out.println("break_tag");
    break break_tag;
}
//break之后会跳过该循环,正常执行下面的代码
for(int i = 0; i<2; i++){
    System.out.println("other loop");
}
System.out.println("Break Successfully");
//result:
//	break_tag
//	other loop
//	other loop
//	Break Successfully

break_tag:
//break标签需要紧跟一个循环语句
for(int i = 0; i<2; i++){
    System.out.println("break_tag");

}
//break之后会跳过该循环,正常执行下面的代码
for(int i = 0; i<2; i++){
    System.out.println("other loop");
    break break_tag;
    //而这样会报错:未定义的标签: break_tag
    //所以说使用标签只能在它紧挨着的loop下
}
System.out.println("Break Successfully");

也有带标签的continue语句,但是本书的作者不喜欢使用switch语句,break和continue语句。

3.9大数

BigInteger 和 BigDecimal类可以实现任意精度的整数和浮点数运算

不能用+,-等处理大数,而需要使用大数类的add,mutiply方法

可以使用ValueOf方法快速转换为大数。

BigInteger a = BigInteger.valueOf(10000000);
BigInteger b = new BigInteger("100000000000000");//注意这里使用字符串来构造
BigInteger c = a.add(b);
System.out.println(c);

Java中没有运算符重载功能

compareTo方法,比较,返回int,前者大返回正数,相等返回0,后者大返回负数

具体的使用参见api文档

3.10数组

声明和创建是分开的。数组声明时长度可以为变量,但在声明过后长度就不变。

int[] a;
int a[];
//都是可以的,但是推荐使用第一种,它将类型和变量名清晰的分开
//还可以声明一个匿名数组
smallPrimes = new int[] {1,2,4,5};
//same to:
int[] anonymous = {1,2,4,5};
samllPrimes = anonymous;

foreach循环 for(variable : collection) statement

foreach循环最大的好处是简洁和自动对下标的控制。但是灵活性没传统的for循环更高。

int[] a = new int[10];//默认全为0
int[] b = a;//地址传递,b会影响a
b[0]= 10;
System.out.println(a[0]);
int[] c = Arrays.copyOf(a,a.length);//重新开辟内存,c不会影响a
c[1] = 11;
System.out.println(a[1]);
//result:10 0

与c++相比,数组更多的是等同于指针

int[] a = new int[100];//java
int * a = new int[100];//c++

在Java应用程序的main函数中,程序名并没有存储在args数组中

java Message -h world
//args[0]是-h,而不是world

可以用Arrays的sort方法进行排序

Math.random()方法返回【0,1)直接的随机浮点数

程序清单3-7中提供了一种不重复随机抽取的方案:

用n记录被抽取的数组大小,使用 (int)n*Math.random()获得抽取的下标r,然后再用数组中最后一个值去覆盖r对于的值。最后n自减,进行下一次抽取。

Arrays的一些常用方法

Static String toString(xxx[] a)//返回包含a中元素的字符串
static xxx[] copyOf(xxx[] a,int length)
static xxx[] copyOfRange(xxx[] a,int start,int end)//返回与a类型相同的数组,长度为length或者end-start
static void sort[xxx[] a]//用优化过的快排对a进行排序
static int binarySearch(xxx[] a, xxx v)
static int binarySearch(xxx[] a, int start, int end, xxx v)//用二分法对v进行查找,找到返回相应的下标,未找到返回一个负数值
static void fill(xxx[] a, xxx v)//将数组所以的数据元素设置为v
static boolean equals(xxx[] a, xxx[] b)//比较,只有长度和每一个对应的值都相同才返回true

二维数组

foreach循环不能自动处理二维数组的每一个元素,而是循环处理行。

可以调用Arrays的deepToString方法快速打印二位数组。

本质上二维数组是数组的数组,所以可以对数组的行进行操作

int[][] a = {
    {1,2,3,4},
    {5,6,7,8},
    {9,10,11,12},
    {13,14,15,16}
};
int[] temp = new int[4];
temp  = a[0];
a[0] = a[1];
a[1] = temp;
System.out.println(Arrays.deepToString(a));
//result is [[5, 6, 7, 8], [1, 2, 3, 4], [9, 10, 11, 12], [13, 14, 15, 16]]

还可以构建一个不规则数组

//Java竟然允许不指明列数
int[][] odds = new int[4][];
for(int n = 0; n < 4; n++){
    odds[n] = new int[n+1];
}
for(int i = 0; i < odds.length; i++){
    for(int j = 0; j < odds[i].length ; j++){
        odds[i][j] = i+j;
    }
}
System.out.println(Arrays.deepToString(odds));
//result is [[0], [1, 2], [2, 3, 4], [3, 4, 5, 6]]
//芜湖!Java真是太有趣了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值