Java的特性:
- 简单性
- 面向对象!
- 分布式!
- 健壮性
- 安全性
- 体系结构中立
- 可移植性!
- 解释型!
- 高性能
- 多线程!
- 动态性
第二章 Java程序设计环境
JDK: 编写Java程序的程序员使用的软件,开发环境工具包
JRE:运行Java程序的用户使用的软件,运行环境
Standard Edition: SE,用于桌面或简单服务器应用的Java平台
EE:用于复杂服务器应用的Java平台
安装:库源文档和文档
库源文件在JDK中以一个压缩文件 src.zip 的形式发布 ,必须将其解压缩后才能够访问源代码 。建议按照下面所的步骤进行操作。
- 确保JDK已经安转,并且在jdk/bin目录中执行路径汇中
- 在主目录中建立一个目录 javasrc 如果愿意 可以在一个终端窗口完成这个步骤
mkdir javasrc
; - 在jdk目录中找到src.zip
- 将src.zip文件解压到javasrc中
1 | public class Welcome { |
编写Welcome.java文件;类型名注意大小写
1 | javac Welcome.java |
从命令行编译和运行一个 Java 程序
javac是一个java的编译器;将Welcome.java编译成Welcome.class;
java程序启动Java虚拟机;虚拟机执行编译器放在class文件的字节码
第三章 Java的基本程序设计结构
主要介绍 程序设计的基本概念(如数据类型,分支以及循环)
一个java demo
1 | public class FirstSample { |
- java区分大小分 main 不是Main!!
- 关键字 public 访问修饰符(access modifier);用于控制程序的其他部分对这段代码的访问级别
- 关键字class 表明Java程序中基本处理的单位是类,所有内容都在类中; class紧跟类名;名字必须字母开头,后跟字母和数字的组合。类名以大写字母开头,驼峰法;源代码命名必须与公共类同名!!
- 正确命名后,
javac FirstSample.java
编译这段代码得到一个包含这个类字节码的文件。Java编译器将字节码文件自动命名为FirstSample.class,同一目录下。 - 运行 java已编译程序
java FirstSample
; Java虚拟机将从指定类中的main方法开始执行(方法即java中的函数); Java 中的所有函數都属于某个类的方法 ( 标准术语将其称为方法而不是成员函数 )。因此 Java 中的 main 方法必须有一个外壳类。Java 中的 main 方法必须是静态的 最后关键字 void 表示这个方法没有返回值。如果 main 方法正常退出 , 那么 Java 应用程序的退出代码为 0,表示成功地运行了程序。如果希望在终止程序时返回其他的代码,那就需要调用System.exit方法 - 使用括号{} 来划分程序的各个部分;一对大括号表示方法体的开始与结束。
- 在上面这个 main 方法体中只包含了一条语句 其功能是 将一个文本行输出到控制台上;使用了 System . out 对象并调用了它的 println 方法。点号(.)用于调用方法。等价于函数调用。
object.methond(parameters)
数据类型
java是强类型语言;意味着必须为每个变量申明一种类型。共有8中基本类型;
- 4种整型(int 4字节 刚过20亿;short 2字节; long 8字节; byte 1字节-128-127);
- 2种浮点类型; float 4字节; double 8字节 !!!;
- 1种用于Unicode编码的字符单元的字符类型char; 单个字符,单引号括起来;
- 转义序列 \u; 从 \u0000 到\uffff; 转义序列 \ u 还可以出现在加引号的字符常量或字符串之外
public static void main(String\u005B\u005D args )
- 注释中 \u 替换成特殊字符; 回车,换行 最好将字符串作为抽象数据类型处理
- 转义序列 \u; 从 \u0000 到\uffff; 转义序列 \ u 还可以出现在加引号的字符常量或字符串之外
- 1种用于表示真值的boolean类型; false 或 true; 不能和整型转换
- 还有一个算术包, 大数值,是一个Java对象,不是类型
变量
java中, 每个变量都有一个类型(type);int i; double salary;变量的声明尽可能地靠近变量第一次使用的地方
$
是一个合法的Java字符,但不要用,只用在Java编译器中。
变量初始化: 声明变量, 初始化; int vacationDays = 12;
常量: 使用 final 表示常量。 final double PI = 3.14; 该变量只赋值一次,不能再次更改了。全部大写。const是保留字; 使用final 定义常量;希望某个常量在一个类中多个方法中使用,称为类常量。使用 static final设置一个类常量。 static final CM_PI = 3.14;
运算符
-; +; /; %; 整数被0产生异常;浮点数被除0得到无穷大或者NaN;
数学函数与常量
在Math类中;Math.sqrt(); print方法处理System.out对象;Math类中sqrt方法处理不是对象是静态方法。
double y = Math.pow(x, a);
floorMod 方法的目的是解决一个长期存在的有关整数余数的问题; 考虑表达式 n % 2 , 所有人都知道 , 如果 n 是偶数; 这个表达式为 0 ; 如果 n 是奇数 表达式则为 1 当然 除 非 n 是负数 如果 n 为负,表达式为-1.
数值类型之间的转换
经常需要将一种数值类型转换为另一种数值类型。图 3 - 1 给出了数值类型之间的合法转换
有 6 个实心箭头 , 表示无信息丢失的转换 ; 有 3 个虚箭头 , 表示可能有精度 损失的转换
强制类型转换
int 类型的值将会自动地转换为 double 类型。 double x = 9.997; int nx = (int) x;
x += 4;
(一般地 , 要把运算符放在 = 号左边 如 *= 或 %= )
1 | int m = 7 ; int n = 7 ; |
在表达式中,前缀形式会先完成加 1 ; 而后缀形式会使用变量原来的值; 单独使用没有区别。
位运算符
处理整型时,可以直接对组成整型数值的各个位完成操作
1 | &("and") 按位与运算符,无短路效果 |
枚举类型
可以自定义枚举类型 。
1 | enum Size { SMALL , MEDIUM , LARGE , EXTRA LARCE } ; |
字符串
注意:String 类是不可改变的,所以你一旦创建了 String 对象,那它的值就无法改变了。
从概念上讲,Java字符串是Unicode字符串序列。例如,”Java\u2122”由5个字符Unicode字符J、a、v、a和”TM”特殊字符。无内置字符串类型;在类库中提供预定义类,叫String。 每个用双引号括起来的字符串都是Strin类的一个实例。
子串,String类中的substring方法可以提取子串。[ );substring 的工作方式有一个优点 容易计算子串的长度 字符串 s . substring ( a , b ) 的长度为 b - a。子串 “ Hel ” 的长度为 3 - 0 = 3
拼接
允许使用+号连接 ( 拼接 ) 两个字符串。当将一个字符串与一个非字符串的值进行拼接时,后者被转换成字符串。
不可变字符串
String 类没有提供用于修改字符串的方法。如果希望将 greeting 的内容修改为 “ Help ! ”,不能直接地将 greeting 的最后两个位置的字符修改为’p’和!’. greeting = greeting.substring(0, 3)+”p!”;
由于不能修改 Java 字符串中的字符 ,所以在 Java 文档中将 String类对象称为不可变字符串. 如同数字 3 永远是数字 3一样, 字符串”hello”包含字符h,e,l,l,o代码单元序列,不能修改其中的任何一个字符。 可以修改字符串变量greeting,让他引用另外一个字符串。
看起来好像修改一个代码单元要比创建一个新字符串更 加简洁,对,也不对。通过拼接 “ Hel ” 和 p ! ” 来创建一个新字符串的效率确实不高。但是 ,不可变字符串却有一个优点 :编译器可以让字符串共享 。
为了弄清具体的工作方式,可以想象将各种字符串存放在公共的存储池中。字符串变量指向存储池中相应的位置,如果复制一个字符串变量,原始字符串与复制的字符串共享相同的字符。
Java 字符串大致类似于 char * 指针 ,不是认为是字符型数组;greeting = “ess”; 指向新串时,Java自动回收垃圾
检测字符串相等
使用equals方法; s.quals(t); 或 “Hello”.equals(s); 而不区分大小写 ,可以使用 equalsIgnoreCase方法
空串与NULL串
空串 “” 是长度为 0 的字符串;可以调用以下代码检查一个字符串是否为空 : if(str.length() == 0)或者if(str.equals(“”)); 空串是一个Java对象,有自己的串长度(0)和内容(空)。
String变量还可以存一个特殊的值,名为null,表示目前没有任何对象与该变量关联。if(str==null)
有时要检查一个字符串既不是null也不为空串,需要使用以下:
if(str != null && str.length() != 0) ; 在null值上调用方法,会出现错误。
码点与代码单元
码点 ( code point ) 是指与一个编码表中的某个字符对应的代码值。 在Unicode标准中,码点采用16进制书写,加上前缀U+,例如U+0041为拉丁字母A的码点。Unicode的码点可以分成17个代码级别。第一个代码级别,称为多语言级别,从U+0000到U+FFFF;其余从U+10000到U+10FFFF,包括辅助字符串;两个代码单元。
UTF 16 编码采用不同长度的编码表示所有 Unicode 码点。在基本的多语言级别中,每个字符用 16 位表示,称为代码单元,而辅助单元采用一对连续的代码单元进行编码。如八元数集。
char 类型描述了 UTF-16 编码中的一个代码单元。
Java 字符串由 char 值序列组成。从 3.3 . 3 节 “ char 类型 ” 已经看到,char数据类型是一个采用UTF - 16 编码表示 码点的代码单元。大多数的常用Unicode使用一个代码单元就可以表示,而辅助字符需要一对代码单元表示。length 方法将返回采用 UTF 16 编码表示的给定字符串所需要的代码单元数量 。
1 | public class StringTest { |
String API
String类中包含了50多个方法。都有用。
1 | java.lang.String |
1 | String a = "Hello World!"; |
首先String不属于8种基本数据类型,String是一个对象。
因为对象的默认值是null,所以String的默认值也是null;但它又是一种特殊的对象,有其它对象没有的一些特性。在这里,我们先不谈堆,也不谈栈,只先简单引入常量池这个简单的概念。
常量池(constant pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量。- Java会确保一个字符串常量只有一个拷贝。
因为例子中的a和b都是字符串常量,它们在编译期就被确定了,所以
a==b为true;而”Hello”和” “以及”World!”也都是字符串常量,当一个字符串由多个字符串常量连接而成时,它自己肯定也是字符串常量,所以d也同样在编译期就被解析为一个字符串常量,所以d也是常量池中”Hello World!”的一个引用。所以我们得出a==b==d;
用new String() 创建的字符串不是常量,不能在编译期就确定,所以new String()创建的字符串不放入常量池中,它们有自己的地址空间。
存在于.class文件中的常量池,在运行期被JVM装载,并且可以扩充。String的intern()方法就是扩充常量池的一个方法;当一个String实例str调用intern()方法时,Java查找常量池中是否有相同Unicode的字符串常量,如果有,则返回其的引用,如果没有,则在常量池中增加一个Unicode等于str的字符串并返回它的引用,看例3就清楚了。
1 | String a = "Hello"; |
String是不可变的 :
这一说又要说很多,大家只要知道String的实例一旦生成就不会再改变了,比如说:String str=”aa”+”bb”+” “+”cc”;
就是有4个字符串常量,首先”aa”和”bb”生成了”aabb”存在内存中,后”aabb”又和” “ 生成 ”aabb “存在内存中,最后又和生成了”aabb cc”,并把这个字符串的地址赋给了str,就是因为String的“不可变”产生了很多临时变量,这也就是为什么建议用StringBuffer的原因了
三、StringBuffer和StringBuiler
我们对String、StringBuffer、StringBuiler先有一个简单的认识。String是不可变字符串,StringBuffer和StringBuilder是长度可变的字符串,区别是前者是线程安全的,后者是线程不安全的,同样后者的效率也会更高。
StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。
例如,如果 z 引用一个当前内容为 “start” 的字符串缓冲区对象,则此方法调用 z.append(“le”) 会使字符串缓冲区包含 “startle”,而 z.insert(4, “le”) 将更改字符串缓冲区,使之包含 “starlet”。
通常,如果 sb 引用 StringBuilder 的一个实例,则 sb.append(x) 和 sb.insert(sb.length(), x) 具有相同的效果。
还有delete删除方法
deleteCharAt(int index)
delete(int start ,int end)
构建字符串
每次连接字符串,需要重新生成新的String对象,耗时,浪费空间。可以使用StringBuilder
如 许多小段字符串构建成一个字符串,
首先,构建一个空 的字符串构建器。
1 | StringBuilder builder = new String StringBuilder(); |
StringBuffer是线程安全的,而StringBuilder是非线程安全的。StringBuilder是从JDK 5开始,为StringBuffer类补充的一个单线程的等价类。我们在使用时应优先考虑使用StringBuilder,因为它支持StringBuffer的所有操作,但是因为它不执行同步,不会有线程安全带来额外的系统消耗,所以速度更快。
二、String为什么不可变
虽然String、StringBuffer和StringBuilder都是final类,它们生成的对象都是不可变的,而且它们内部也都是靠char数组实现的,但是不同之处在于,String类中定义的char数组是final的,而StringBuffer和StringBuilder都是继承自AbstractStringBuilder类,它们的内部实现都是靠这个父类完成的,而这个父类中定义的char数组只是一个普通是私有变量,可以用append追加。因为AbstractStringBuilder实现了Appendable接口。
1 | - StringBuilder() |
输入输出
读取输入
读取 标准输入流; System.in 主语是主机
1 | // 首先 构造一个Scanner 对象,并且与 "标准输入流" System.in关联 |
1 | import java.util.*; |
1 | // 用给定的输人流创建一个 Scanner 对象 |
格式化输出
可以使用System.out.print(x)
将数值 x 输出到控制台上
1 | System.out.printf("%8.2f", x); |
每一个以%字符开始的格式说明符都用相应的参数替换。格式说明符尾部的转换符将指示被 格式化的数值类型。f 表示浮点数;s 表示字符串;d表示十进制整数。还可以给出控制格式化输出的各种标志.
可以使用 s 转换符格式化任意的对象。对于任意现了 Formattable 接口的对象都 将调用 formatTo 方法 否则将调用 toString 方法 它可以将对象转换为字符串。
可以使用静态的String.format方法创建一个格式化的字符串,而不打印输出:
1 | String message = String.format("Hello, %s. Next Year you will be %d", name, age+1); |
文件输入与输出
想要对文件进行读写,需要一个File对象构造一个Scanner对象,如下:
1 | Scanner in = new Scanner(Paths.get("myfile.txt"),"UTF-8"); |
现在介绍前面的任何一个Scanner 方法对文件进行读写。
要想写文件,使用 PrintWriter对象。在构造器中,只需要提供文件名:
1 | PrintWriter out = new PrintWriter("myfile.txt", "UTF-8"); |
如文件不存在,则创建文件。
1 | - Scanner(File f) // 构造一个从给定文件读取数据的Scanner |
控制流程
使用条件 和循环语句。
块作用域
块(Block)概念: 复合语句,由一对大括号括起来的若干条简单的Java语句。确定变量的作用域,可嵌套,但嵌套的两个块中不能声明相同变量。C++可重定义一个变量。
条件/ 循环
1 | if (condition) { |
确定循环
for 循环语言, 迭代。
1 | for(int i = 0; i <= 10; i++) { |
for 语句的第 1 部分通常用于对计数器初始化;第 2 部分给出每次新一轮循环执行前要检测的循环条件; 第 3 部分指示如何更新计数器
大数值
基本的整数和浮点数精度不足,可使用java.math的两个类:BigInteger和BigDecimal。可处理包含任意长度数字序列的整数,浮点数。
使用静态的 valueOf 方法可以将普通的数值转换为大数值:
不能使用算术运算符(+和*)处理,需要使用大数值类中的add和multiply方法。
1 | BigInteger a = BigInteger.valueOf(100); |
Java中没有运算符重载的功能。不能重载/ *等运算符; Java只为字符串的连接重载了+运算符。
1 | BigInteger add(BigInteger other); |
数组
数组是一种数据结构,用来存储同一类型值的集合。通过以下整型下标可以方位数组中的每一个值。例如,a是一个整形数组,a[i]就是数组的中下标为i的整数。
创建整型数组,所有元素初始化为0;所有boolean初始化为false;对象数组为null
字符串长度用string.length(); 数组用array.length;
使用new和{}初始化数组
在声明数组变量时,需要指出数组类型(数据元素类型紧跟[])和数组变量名。
1 | int[] a; //该语句只声明了变量a,没有讲a初始化一个真正的数组,应使用new |
一旦创建了数组,就不能再改变大小了;如果要在运行过程中扩展数组大小。就应该使用另一种数据结构–数组列表。
1 | for each循环使用 //这个循环应该读作 “ 循环 a 中的每一个元素 ” ( for each element in a ) |
数组初始化以及匿名数组
在Java中,提供了一种创建数组对象并同时赋予初始化的简化书写形式;
1 | int[] smallPrimes = {1, 2,3, 4,5,6}; |
这种表示法将创建一个新数组并利用括号中提供的值进行初始化,数组的大小就是初始值的个数。使用这种语法形式可以在不创建新变量的情况下重新初始化一个数组。
数组拷贝
在 Java 中,允许将一个数组变量拷贝给另一个数组变量 这时 两个变量将引用同一个数组:
1 | int[] luckyNumbers = new int{1, 3,34}; |
数组排序
使用Arrays.sort(); Arrays的API使用。
多维数组
多维数组将使用多个下标访问数组元素, 适用于表示表格或更加复杂的排列形式
初始化方式一:
在 Java 中 声明一个二维数组相当简单,与一维数组一样,在调用new对多维数组进行初始化之前不能使用它,在这里可以这样初始化
1 | double[][] balances; |
初始化方式二:另外, 如果知道数组元素 就可以不调用 new, 而直接使用简化的书写形式对多维数组进行初始化 。
1 | int[][] magicSquare = { |
一旦数组初始化,可以利用balances[i][j]
访问
for each 不能自动处理二维数组的每一个元素,他是按照行处理,也是一维数组。需要使用嵌套循环。
1 | for (double[] row : a) { |
不规则数组
Java实际上没有多维数组。只有一维数组;多维数组可称为“数组的数组”。在前面的示例中, balances 数组实际上是一个包含10 个元素的数组 ,而每个元素又是一个由 6个浮点数组成的数组。
表达式 balances[i]引用第 i 个子数组,也就是二维表的第 i 行,它本身也是一个数组。由于可以单独地存取数组的某一行,所以可以让两行交换。还可以方便地构造一个不规则数组,即数组的每一行有不同的长度,下面是一个典
型的示例。