1. Java “ 白皮书 ” 的关键术语
1 ) 简单性 2 ) 面向对象 3 ) 分布式 4 ) 健壮性 5 ) 安全性 6 ) 体系结构中立 7 ) 可移植性 8 ) 解释型 9 ) 高性能 10 ) 多线程 11 ) 动态性
2. Java 的基本程序设计结构
一个简单的 Java 应用程序
public class Main {
public static void main(String[] args) {
System.out.println("hello world!");
}
}
- Java区分大小写
- 关键字 public 称为访问修饰符 ( access modifier ) ,这些修饰符用于控制程序的其他部分对这段代码的访问级別
- 根据 Java 语言规范 , main 方法必须声明为 public
- Java 中的所有函数都属于某个类的方法 ( 标准术语将其称为方法,而不是成员函数 )。 因此 , Java中的 main 方法必须有一个外壳类 。
- Java 中的 main 方法必须是静态的 。
- Java main函数没有返回值,所以是void
Java 使用的通用语法是 object.method ( parameters ),这等价于函数调用。
访问控制修饰符
Java提供了许多访问修饰符来设置类,变量,方法和构造函数的访问级别。 四个访问级别是 -
对包可见(
default
),不需要修饰符。- 仅对类可见(
private
)。 - 对所有可见(
public
)。 - 对包和所有子类可见(
protected
)。
注释
- // is this too cute ?
- 使用 / 和 /
- 自动地生成文档。 这种注释以 / 开始 , 以 * / 结束。
数据类型
Java有8种基本类型(primitive type):
4 种整型:
- int 4字节
- short 2字节
- long 8字节
- byte 1字节
注意:
其中:长整型数值有一个后缀 L 或 l ( 如 4000000000 L ) 。 十六进制数值有一个前缀 0x 或 0X ( 如OxCAFEL 八进制有一个前缀0,例如,010 对应八进制中的8。
从java 7开始,可以加上前缀 0b 或 0B 就可以写二进制数。 例如 , 0b1001就是 9。
从java 7开始,可以为数字字面量加下划线, 如用1000_000 ( 或0b1111_0100 0010_0100_0000 )表示一百万,这些下划线只是为了让人更易读 。 Java编译器会去除这些下划线。
在C和C++中,int 和 long 等类型的大小与目标平台相关。而在Java 中,所有的数值类型所占据的字节数量与平台无关。
Java 没有任何无符号(unsigned)形式的int、long 、short或 byte 类型 。
Java 有一个能够表示任意精度的算术包,通常称为“大数值 ”( big number )。他不是一个新的数据类型,是一个对象
2 种浮点型:
- float 4字节
- double 8字节
注意:
float类型的数值有一个后缀F或f(例如,3.14F)。 没有后缀F的浮点数值(如 3.14) 默认为 double 类型。当然 ,也可以在浮点数值后面添加后缀D或d(例如3.14D)。
可以使用十六进制表示浮点数值。
常量Double_POSITIVE_INFINITY、Double.NEGATIVE_INFINITY和Double.NaN( 以及相应的 Float 类型的常量 ) 分别表示正无穷大,负无穷大和NaN
一 正整数除以 0 的结果为正无穷大。计算0/0或者负数的平方根结果为NaN
if(Double.NaN(x)) // 这个结果永远不是true,所以不能判断x是否为一个数字
if(Double.isNaN(x)) // 可以判断x是否为一个数字
但在实际应用中很少遇到 。
1 种字符类型:char
注意:
char类型原本用于表示单个字符。不过 ,现在情况已经有所变化。如今,有些 Unicode字符可以用一个char值描述,另外一些Unicode字符则需要两个char值。
char 类型的值可以表示为十六进制值,其范围从\u0000到\Uffff,也可以用ascii码表示,如char ch = 65, ch表示’A’
在 Java 中,char 类型描述了UTF-16编码中的一个代码单元。
1 表示真值的类型:boolean
注意:
在C++中数值甚至指针可以代替 boolean值。值0相当于布尔值 false,非0值相当于布尔值true,在 Java 中则不是这样(0和非0不能表示false和true)。
变量
可以在一行中声明多个变量,不过不提倡,因为逐一声明变量可以提高程序的可读性。
变量初始化
声明一个变量之后,必须用赋值语句对变量进行显式初始化, 千万不要使用未初始化的变量。
在C++和C中区分变量的声明和定义,Java中不区分。
类变量:
也是静态变量,
static int allClicks=0; // 类变量 独立于方法之外的变量,用 static 修饰。
int allClicks=0; //实例变量,没有用static修饰
static关键字
静态变量
如果将一个变量声明为static
,它就是所谓的静态变量了。
静态变量可以用于引用所有对象的公共属性(对于每个对象不是唯一的)。如:员工公司名称,学生所在的大学名称。
它能使程序存储器高效(即它节省内存)。
静态方法
如果在任何方法上应用static
关键字,此方法称为静态方法。
静态方法属于类,而不属于类的对象。
可以直接调用静态方法,而无需创建类的实例。
静态方法可以访问静态数据成员,并可以更改静态数据成员的值。
静态方法不能直接使用非静态数据成员或调用非静态方法。this
和super
两个关键字不能在静态上下文中使用。
Java静态块
Java中的静态块主要有两个作用:
- 用于初始化静态数据成员。
它在类加载时在main方法之前执行。
class A2 {
static {
System.out.println("static block is invoked");
}
public static void main(String args[]) {
System.out.println("Hello main");
}
}
为什么java main方法是静态的?
这是因为调用静态方法不需要创建对象,如果它是非静态方法,jvm首先要创建对象,然后调用main()方法,这将导致额外的内存分配的问题。常量
在 Java 中, 利用关键字 final 指示常量。
关键字 final 表示这个变量只能被赋值一次。一旦被赋值之后, 就不能够再更改了。习惯上,常量名使用全大写。
在 Java 中,经常希望某个常量可以在一个类中的多个方法中使用,通常将这些常量称为类常量。可以使用关键字static final设置一个类常量。 下面是使用类常量的示例:
而且, 如果一个常量被声明为 public, 那么其他类的方法也可以使用这个常量。
public class helloworld {
// 定义一个访问修饰符为public的类常量
// 其他类也可以访问他
public static final double PI = 3.14;
public static void main(String[] args){
// 定义一个普通常量
final double ridius = 3;
double area = ridius*ridius*PI;
System.out.println(area);
}
}
运算符
如果将一个类标记为strictfp , 这个类中的所有方法都要使用严格的浮点计算。
public static strictfp void main(String[] args){
// 定义一个普通常量
final double ridius = 3;
double area = ridius*ridius*PI;
System.out.println(area);
}
在默认情况下,虚拟机设计者允许对中间计算结果采用扩展的精度。因为对大多数程序来说,浮点溢出不属于大向题。
strictfp关键字
strictfp
关键字可以应用于方法,类和接口。
strictfp class A{}//strictfp applied on class
strictfp interface M{}//strictfp applied on interface
class B{
strictfp void m(){}//strictfp applied on method
}
strictfp
关键字不能应用于抽象方法,变量或构造函数。
class B{
strictfp abstract void m();//Illegal combination of modifiers
}
class B1{
strictfp int data=10;//modifier strictfp not allowed here
}
class B2{
strictfp B(){}//modifier strictfp not allowed here
}
数学函数与常量
在 Math 类中, 包含了各种各样的数学函数 。
Math中大部分方法是静态方法,直接用类名调用
double x = 4 ;
double y = Math.sqrt(x);
import java.lang.Math.*;
// 主要功能
Math.
Math.E,PI
Math.abs()
Math.pow()
Math.sqrt()
Math.cbrt()// 立方根
Math.max()
Math.min()
Math.exp()
Math.log()
Math.log10()
Math.Random()
Math.round() // 四舍五入
Math.ceil() // 天花板的意思,就是逢余进一(向上取整)
Math.floor() // 地板的意思,就是逢余舍一(向下取整)
Math.floorMod() // 为取模(mod),与a%b取余相反
Math.rint() // 四舍五入,返回最接近的整数。 注意如果存在两个这样的整数,则返回其中的偶数;
三角函数
Math.sin()
Math.cos()
Math.tan()
Math.atan()
Math.atan2()
如果不想在前面加Math,可以用静态导入(第四章会讲)
import static java.lang.Math.*;
double x = sqrt(4) // x为2
数值类型之间的转换
对于两个不同的数据类型,是先自动转换再计算。
低精度的向高精度的转换:
- 如果两个操作数中有一个是 double 类型, 另一个操作数就会转换为 double 类型。
- 否则, 如果其中一个操作数是 float 类型, 另一个操作数将会转换为 float 类型。
- 否则, 如果其中一个操作数是 long 类型, 另一个操作数将会转换为 long 类型。
- 否则, 两个操作数都将被转换为 int 类型。
下图实线转换没有信息丢失,虚线可能有信息丢失(精度不同)。
强制类型转换
如果试图将一个数值从一种类型强制转换为另一种类型, 而又超出了目标类型的表示范围, 结果就会截断成一个完全不同的值。 例如(byte) 300 的实际值为44。
对于浮点数,强制类型转换通过截断小数部分将浮点值转换为整型。
如果想对浮点数进行舍入运算, 以便得到最接近的整数。那就需要使用 Math.round()方法
double x = 9.8765;
int nx1 = (int)x;//nx1为9
int nx2 = (int)Math.round(x);//nx2为10
int a = b?1:0 // boolean转数值类型
结合赋值和运算符
Java中也可以使用自增(i++,++i)和自减(—i,i—)也可简便运算,如x += 2;
注意:
如果运算符得到一个值, 类型与左侧操作数的类型不同, 就会发生强制类型转换。 例如, 如果x是一个 int, 则以下语句
x += 3.5;
是合法的, 将把x设置为 (int)(x+3.5)。
关系和 boolean 运算符
关系
关系运算符和c++一样:
>、<、==、>=、<=、&&、||、a?b:c
位运算符(和c++一样)
包括:&(“and”)、 |(“or”) 、 ^(“xor”)、 ~(“not”)、 <<(“左移”)、 >>(“右移”)、 >>>(“用 0 填充高位”)
>>>和>>不同,>>会用符号位填充高位。
在 C / C ++ 中 , 不能保证 >> 是完成算术移位 ( 扩展符号位 ) 还是逻辑移位 ( 填充 0 )。 实现者可以选择其中更高效的任何一种做法 。 这意味着 C / C + + >> 运算符对于负数生成的结果可能会依赖于具体的实现。 Java则消除了这种不确定性
位运算应用在布尔值上时 , & 和丨运算符也会得到一个布尔值 。 这些运算符与&& 和||运
算符很类似, 不过 &和丨运算符不采用 “短路 ” 方式来求值,也就是说, 得到计算结果之前两个操作数都需要计算。
括号与运算符
java中没有c/c++中的逗号运算符,但是可以在 for 语句的第 1 和第 3 部分中使用逗号分d隔表达式列表 。
枚举类型
enum Size {EXTRA_LARGE, LARGER, MEDIUM, SMALL}
public static void main(String[] args) {
Size s = Size.MEDIUM;
System.out.println(s);
}
字符串
从概念上讲, Java 字符串就是 Unicode 字符序列 。
String s = ""; // 空串
String str = "hello";
子串(str.substring)
String str = "hello";
String subStr1 = str.substring(0,3); // str.substring(begin,end) subStr1=="hel"
String subStr2 = str.substring(1); // str,substring(begin) subStr2=="ello"
拼接(+和str.join)
String str1="hello";
String str2="world";
String str3=str1+" "+str2+"!"; // str3="hello world!"
当将一个字符串与一个非字符串的值进行拼接时,后者会转换成字符串
int age = 13;
String rating = "PG" + age;
// rating为 "PG13"
String静态 join 方法
String all = String.join("/","a","b","c");//将第一个字符串插入后面所有的字符串两两之间 第一个参数delimiter(定界符)
System.out.println(all); // all == "a/b/c"
Java11还提供了一个 repeat 方法(重复)
String repeated = "Java".repeat(3);// repeated为 "JavaJavaJava"
不可变字符串
String 类没有提供用于修改字符串的方法。如果希望将 greeting=”hello” 的内容修改为 “Help!” ,不能直接地将 greeting 的最后两个位置的字符修改为”p”和”!”。
修改时可以用下列代码
String greeting="hello";
greeting = greeting.substring(0,3)+"p!";
char x= greeting.charAt(0);//charAt可以取出相应位置的字符
由于不能修改 Java 字符串中的字符 , 所以在 Java 文档中将 String 类对象称为不可变字符串 , 如同数字 3 永远是数字 3 — 样 , 字符串 “hello” 永远包含字符’h’、’e’、’l’、’l’、’o’,的代码单元序列, 而不能修改其中的任何一个字符。
当然 ,可以修改字符串变量 greeting, 让它引用另外一个字符串 , 这就如同可以将存放 3 的数值变量改成存放 4 一样。
不可变字符串却有一个优点 : 编译器可以让字符串共享
Java 的设计者认为共享带来的高效率远远胜过于提取 、 拼接字符串所带来的低效率。(因为有自动内存回收)
C++可以修改字符串。Java字符串不可以修改,但是可以修改字符串变量。修改后赋值给字符串变量。
检测字符串是否相等(equals方法)
String str1="hello";
String str2="heaaa";
String str3="HellO";
boolean x = str1.equals(str2); //equals方法检测两个字符串串是否相等(区分大小写)
boolean y = str1.equalsIgnoreCase(str3);//equalsIgnoreCase方法检测两个字符串串是否相等(不区分大小写)
boolean z = str1.equals("hello");
x==fasle;
y==true;
z==true;
一定不要使用 == 运算符检测两个字符串是否相等 ! 这个运算符只能够确定两个字串是否放置在同一个位置上 。
当然,如果位置相同,两个字符串肯定相同,但完全有可能将内容相同的多个字符串的拷贝放置在不同的位置上。”==”让本该是true的判断变为false。
compareTo ( String other )方法
按照字典顺序, 如果字符串位于 other 之前,返回一个负数;如果字符串位于other 之后,返回一个正数;如果两个字符串相等,返回0。和c语言的strcmp()一样
空串和Null串
空串 “” 是长度为 0 的字符串。 可以调用以下代码检查一个字符串是否为空:
String str1="";
if(str1=="")//true
System.out.println("这可以判断空串");
if(str1.length()==0)//true
System.out.println("这也可以判断空串");
空串是一个 Java 对象 , 有自己的串长度( 0 ) 和内容( 空 )。
String变量还可以存放一个特殊的值 ,名为 null , 这表示目前没有任何对象与该变量关联。
判断字符串既不是空串也不是null
if(str1!=null&&str1.length()!=0)
System.out.println("这可以判断字符串既不是空串也不是null");
码点和代码单元
Java 字符串由 char 值序列组成。char 数据类型是一个采用 UTF-16 编码表示 Unicode 码点的代码单元。 大多数的常用 Unicode 字符使用一个代码单元就可以表示,而辅助字符需要一对代码单元表示。
String str="hello";
// length方法将返回采用UTF-16编码表示的给定字符串所需要的代码单元数量
int len1 = str.length();
// codePointCount方法返回实际的长度, 即码点数量
int len2 = str.codePointCount(0,str.length());
// 调用str.charAt(n)将返回位置n的代码单元
char x = str.charAt(0); // x=='h'
// 要想得到第i个码点,应该使用下列语句
// 其中offsetByCodePoints第一个参数为,第二个参数为
int index = str.offsetByCodePoints(0,1);
int cp = str.codePointAt(index);
String API
Java 中的 String 类包含了 50 多个方法。 令人惊讶的是绝大多数都很有用 ,可以设想使用的频繁非常高。下面的API 注释汇总了一部分最常用的方法 。
构建字符串
如果需要用许多小段的字符串构建一个字符串,那么应该按照下列步骤进行。
// 首先,构建一个空的字符串构建器
StringBuffer builder = new StringBuffer();
// 当每次需要添加一部分内容时,就调用 append 方法。
builder.append('a');// 添加单个字符
builder.append("bcd");// 添加字符串
// 在需要构建字符串时就凋用 toString 方法,将可以得到一个 String 对象,其中包含了构建器中的字符序列。
String str = builder.toString();
System.out.println(str);//输出abcd
字符串构建器API:
StringBuilder ()
构造一个空的字符串构建器
int length ( )
返回构建器或缓冲器中的代码单元数量
StringBuilder append( String str )
追加一个字符串并返回 this
StringBuilder append( char c )
追加一个代码单元并返回 this
StringBuilder appendCodePoint( int cp )
追加一个代码点, 并将其转换为一个或两个代码单元并返回 this 。
void setCharAt ( int i , char c )
将第 i 个代码单元设置为 c
StringBuilder insert ( int offset , String str )
在 offset 位置插入一个字符串并返回 this
StringBuilder insert ( int offset , Char c )
在 offset 位置插入一个代码单元并返回 this
StringBuilder delete ( int startindex , int endlndex )
删除偏移量从 startindex 到 endlndex - 1 的代码单元并返回 this
String toString ( )
返回一个与构建器或缓冲器内容相同的字符串
输入输出
读取输入
要想通过控制台进行输人,首先需要构造一个 Scanner 对象,并与”标准输人流”System.in 关联。
示例:
import java.util.Scanner;
public class helloworld {
public static void main(String[] args){
Scanner in = new Scanner(System.in);
System.out.println("请输入一句话:");
// 读取输入的下一行内容。
String name = in.nextLine();
System.out.println(name);
System.out.println("请输入一个单词:");
// 读取输入的下一个单词(以空格作为分隔符)。
String grade = in.next();
System.out.println(grade);
System.out.println("请输入一个整数:");
// 读取一个整数
int age = in.nextInt();
System.out.println(age);
System.out.println("请输入一个double浮点数:");
// 读取一个浮点数。
double price = in.nextDouble();
System.out.println(price);
System.out.println("别忘了加 import java.util.Scanner;");
// 下面的如果输入1.0的话
// 检测输人中是否还有其他单词。
boolean hn = in.hasNext();
System.out.println(hn); // true
// 检测是否还有表示整数或浮点数的下一个字符序列。
boolean hni = in.hasNextInt();
System.out.println(hni); // false
boolean hnd = in.hasNextDouble();
System.out.println(hnd); // true
}
}
因为输入是可见的, 所以 Scanner 类不适用于从控制台读取密码。Java SE 6 特别引入了 Console 类实现这个目的。要想读取一个密码, 可以采用下列代码:
Console cons = System.console();
String username = cons.readLine("User name: ");
char [] passwd = cons.readPassword("Password: ");
采用 Console 对象处理输入不如采用 Scanner 方便。每次只能读取一行输入, 而没有能够读取一个单词或一个数值的方法。
格式化输出(这些转换符string.format都可以用)
Java SE 5.0 沿用了 C 语言库函数中的 printf方法
如:
double x=10.0/3;
System.out.printf("%.8f",x);
// 输出3.33333333
String name = "龚万福";
int age = 20;
System.out.printf("hello %s,Next year, you'll be %d ",name,age);
// 输出hello 龚万福,Next year, you'll be 20
另外,还可以给出控制格式化输出的各种标志。 表 3-6 列出了所有的标志。 例如,逗号标志增加了分组的分隔符。 即
System.out.printf("%,.2f",10000.00/3);
// 输出 3,333.33
可以使用多个标志, 例如,”%,(.2f” 使用分组的分隔符并将负数括在括号内。
System.out.printf("%,(.2f",-10000.00/3);
// 输出 (3,333.33) 而不是-3.333.33
可以使用静态的 String.format 方法创建一个格式化的字符串, 而不打印输出:
String name = "龚万福";
int age = 20;
String message = String.format("Hello, %s. Next year , you'll be %d", name, age) ;
System.out.println(message); // 输出 Hello, 龚万福. Next year , you'll be 20
(1)日期和时间字符串格式化
eg:
Date date=new Date();
String year=String.format("%tY", date);
String month=String.format("%tB", date);
String day=String.format("%td", date);
System.out.println(year);//2018
System.out.println(month);//五月
System.out.println(day);//29
时间格式化:
格式包括两个字母, 以 t 开始, 以表 3-7 中的任意字母结束。 (也是printf)
如:
System.out.printf("%tc",new Date());
// 打印当前的全部时间
// 周三 11月 25 19:23:19 CST 2020
格式化常见的日期时间组合:
%tF “年-月-日”
%tD “月/日/年”
%tc 全部日期和时间
%tr “时:分:秒 AM(PM)”(12小时)
%tT “时:分:秒”(24小时)
%tR “时:分”(24小时)
文件输入与输出
读取
要想对文件进行读取, 就需要一个用 File 对象构造一个 Scanner 对象(要加throws IOException异常处理), 如下所示:
// 将数据d读出Myfile.txt
// 构造File对象
File file = new File("D:\\Myfile.txt");
Scanner in = new Scanner(file, "UTF-8") ;
// 读出一句
String s = in.nextLine();
System.out.println(s);
如果文件名中包含反斜杠符号,就要记住在每个反斜杠之前再加一个额外的反斜杠:“ c:\mydirectory\myfile.txt”
写入
要想写入文件, 就需要构造一个 PrintWriter 对象。在构造器中,只需要提供文件名:
// 加入异常处理,防止报错
public static void main(String[] args) throws IOException
{
// 将数据写入Myfile.txt
PrintWriter out = new PrintWriter("Myfile.txt","utf-8") ;
out.println("test");
out.close();
}
如果文件不存在,创建该文件。
可以像输出到 System.out—样使用 print、 println 以及 printf命令
// 构造一个从给定文件读取数据的 Scanner 。
Scanner(File file);
// 构造一个从给定字符串读取数据的 Scanner。
Scanner(String data);
// 构造一个将数据写入文件的 PrintWriter。 文件名由参数指定。
PrintWriter(String fileName);
// 根据给定的路径名构造一个 Path。
static Path get(String pathname);
控制流程
和C++一样
大数值
如果基本的整数和浮点数精度不能够满足需求, 那么可以使用java.math包中的两个很有用的类: BigInteger和BigDecimal。 这两个类可以处理包含任意长度数字序列的数值。 BigInteger类实现了任意精度的整数运算, BigDecimal实现了任意精度的浮点数运算。
BigInteger
import java.math.BigInteger;
// static BigInteger.valueOf(1ong x)
// 将普通的数值转换为大数值,返回值等于 x 的大整数。
BigInteger x = BigInteger.valueOf(2);
// BigInteger add(BigInteger other)
// 大数加法 2 + 5
BigInteger y = x.add(BigInteger.valueOf(5));
System.out.println(y); // y==7
// BigInteger subtract(BigInteger other)
// 大数减法 7 - 2
BigInteger z = y.subtract(x);
System.out.println(z); // z==5
// BigInteger multiply(BigInteger other)
// 大数乘法 7 * 2
z = y.multiply(x);
System.out.println(z); // z==14
// BigInteger divide(BigInteger other)
// 大数除法 7 / 2
z = y.divide(x);
System.out.println(z); // z==3
// BigInteger mod(BigInteger other)
// 大数取模 7%2
z = y.mod(x);
System.out.println(z); // z==1
// int compareTo(BigInteger other)
// 大数比较大小 7 > 2
// 如果这个大整数与另一个大整数 other 相等, 返回 0; 如果这个大整数小于另一个大整
// 数 other, 返回负数; 否则, 返回正数。
int a = y.compareTo(x);
System.out.println(a); // a>0
BigDecimal
import java.math.BigDecimal;
// static BigDecimal.valueOf(1ong x)
// 返回值为 x
BigDecimal x = BigDecimal.valueOf(2);
// static BigDecimal valueOf(1 ong x ,int scale)
// 返回值为 x / 10^scale 的一个大实数。
BigDecimal b = BigDecimal.valueOf(1,2); // 1/10^2==0.01
System.out.println(b); // b==0.01
// BigDecimal add(BigDecimal other)
BigDecimal y = x.add(BigDecimal.valueOf(5));
System.out.println(y); // y==7
// BigDecimal subtract(BigDecimal other)
// 大数减法 7 - 2
BigDecimal z = y.subtract(x);
System.out.println(z); // z==5
// BigDecimal multiply(BigDecimal other)
// 大数乘法 7 * 2
z = y.multiply(x);
System.out.println(z); // z==14
// 要想计算商, 必须给出舍
// 入方式 ( rounding mode。) RoundingMode.HALF UP 是在学校中学习的四舍五入方式
// ( BP , 数值 0 到 4 舍去, 数值 5 到 9 进位)。它适用于常规的计算。有关其他的舍入方
// 式请参看 Apr文档。
// BigDecimal divide(BigDecimal other)
// 大数除法 7 / 2
z = y.divide(x);
System.out.println(z); // z==3.5
// int compareTo(BigDecimal other)
// 如果这个大实数与另一个大实数相等, 返回 0 ; 如果这个大实数小于另一个大实数,
// 返回负数; 否则,返回正数。
// 大数比较大小 7 > 2
int a = y.compareTo(x);
System.out.println(a); // a>0
数组
在声明数组变量时, 需要指出数组类型( 数据元素类型紧跟[]) 和数组变量的名字。 下面声明了整型数组a:
int[] a;
// 或者
int a[];
一般用第一种,因为它将类型 int[] ( 整型数组)与变量名分开了。
不过, 这条语句只声明了变量a, 并没有将a初始化为一个真正的数组。 应该使用new运算符创建数组。
int [] a = new int[100]; //长度可以不是常量,如int [] a = new int[n];也可以
foreach循环
Java有一种功能很强的循环结构, 可以用来依次处理数组中的每个元素( 其他类型的元素集合亦可) 而不必为指定下标值而分心。这种增强的for循环的语句格式为:
for(variable : collection)
statement
定义一个变量用于暂存集合中的每一个元素, 并执行相应的语句( 当然, 也可以是语句块) 。 collection这一集合表达式必须是一个数组或者是一个实现了Iterable接口的类对象( 例如ArrayList) 。
int a[] = {5,4,3,2,1};
for(int item : a){
System.out.println(item);//输出5 4 3 2 1
}
这个方法显得更加简洁、 更不易出错(不必为下标的起始值和终止值而操心。)
数组初始化以及匿名数组
在Java中, 提供了一种创建数组对象并同时赋予初始值的简化书写形式。 下面是一个例子:
int a[] = {5,4,3,2,1}; // 不需要用nuw
甚至还可以初始化一个匿名的数组:
new int[] {5,4,3,2,1}; // 数组的大小就是初始化的个数
使用这种语法形式可以在不创建新变量的情况下重新初始化一个数组。 例如:
a = new int[] {2,3,4,5,6};
等价于下面
int[] b = {2,3,4,5,6};
a = b;
在Java种允许长度为0的数组,长度为0和NULL不同
int[] a = new int[0];
一维数组总结:
// 声明一个数组
int[] intArray0 ;
int intArray1 [];
// 分配空间有三种方法,牢记,熟练掌握:
scores=new int[5]
int scores[]=new int[5]// 声明并分配空间
int scores[]={71,82,75,98,65}// 直接给初始化值
// 定义一个数组,保存五名学生的成绩
int[] scores = { 78, 93, 97, 84, 63 };
// 等价于
int[] scores = new int []{ 78, 93, 97, 84, 63 };
数组拷贝
在 Java 中, 允许将一个数组变量拷贝给另一个数组变量。这时, 两个变量将引用同个数组。和C语言的地址类似。
int[] b = {1,2,3,4,6,7};
int [] a = b;
a[5] = 12;
System.out.println(b[5]); // b[5]也是12
Arrays类的copyOf方法
int[] b = {1,2,3,4,5,6,7};
int[] copyb = Arrays.copyOf(b,b.length); // 第二个为复制长度,当长度小于b.length时直接截断,
// 当长度大于b.length时,如果b是bool,则增加的元素都为false
// 如果是数值型,则增加的赋值为0
for(int item : copyb){
System.out.println(item); // 1 2 3 4 5 6 7
}
// 这个方法通常用来增加数组的大小
b = Arrays.copyOf(b,2*b.length);
for(int item : b){
System.out.println(item);// 1 2 3 4 5 6 7 0 0 0 0 0 0 0
}
命令行参数
和c++命令行参数类似
public static void main(String[] args) {
if(args.length==0||args[0].equals("-h")){
System.out.println("hello,");
}else if(args[0].equals("-g")){
System.out.println("Goodbye,");
}
for(int i=1;i<args.length;i++)
System.out.println(" "+args[i]);
System.out.println("!");
}
// java Message -g cruel world 命令行运行后
// args 数组将包含下列内容:
// args[0]:"-g"
// args[l]:"cruel"
// args[2]:"world"
这个程序将显示下列信息:
Goodbye, cruel world!
注意args[0]是"-g",不是"Message"
数组排序
Arrays.sort()方法快速排序
int [] a = {6,5,2,7,1,9};
Arrays.sort(a);
for(int item : a){
System.out.println(item);
}
Arrays的方法
static String toString(type[] a)
// 返回包含 a 中数据元素的字符串, 这些数据元素被放在括号内, 并用逗号分隔。
// 参数: a 类型为 int、long、short、char、 byte、boolean、float 或 double 的数组。
static type copyOf(type[] a, int length)
static type copyOfRange(type[] a , int start , int end)
// 返回与 a 类型相同的一个数组, 其长度为 length 或者 end-start, 数组元素为 a 的值。
// 参数:a 类型为 int、 long、short、char、byte、boolean、float 或 double 的数组。
// start 起始下标(包含这个值)0
// end 终止下标(不包含这个值)。 这个值可能大于 a.length。 在这种情况
// 下,结果为 0 或 false。
// length 拷贝的数据元素长度。 如果 length 值大于 a.length, 结果为 0 或 false ;
// 否则, 数组中只有前面 length 个数据元素的拷贝值。
static void sort(type[] a)
// 采用优化的快速排序算法对数组进行排序
// 参数:a 类型为 int、long、short、char、byte、boolean、float 或 double 的数组。
static int binarySearch(type[] a, type v)
static int binarySearch(type[] a, int start, int end , type v)
// 采用二分搜索算法查找值 v。如果查找成功, 则返回相应的下标值; 否则, 返回一个
// 负数值 r 。 -r-1 是为保持 a 有序 v 应插入的位置。
// 参数: a 类型为 int、 long、 short、 char、 byte、 boolean 、 float 或 double 的有
// 序数组。
// start 起始下标(包含这个值)。
// end 终止下标(不包含这个值。)
// v 同 a 的数据元素类型相同的值。
static void fi11(type[] a , type v)
// 将数组的所有数据元素值设置为 V。
static boolean equals(type[] a, type[] b)
// 如果两个数组大小相同, 并且下标相同的元素都对应相等, 返回 true。
多维数组
声明二维数组
int [][] a;
与一维数组一样, 在调用 new 对多维数组进行初始化之前不能使用它。
初始化
a = new int[5][5];
另外, 如果知道数组元素, 就可以不调用 new, 而直接使用简化的书写形式对多维数组
进行初始化。例如:
int [][] a =
{
{6,5,2,7,1,9},
{0,1,2,3,4,5}
};
多维数组中的foreach
int [][] a =
{
{6,5,2,7,1,9},
{0,1,2,3,4,5}
};
for(int[] items : a)
for (int item : items){
System.out.println(item);
}
public static void main(String[] args) {
int [][] a =
{
{6,5,2,7,1,9},
{0,1,2,3,4,5}
};
System.out.println(Arrays.deepToString(a));// 快速地打印一个二维数组的数据元素列表
// [[6, 5, 2, 7, 1, 9], [0, 1, 2, 3, 4, 5]]
}
二维数组总结
// 声明一个数组
int[][] intArray0 ;
int intArray1 [][];
// 分配空间
a=new int[2][4];
// 初始化
int myarr[][]={{12,0},{45,10}};//声明并分配空间
Java 实际上没有多维数组, 只有一维数组。 多维数组被解释为“ 数组的数组。”
不规则数组
数组两行交换
double[] temp = balances[i]; // temp存储一列数组
balances[i] = balances[i + 1];
balances[i + 1] = temp;
构造一个“ 不规则” 数组, 即数组的每一行有不同的长度。
下面是一个典型的示例。 在这个示例中, 创建一个数组, 第i行第j列将存放“从i个数值中抽取j个数值” 产生的结果。
public static void main(String[] args) {
int NMAX=5;
int [][] odds = new int[NMAX+1][];
for (int i =0;i<=NMAX;i++){
odds[i] = new int[i+1]; // 第一行为1个,第二行为2个,第三行为3个。。。。
}
int s = 0;
for(int i=0;i<odds.length;i++)
for(int j=0;j<odds[i].length;j++)
{
odds[i][j] = s++;
}
System.out.println(Arrays.deepToString(odds));
}