public class FirstExample{
public static void main(String[] args){
System.out.println("we will not use 'hello world' ");
}
}
从这个程序中,我们可以知道哪些?
1 java对大小写很敏感,main写成Main,程序无法执行
2 public访问修饰符,控制程序的其他部分对这段代码的访问级别
3 class表名java程序包含在类中,这里,只需要将类作为一个加载程序逻
辑的容器,程序逻辑定义了应用程序的行为。
4 class后面跟的是类名,命名规则:类名是以大写字母开头的名词。如果
名字由多个单词组成,每个单词的第一个字母都应该大写。其他等同于标
识符的命名规则。
5 文件名与公有类的类名一致,如FirstExample.java
6 每个java应用程序必须有一个main方法
7 {}方法体开始和结束。每个句子必须用‘;’结束,回车不是结束的标志,因此,可以将一条java语句写在多行上
8 System.out.println(),方法调用
9 “”引用字符串
10 方法可以没有参数,也可以有多个参数,但必须用()表示例如,不带
参数的println方法只打印一个空行。使用下面的语句:
System.out.println()
Note:
运行编译程序时, Java虚拟机将从指定类中的main方法开始执行(这里的“方法”就是Java中所说的“函数”),
因此为了代码能够执行,在类的源文件中必须包含一个main方法。当然,也可以将用户自定义的方法添加到类中,
并且在main方法中调用它们。
根据Java语言规范, main方法必须声明为public
Java的类与C++的类很相似,但还是有些差异会使人感到困惑。
例如, Java中的所有函数都属于某个类的方法(标准术语将其称为方法,而不是成员函数)。
因此, Java中的main方法必须有一个外壳类。读者有可能对C++中的静态成员函数( static member functions)十分熟悉。
这些成员函数定义在类的内部,并且不对对象进行操作。 Java中的main方法必须是静态的。
最后,C/C++一样,关键字void表示这个方法没有返回值,所不同的是main方法没有给操作系统返回“退出代码”。
如果main方法正常退出,那么Java应用程序的退出代码为0,表示成功地运行了程序。
如果希望在终止程序时返回其他的代码,那就需要调用System.exit方法。
与多数设计语言一样,java中的注释不会出现在可执行程序中。
注释类型:
单行://注释的内容
多行:/*注释的内容 */
另一种:/**注释的内容*/
Note:
在Java中, /* */注释不能嵌套。也就是说,如果代码本身包含了一个*/,就不能用/*和*/将注释括起来。
四种整型,两种浮点,一种char,一种Boolean
1 整型
类型 | 存储要求 | 取值范围 |
---|---|---|
int | 4字节 | -2 147 483 648~2 147 483 647(正好超过20亿) |
short | 2字节 | -32 768~32 767 |
long | 8字节 | -9 223 372 036 854 775 808~9 223 372 036 854 775 807 |
byte | 1字节 | -128~127 |
在java中,整型的取值范围固定,与平台无关,这就解决了移植性的问题,而c/c++需要针对不同的处理器选择最为有效的整型,会导致整数溢出问题
2 浮点型
类型 | 存储要求 | 取值范围 |
---|---|---|
float | 4字节 | 大约±3.402 823 47E+38F(有效位数为6~7位) |
double | 8字节 | 大约±1.797 693 134 862 315 70E+308(有效位数为15位) |
常量Double.POSITIVE_INFINITY、 Double.NEGATIVE_INFINITY和Double.NaN(与相应的Float类型的常量一样),例如:
一个正整数除以0的结果为正无穷大。计算0/0或者负数的平方根结果为NaN。
检测一个数是不是NaN,不能
if(x==Double.NaN)
//所有"非数值"的值都认为是不相同的。可以用Double.NaN(x)
if(Double.NaN(x))
3 char类型
记住以下几点:
1 ‘A’和“A”不同:前者是字符常量65,后者是包含字符A的字符串
2 在”和”“中可以假如转义字符,但只有\u可以不在内部,如\u005B和\u005D是(和)的编码。
3 java中采用的UTF-16描述一个代码单元
4 强烈建议不要在程序中使用char类型
4 boolean型
在C++中,数值或指针可以代替boolean值。整数0相当于布尔值false,非0值相当于布尔值true。在Java中则不行。
因此, Java应用程序员不会遇到下述麻烦:
if(x=0)//
在C++中这个测试可以编译运行,其结果总是false。而在Java中,这个测试将不
能通过编译,其原因是整数表达式x = 0不能转换为布尔值。
记住一下几点:
1 变量名区分大小写
2 在c/c++,区分变量定义和声明,如:
int i=10;//定义变量
extern int i;//声明一个变量
java中不做区分,可以直接写成:int i=10;//声明,定义,初始化
3 与变量对应的就是常量,用final声明,通常常量名使用大写,常量不能更改,如:
final int PI=3.14;
4 希望某个常量可以在一个类中的多个方法中使用,通常将这些常量称为类
常量。可以使用关键字static final设置一个类常量。需要注意,类常量的定义位于main方法的外部。
const是Java保留的关键字,但目前并没有使用。在Java中,必须使用final定义常量。
关于运算符需要注意的一些问题:
1 整数除0会产生一个异常,浮点数除0则会得到无穷或NaN
2 自增运算符与自减运算符,举个例子:
int m=7;
int n=7;
int a=2*++m;//m=8,a=16
int b=2*n++;//n=8,b=14
3 关系运算符与boolean运算符,举个例子:
if(x!=0&&1/x>x+y)
当x为0时,不会计算第二部分。因此,若x为0, 1/x不被计算,也不会出现除以0的错误。&&和 || 是按照“短路”方式求值的。
4 位运算符(这个用的较少,但容易忽略)
&( "与")、 |( "或")、 ^( "异或")、 ~( "非")
“ >>”和“ <<”运算符将二进制位进行右移或左移操作
>>>运算符将用0填充高位; >>运算符用符号位填充高位。没有<<<运算符
对移位运算符右侧的参数需要进行模32的运算(除非左边的操作数是long类型,在这种情况下需对右侧操作数模64)。例如, 1 << 35与1 << 3或8是相同的。
5 数学函数和常量
举个例子:
double x=4;
double y=Math.sqrt(x);
System.out.println(y);//print 2.0
Note:
println方法和sqrt方法存在微小的差异。 println方法操作一个定义在System类中的System.out对象。但是, Math类中的sqrt方法操作的不是对象,这样的方法被称为静态方法。
提示:从JDK 5.0开始,不必在数学方法名和常量名前添加前缀“ Math.”,而只要在源文件的顶部加上下列内容就可以了。
例如:
import static java.lang.Math.*;
6 数值之间的转换规则
贴个图,不解释
实心箭头,表示无信息丢失的转换;虚箭头,表示可能有精度损失的转换。
例如:123 456 789是一个大整数,它所包含的位数比float类型所能够表达的位数多。当将这个整型数值转换为float类型时,将会得到同样大小的结果,但却失去了一定的精度。
int n=123456789;
float f=n;//f is 1.234567892 E8
当使用数值进行二元运算时,先将两个操作数转换为同一类型,转换规则如下:
如果两个操作数中有一个是double类型的,另一个操作数就会转换为double类型。
否则,如果其中一个操作数是float类型,另一个操作数将会转换为float类型。
否则,如果其中一个操作数是long类型,另一个操作数将会转换为long类型。
否则,两个操作数都将被转换为int类型。
强制转换,举个例子;
double x=9.997;
int n=(int)x;//n is 9
如果取最接近的整数,可以使用:
double x=9.997;
int n=(int)Math.round(x);//n is 10
不要在boolean类型与任何数值类型之间进行强制类型转换,如果转换可以使用条件表达式b? 1:0。
7 括号与运算符级别
如果不使用圆括号,就按照给出的运算符优先级次序进行计算。同一个级别的运算符按照从左到右的次序进行计算(除了表中给出的右结合运算符外。)
运算符 | 结合性 |
---|---|
[ ] . ( ) (方法调用) | 从左向右 |
! ~ ++ – + (一元运算) - (一元运算) ( ) (强制类型转换) new | 从右向左 |
*/ % | 从左向右 |
加 - | 从左向右 |
<< >> >>> | 从左向右 |
< <= > >= instanceof | 从左向右 |
== != | 从左向右 |
& | 从左向右 |
^ | 从左向右 |
按位或 | 从左向右 |
&& | 从左向右 |
或 | 从左向右 |
?: | 从右向左 |
= += -= *= /= %= &= 或= ^= <<= >>= >>>= | 从右向左 |
8 枚举类型
这里先不做解释
从概念上讲,java字符串就是Unicode字符序列。如,串“ Java\u2122”由5个Unicode字符J、 a、 v、 a和TM。java没有内置的字符串类型(基本数据来了类型里没有),在java标准类库里提供了一个预定义的String类。每个“”括起来的都是字符串的一个实例:
String string="";//an empty string
String String="hello";//String是Java的一个类,类名是标识符,所以String可以做标识符。
String sizeof="sizeof";//There is no sizeof operator.Java中没有sizeof运算符,所以sizeof可以作为标识符
1 子串
举个例子:
String greeting="hello";
String s=greeting.subString(0,3);//s is hel
解释一下subString函数:
第一个参数,从0位置开始;第二个参数,到3结束(0,1,2,不包括3)。
则求子串的长度就比较简单,即3-0=3。
2 拼接
所谓拼接,即用+连接两个字符串。举个例子:
String a="hello";
String b="world";
int age=13;
String c=a+b;//c is helloworld
String d=a+age;//d is hello13
两个原则:
1 单词之间没有空格, +号按照给定的次序将两个字符串拼接起来
2 当将一个字符串与一个非字符串的值进行拼接时,后者被转换成字符串
3 不可变字符串
String类没有提供修改字符串的方法,如果希望将greeting的内容修改为“ Help!”,不能直接地将greeting的最后两个位置的字符修改为‘ p’和‘ !’。在c中实现起来,就比较麻烦:
在这里写提一下,将字符串认为是字符型数组:
char greeting[]="hello";
这种认识是错误的, Java字符串更加像char*指针,
char *greeting="hello";
当采用另一个字符串替换greeting的时候, c代码主要进行下列操作:
char *temp=malloc(6);
strncpy(temp,greeting,3);
strncpy(temp+3,"p!",3);
greeting=temp;
在Java中实现这项操作非常容易。首先提取需要的字符,然后再拼接上替换的字符串:
greeting=greeting.subString(0,3)+"p!";//greeting is help!
在java的源码文档中,将String类对象成为不可变字符串,在这里会有一个疑问:
String greeting="hello";
greeting="help!";
以上代码只是修改了greeting引用的地址,即原来引用的是“hello”,后来引用“help!”,那原来的“hello”去哪了?
这样做会不会产生内存遗漏呢?毕竟,原始字符串放置在堆中。十分幸运, Java将自动地进行垃圾回收。如果一块内存不再使用了,系统最终会将其回收。
当然,C++ string对象也自动地进行内存的分配与回收。内存管理是通过构造器、赋值操作和析构器显式执行的。然而, C++字符串是可修改的,也就是说,可以修改字符串中的单个字符。
为什么这么设计?看起来好像修改一个代码单元要比创建一个新字符串更加简洁,效率更高?
答案是:也对,也不对。的确,通过拼接“ Hel”和“ p!”来创建一个新字符串的效率确实不高。但是,不可变字符串却有一个优点:编译器可以让字符串共享。
为了弄清具体的工作方式,可以想像将各种字符串存放在公共的存储池中。字符串变量指向存储池中相应的位置。如果复制一个字符串变量,原始字符串与复制的字符串共享相同的字符。
总而言之, Java的设计者认为共享带来的高效率远远胜过于提取、拼接字符串所带来的低效率。查看一下程序会发现:很少需要修改字符串,而是往往需要对字符串进行比较。
4 检查字符串是否相等
如果你认为比较是否相等,可以用“==”即可,那你就错了,举个例子:
String greeting="hello";//initialize greeting to a string
if(greeting="hello")...
//probably true
if(greeting.subString(0,3)=="hel")...
//probably false
why?
如果虚拟机始终将相同的字符串共享,就可以使用 == 运算符检测是否相等。但实际上只有字符串常量是共享的,而+或substring等操作产生的结果并不是共享的。因此,千万不要使用 == 运算符测试字符串的相等性,以免在程序中出现糟糕的bug。从表面上看,这种bug很像随机产生的间歇性错误。
那在java中怎么比较字符串是否相等?
String greeting=hello;
"hello".equals(greeting)...//true
"Hello".equalsIgnore(greeting)...//true,不区分大小写,
Note:
对于习惯使用C++的string类的人来说,在进行相等性检测的时候一定要特别
小心。
C++的string类重载了==运算符以便检测字符串内容的相等性。可惜Java没有采用这种方式,
它的字符串“看起来、感觉起来”与数值一样,但进行相等性测试时,其操作方式又类似于指针。
语言的设计者本应该像对+那样也进行特殊处理,即重定义 == 运算符。
当然,每一种语言都会存在一些不太一致的地方。C程序员从不使用 == 对字符串进行比较,而使用strcmp函数。
Java的compareTo方法与strcmp完全类似,因此,可以这样使用:
if(greeting.comepareTo("hello")==0)...
不过,使用equals看起来更为清晰。
5 代码点与代码单元
什么是代码点和代码单元?
Java中,char[]、String、StringBuilder和StringBuffer类中采用了UTF-16编码,使用U+0000~U+FFFF来表示一个基本字符(BMP字符),但是位于U+D800到U+DBFF和U+DC00到U+DFFF的char被视为无定义字符。大多数的常用Unicode字符使用一个代码单元就可以表示,而辅助字符需要一对代码单元表示。即:基本字符用一个char表示,辅助字符使用一对char表示。
Java使用代码点(Unicode code pointer)这个概念来表示范围在U+0000与U+10FFFF之间的字符值(int型),代码单元(Unicode code unit)表示作为UTF-16编码的代码单元的 16位char值(char型)。也就是说,可能存在一个字符,它的代码点数量是1,而代码单元数量是2。所以,代码单元的数量并不一定是字符的数量。
相比之下,代码单元更加偏底层。
相关函数:
length()函数返回采用UTF-16编码标识的给定字符串所需要的代码单元的数量。
codePointCount()函数返回采用UTF-16编码标识的给定字符串所需要的代码点的数量。
测试程序:
package com.xujin;
public class Test{
public static void main(String...args){
char[] ch = Character.toChars(0x10400);
System.out.printf("U+10400 高代理字符: %04x\n", (int)ch[0]);//d801
System.out.printf("U+10400 低代理字符: %04x\n", (int)ch[1]);//dc00
String str = new String(ch);
System.out.println("代码单元长度: " + str.length());//2
System.out.println("代码点数量: " + str.codePointCount(0, str.length()));//1
System.out.println(str.codePointAt(0));//返回给定位置开始或结束的代码点,66560
System.out.println(str.charAt(1));//返回给定位置的代码单元,由于未定义,返回?
//遍历一个字符串,打印出所有字符的代码点
str += "Hello,world!";
int i = 0;
int cp = str.codePointAt(i);
while(i < str.length()){
System.out.println(str.codePointAt(i));
if(Character.isSupplementaryCodePoint(cp))
i += 2;//如果cp所在的位置是代码点的第一部分,执行此处
else i++;
}
/*
* 66560
* 72
* 108
* 111
* 119
* 114
* 100
*/
}
}
java字符串是由char序列组成,char是一个采用UTF-16编码表示
Unicode代码点的代码单元。常用Unicode字符使用一个代码单元就可以表示,而辅助字符需要一对代码单元表示。
length方法将返回采用UTF-16编码表示的给定字符串所需要的代码单元数量。例如:
String greeting="hello";
int l=greeting.length();//5
要想得到实际的长度,即代码点数量,可以调用:
int cpCount = greeting.codePointCount(0, greeting.length() );
//为什么说这个是实际长度?
调用s.charAt(n) 将返回位置n的代码单元, n介于0~s.length()-1之间。例如:
char first=greeting.charAt(0);//first is h
char last=greeting.charAt(4);//last is o
//返回字符
//要想得到第 i 个代码点,应该使用下列语句
int index = greeting.offsetByCodePoints(0, i);
int cp = greeting.codePointAt(index);
//返回ascii值
6 字符串API