java基础知识学习笔记(二)
2016-03-28 19:06
561 查看
java基本的程序设计结构
1 一个简单的java例子
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方法。
2 注释
与多数设计语言一样,java中的注释不会出现在可执行程序中。注释类型:
单行:
//注释的内容
多行:
/*注释的内容 */
另一种:
/**注释的内容*/
Note: 在Java中, /* */注释不能嵌套。也就是说,如果代码本身包含了一个*/,就不能用/*和*/将注释括起来。
3 数据类型
四种整型,两种浮点,一种char,一种Boolean1 整型
类型 | 存储要求 | 取值范围 |
---|---|---|
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不能转换为布尔值。
4 变量
记住一下几点: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定义常量。
5 运算符
关于运算符需要注意的一些问题: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 | 从左向右 |
== != | 从左向右 |
& | 从左向右 |
^ | 从左向右 |
按位或 | 从左向右 |
&& | 从左向右 |
或 | 从左向右 |
?: | 从右向左 |
= += -= *= /= %= &= 或= ^= <<= >>= >>>= | 从右向左 |
这里先不做解释
6 字符串
从概念上讲,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
java的String类包含50多个方法,下面列举一些常用的方法
java.lang.string 1.0
如果某个方法是在这个版本之后添加的,就会给出一个单独的版本号。
• char charAt (int index) 返回给定位置的代码单元。除非对底层的代码单元感兴趣,否则不需要调用这个方法。 • int codePointAt(int index) 5.0 返回从给定位置开始或结束的代码点。 • int offsetByCodePoints(int startIndex, int cpCount) 5.0 返回从startIndex代码点开始,位移cpCount后的代码点索引。 • int compareTo(String other) 按照字典顺序,如果字符串位于other之前,返回一个负数;如果字符串位于other之后, 返回一个正数;如果两个字符串相等,返回0。 • boolean endsWith(String suffix) 如果字符串以suffix结尾,返回true。 • boolean equals(Object other) 如果字符串与other相等,返回true。 • boolean equalsIgnoreCase(String other) 如果字符串与other相等(忽略大小写),返回true。 • int index0f(String str) • int index0f(String str, int fromIndex) Java基本的程序设计结构 47 java.lang.string 1.0 • int index0f(int cp) • int index0f(int cp, int fromIndex) 返回与字符串str或代码点cp匹配的的第一个子串的开始位置。这个位置从索引0或 fromIndex开始计算。如果在原始串中不存在str,返回-1。 • int lastIndex0f(String str) • int lastIndex0f(String str, int fromIndex) • int lastindex0f(int cp) • int lastindex0f(int cp, int fromIndex) 返回与字符串str或代码点cp匹配的最后一个子串的开始位置。这个位置从原始串尾端或 fromIndex开始计算。 • int length( ) 返回字符串的长度。 • int codePointCount(int startIndex, int endIndex) 5.0 返回startIndex和endIndex-1之间的代码点数量。没有配成对的代用字符将计入代码点。 • String replace(CharSequence oldString,CharSequence newString) 返回一个新字符串。这个字符串用newString代替原始字符串中所有的oldString。可以用 String或StringBuilder对象作为CharSequence参数。 • boolean startsWith(String prefix) 如果字符串以preffix字符串开始,返回true。 • String substring(int beginIndex) • String substring(int beginIndex, int endIndex) 返回一个新字符串。这个字符串包含原始字符串中从beginIndex到串尾或endIndex-1的所 有代码单元。 • String toLowerCase( ) 返回一个新字符串。这个字符串将原始字符串中的所有大写字母改成了小写字母。 • String toUpperCase( ) 返回一个新字符串。这个字符串将原始字符串中的所有小写字母改成了大写字母。 • String trim( ) 返回一个新字符串。这个字符串将删除了原始字符串头部和尾部的空格
7 构建字符串
java里常用的一般是字符串的复制、比较等等,故java的String类设计成不可变字符串,复制和比较等等用的是字符串的共享,方便快捷,但有些时候,也需要对字符串进行构建,如按键或文件中的单词,采用字符串拼接的方式固然可以,但效率略低,每次连接时都需要创建一个新的String对象,即耗时,又耗空间,使用StringBuilder类就可以避免这个问题的发生。
使用许多小段字符串构建一个字符串,步骤如下:
首先,构建一个空的字符串构建器
StringBuilder builder=new StringBuilder();
当每次需要加入新字符串时,调用append方法:
builder.append(ch);//appends a single character builder.append(str);//appends a string
在需要构建字符串时调用toString方法,可以得到一个String对象,其中包含构建器中的字符序列。
String completedString=builder.toString();
Note: 在JDK5.0中引入 StringBuilder类。这个类的前身是StringBuffer,其效率略微有些 低,但允许采用多线程的方式执行添加或删除字符的操作。如果所有字符串在一个单线 程中(通常都是这样)编辑,则应该用StringBuilder替代它。这两个类的API是相同的。
下面是StringBuilder类中的重要方法。
java.lang.StringBuilder 5.0
• 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 endIndex) 删除偏移量从startIndex到-endIndex-1的代码单元并返回this。 • String toString() 返回一个与构建器或缓冲器内容相同的字符串
7 输入输出
1 读取输入简单说一下从控制台输入的步骤:
首先,构造一个Scanner对象,并接收参数System.in
Scanner in=new Scanner(System.in);
现在可以使用Scanner类中的方法实现输入操作了
System.out.println("What is your name?"); String name=in.nextLine();//在输入行中有可以包含空格。 String fistName=in.next();//读取一个单词(以空白符作为分隔符) int age=in.nextInt();//读取一个整数 ...
最后,在程序的最开始添加上一行:
import java.util.*;//last
测试程序
import java.util.*; public class InputTest{ public static void main(){ //1 构造Scanner,以System.in作为参数 Scanner in=new Scanner(System.in); //2 调用相应Scanner类中的方法 System.out.println("what is your name?"); String name=in.nextLine(); System.out.println(how old are you?); int age=in.nextInt(); //3 display System.out.println("hello,"+name+".Next year,you'll be "+(age+!)); } }
Note: 因为输入是可见的,所以Scanner类不适用于从控制台读取密码。 Java SE 6特别引 入了Console类实现这个目的。要想读取一个密码,可以采用下列代码: Console cons=System.console(); String username=cons.readLine("User name:"); char password=cons.readPassword("Password:"); 为了安全起见,返回的密码存放在一维字符数组中,而不是字符串中。在对密码进行处 理之后,应该马上用一个填充值覆盖数组元素(数组处理将在本章稍后介绍)。 采用Console对象处理输入不如采用Scanner方便。每次只能读取一行输入,而没有能够读 取一个单词或一个数值的方法。
下面附上Scanner类的方法
java.util.Scanner 5.0
• Scanner (InputStream in) 用给定的输入流创建一个Scanner对象。 • String nextLine( ) 读取输入的下一行内容。 • String next( ) 读取输入的下一个单词(以空格作为分隔符)。 • int nextInt( ) • double nextDouble( ) 读取并转换下一个表示整数或浮点数的字符序列。 • boolean hasNext( ) 检测输入中是否还有其他单词。 • boolean hasNextInt( ) • boolean hasNextDouble( ) 检测是否还有表示整数或浮点数的下一个字符序列
下面是System中console方法
java.lang.System 1.0
• static Console console( ) 6 如果有可能进行交互操作,就通过控制台窗口为交互的用户返回一个Console对象,否则 返回null。对于任何一个通过控制台窗口启动的程序,都可使用Console对象。否则,其 可用性将与所使用的系统有关。
下面是Console类的方法
java.io.Console 6
• static char[] readPassword(String prompt, Object...args) • static String readLine(String prompt, Object...args) 显示字符串prompt并且读取用户输入,直到输入行结束。 args参数可以用来提供输入格 式。
2 格式化输出
常用的输出
System.out.print(); System.out.println();//与上面方法相比,多输出一个换行符
当然,Java SE 5.0沿用了C语言库函数中的printf方法。
转换符 | 类型 | 举例 | 转换符 | 类型 | 举例 |
---|---|---|---|---|---|
d | 十进制整数 | 159 | s | 字符串 | hello |
x | 十六进制整数 | 9f | c | 字符 | h |
o | 八进制整数 | 237 | b | 布尔 | true |
f | 定点浮点数 | 15.9 | h | 散列码 | 42628b2 |
e | 指数浮点数 | 1.59e+01 | tx | 日期时间 | 见下面详解 |
g | 通用浮点数 | % | 百分号 | % | |
a | 十六进制浮点数 | 0x1.fccdp3 | n | 与平台有关的行分隔符 |
System.out.printf(",.2f",10000.0/3.0);//3,333.33
标志 | 目的 | 举例 |
---|---|---|
+ | 打印正数和负数的符号 | +3333.33 |
空格 | 在正数之前添加空格 | 空格3333.33 |
0 | 数字前面补0 | 003333.33 |
- | 左对齐 | 3333.33 |
( | 将负数括在括号内 | ( 3333.33) |
, | 添加分组分隔符 | 3,333.33 |
(对于f格式) | 包含小数点 | 3,333 |
(对于x或0格式) | 添加前缀0x或0 | 0xcafe |
美元符 | 给定被格式化的参数索引。例如, %1d,d, %1x将以十进制和十六进制格式打印第1个参数 | 159 9F |
< | 格式化前面说明的数值。例如, %d% | 159 9F |
Note: 可以使用s转化符格式化任何对象,对于实现了Formattable接口的对象将调用formatTo方法,否则调用toString方法。 可以使用静态的String.format方法将对象转换为字符串,不打印输出,如: String greeting=String.format("hello, %s.Next year,you'll be %d",name,age);
printf方法中时间日期的格式化
以t开始,以下表中任一字母结束的两个字母格式,如:
System.out.printf("%tc",new Date()); //Mon Feb 09 18:05:19 PST 2004
转换符 | 类型 | 举例 |
---|---|---|
c | 完整的日期和时间 | Mon Feb 09 18:05:19 PST 2004 |
F | ISO 8601日期 | 2004-02-09 |
D | 美国格式的日期(月/日/年) | 02/09/2004 |
T | 24小时时间 | 18:05:19 |
r | 12小时时间 | 06:05:19 pm |
R | 24小时时间没有秒 | 18:05 |
Y | 4位数字的年(前面补0) | 2004 |
y | 年的后两位数字(前面补0) | 04 |
C | 年的前两位数字(前面补0) | 20 |
B | 月的完整拼写 | February |
b或h | 月的缩写 | Feb |
m | 两位数字的月(前面补0) | 02 |
d | 两位数字的日(前面补0) | 09 |
e | 两位数字的月(前面不补0) | 9 |
A | 星期几的完整拼写 | Monday |
a | 星期几的缩写 | Mon |
j | 三位数的年中的日子(前面补0),在001到366之间 | 069 |
H | 两位数字的小时(前面补0),在0到23之间 | 18 |
k | 两位数字的小时(前面不补0),在0到23之间 | 18 |
I | 两位数字的小时(前面补0),在0到12之间 | 06 |
l | 两位数字的小时(前面不补0),在0到12之间 | 6 |
M | 两位数字的分钟(前面补0) | 05 |
S | 两位数字的秒(前面补0) | 19 |
L | 三位数字的毫秒(前面补0) | 047 |
N | 九位数字的毫微秒(前面补0) | 047000000 |
P | 上午或下午的大写标志 | PM |
p | 上午或下午的小写标志 | pm |
z | 从GMT起, RFC822数字位移 | -0800 |
Z | 时区 | PST |
s | 从格林威治时间1970-01-01 00:00:00起的秒数 | 1078884319 |
Q | 从格林威治时间1970-01-01 00:00:00起的毫秒数 | 1078884319047 |
System.out.printf("%1$s %2$tB %2$te,%2$tY","Due date:",new Date()); //Due Date:February 9,2004
还可以选择使用<标志。它指示前面格式说明中的参数将被再次使用。也就是说,下列语句将产生与前面语句同样的输出结果。
System.out.printf("%s %tB %<te,%<tY","Due date:",new Date());
数索引值从1开始,而不是从0开始, %1$...对第1个参数格式化。这就避免了与0标志混淆。
对格式化说明做个简单总结
3 文件的输入输出
1 对文件读取,需按照以下步骤:
首先,为文件对象File创建一个Scanner对象,如:
Scanner in =new Scanner(new File("myfile.txt"));
如果文件名中包含反斜杠符号,就要记住在每个反斜杠之前再加一个额外的反斜杠:
“ c:\mydirectory\myfile.txt”。
然后,调用Scanner的方法对文件进行读取。
2 对文件写入,需要构造一个PrintWriter对象,在构造器中只需提供文件名,如:
PrintWriter out=new PrintWriter("myfile.txt");
Note: 可以构造一个带有字符串参数的Scanner,但这个Scanner将字符串解释为数据,而不是文件名。例如,如果调用: Scanner in =new Scanner("myfile.txt");//error? 这个scanner会将参数作为包含10个字符的数据:‘ m’,‘ y’,‘ f’等等。在这个示例中所显示的并不是人们所期望的效果。
Note:
当指定一个相对文件名时,例如, “ myfile.txt”, “ mydirectory/myfile.txt”或
“ ../myfile.txt”,文件位于Java虚拟机启动路径的相对位置。如果在命令行方式下用下列命
令启动程序:
java MyProg
启动路径就是命令解释器的当前路径。然而,如果使用集成开发环境,那么启动路径将
由IDE控制。可以使用下面的调用方式找到路径的位置:
String dir=System.getProperty(user.dir);
如果觉得定位文件比较烦恼,则可以考虑使用绝对路径,例如: “c:\\mydirectory\\
myfile.txt”或者“ /home/me/mydirectory/myfile.txt”。
正如读者所看到的,访问文件与使用System.in和System.out一样容易。要记住一点:如果
用一个不存在的文件构造一个Scanner,或者用一个不能被创建的文件名构造一个PrintWriter,
那么就会发生异常。 Java编译器认为这些异常比“被零整除”异常更严重。
现在,应该告知编译器:已经知道有可能出现“找不到文件”的异常。这需要在main方法中用throws子句标记,如下所示:
public static void main(String[] args)throws FileNotFoundException{
Scanner in =new Scanner(new File("myfile.txt"));}
Note: 当采用命令行方式启动一个程序时,可以利用重定向将任意文件捆绑到System.in 和System.out: java MyProg<myfile.txt> output.txt 这样,就不必担心处理FileNotFoundException异常了。
附上文件输入输出用到的API
java.util.Scanner 5.0
• Scanner(File f) 构造一个从给定文件读取数据的Scanner。 • Scanner(String data) 构造一个从给定字符串读取数据的Scanner。
java.io.PrintWriter 1.1
• PrintWriter(File f) 构造一个将数据写入给定文件的PrintWriter。 • PrintWriter(String fileName) 构造一个将数据写入文件的PrintWriter。文件名由参数指定。
java.io.File 1.0
• File(String fileName) 用给定文件名,构造一个描述文件的File对象。注意这个文件当前不必存在。
8 控制流程
java语言和其他语言一样,也有自己的控制流程语句,如:条件语句
循环语句
switch语句
下面对这三种控制语句进行详细解释。
Note: 与c/c++相比,没有goto语句,但break语句可以带标签,可以利用它实现从内层循环跳出的目的(这种情况C语言采用goto语句实现)。 Java SE 5.0还添加了一种变形的for循环,在C或C++中没有这类循环。它有点类似于C#中的foreach循环。
在解释控制语句之前,先说一下块(block)
1 块作用域
块就是用花括号括起来的若干条java语句,块确定了变量的块作用域,一个块可以嵌套在另一个块中。但是不能在嵌套的块中声明相同的变量,这点和c/c++不一样,切记
public static void main(){ int n; { int k; int n;//error--can't redefine n in inner block } }
2 条件语句
条件语句常见格式如下:
if (condition) statement 或者 if(condition){ statement1; statement2; ... }
if(condition)statement1 else statement2 或者 if(condition){ statement1; statement2; ... } else{ statement3; statement4; ... }
3 循环结构
循环语句常见格式如下:
while(condition) statement 或者 while(condition){ statement1; statement2; ... } //while循环语句首先检测循环条件。因此,循环体中的代码有可能不被执行。
do{ statement1; statement2; ... }while(condition) //这种循环语句先执行语句(通常是一个语句块),再检测循环条件
4 确定循环(for循环)
for(int i=1;i<=10;i++){ ... } //i no longer defined here
5 多重选择:switch语句
Note: 如果在case分支语句的末尾没有break语句,那么就会接着执行下一个case分支语句。 这种情况相当危险,常常会引发错误。为此,我们在程序中从不使用switch语句。 case标签必须是整数或枚举常量,不能测试字符串。例如,下面这段代码就存在错误。 String input="..."; switch(input){//errror case "A"://error ... breadk; ... } 当在switch语句中使用枚举常量时,不必在每个标签中指明枚举名,可以由switch的表达式值确定。例如: Size sz=...; switch(sz){ case SMALL://no need use Size.SMALL ... break; ... }
6 中断控制流程语句
java中goto被设计为保留字,但实际上并没有打算在语言中使用它,因为goto语句被认为是一种设计拙劣的程序结构。不过,java提供了一种带标签的break语句,其执行结果和goto类似。
先简单说明一下为什么需要break语句?
举个例子:
while(year<=100){ balance+=payment; double interest=balance*instrestRate/100; balance+=instrest; if(balance>=goal)break; years++; } //在循环开始时,如果years > 100,或者在循环体中balance≥goal,则退出循环语句。
while(year<=100&&balance<goal){ balance+=payment; double interest=balance*instrestRate/100; balance+=instrest; if(balance<goal){ years++; } } //在这个版本中,检测了两次balance < goal。为了避免重复检测,有些程序员更加偏爱使用break语句。
下面就解释一下带标签的break语句
与c++不同,java提供一种带标签的break语句,用于跳出多重嵌套的循环语句。一般循环是逐层跳出的,但有些时候需要直接跳出所有嵌套循环,在循环体中加一些额外判断参数来检测各层循环不太方便,故需要一种可以简单自定义跳出所有循环的方法,带标签的break就可以恰当实现。
既然是带标签,就要明白标签用来干什么的。标签相当于一个入口声明,告诉程序跳出后的入口在哪,然后顺序执行下面的语句。标签必须放在希望跳出的最外层循环之前,并且紧跟冒号。举个例子:
Scanner in=new Scanner(System.in); int n; read_data: while(...)//this loop statement is tagged with the label { ... for(...) //this innner loop is not labeled { System.out.print("enter a number >=0"); n=in.nextInt(); if(n<0) //should never happen,can't go on { break read_data;//break out of read_data loop } ... } } //this statement is executed immediately after the labeled break if(n<0)//bad situation { //deal with bad situation ... } else{ ...//nomal processing }
continue语句与break语句有什么区别?
break语句:终止最近的封闭循环或所在的switch语句,控制传递给终止语句后面的语句。
contiinue语句:控制转移到它所在的内层循环的首部(下一次迭代)
举个例子:
/** * */ package com.su.biancheng; /** * @title break_continue.java * @author Shuai * @date 2016-4-2下午4:36:32 */ public class break_continue { public static void main(String[] args){ char[] arr={'a','b','c','d','e','f'}; for(char c:arr) { switch(c){ case 'd': //continue; break; } System.out.println("put out:"+c); } } }
输出结果: put out:a put out:b put out:c put out:d //多出这一行 put out:e put out:f
public class break_continue { public static void main(String[] args){ char[] arr={'a','b','c','d','e','f'}; for(char c:arr) { switch(c){ case 'd': continue;//类似于next //break; } System.out.println("put out:"+c); } } }
输出结果: put out:a put out:b put out:c put out:e put out:f
9 大数值
如果基本的整数和浮点数精度不能够满足需求,那么可以使用java.math包中的两个很有用的类: BigInteger和BigDecimal。这两个类可以处理包含任意长度数字序列的数值。 BigInteger类实现了任意精度的整数运算, BigDecimal实现了任意精度的浮点数运算。使用静态的valueOf方法可以将普通的数值转换为大数值:BigInteger n=BigInteger.valueOf(100);
遗憾的是,不能使用人们熟悉的算术运算符(如: + 和*)处理大数值。而需要使用大数值类中的add和multiply方法。
BigInteger a=n.add(b);//a=n+b BigInteger d=c.multiply(b.add(BigInteger.valueOf(2)));//d=c*(b+2)
API java.math.BigInteger 1.1
• BigInteger add(BigInteger other) • BigInteger subtract(BigInteger other) • BigInteger multiply(BigInteger other) • BigInteger divide(BigInteger other) • BigInteger mod(BigInteger other) 返回这个大整数和另一个大整数other的和、差、积、商以及余数。 • int compareTo(BigInteger other) 如果这个大整数与另一个大整数other相等,返回0;如果这个大整数小于另一个大整数 other,返回负数;否则,返回正数。 • static BigInteger valueOf(long x) 返回值等于x的大整数。
java.math.BigInteger 1.1
• BigDecimal add(BigDecimal other) • BigDecimal subtract(BigDecimal other) • BigDecimal multiply(BigDecimal other) • BigDecimal divide(BigDecimal other, RoundingMode mode) 5.0 返回这个大实数与另一个大实数other的和、差、积、商。要想计算商,必须给出舍入方式 ( rounding mode)。 RoundingMode.HALF_UP是在学校中学习的四舍五入方式(即,数值0 到4舍去,数值5到9进位)。它适用于常规的计算。有关其他的舍入方式请参看API文档。 • int compareTo(BigDecimal other) 如果这个大实数与另一个大实数相等,返回0;如果这个大实数小于另一个大实数,返回 负数;否则,返回正数。 • static BigDecimal valueOf(long x) • static BigDecimal valueOf(long x,int scale) 返回值为x或x / 10scale的一个大实数。
10 数组
声明数组要指出数组类型(数据元素类型紧跟[])和数组变量的名字。
int[] a;//推荐这一种,"int[]"数组与变量"a"分开 //或 int a[];
初始化数组
int[] a=new int[100]; //或 int[] a={1,2,3,..};//无需使用new //或 b=new int[]{1,2,3,..};//初始化一个匿名数组 //等价于 int[] a={1,2,3,..}; b=a;
数组的输出
int[] a={1,2,3,4,5,6,7}; //foreach for(int element:a) System.out.println(element); //传统for for(int element;element<a.length;element++) System.out.println(element); //Arrays的toString方法 System.out.println(Arrays.toString(a));
数组的拷贝
在Java中,允许将一个数组变量拷贝给另一个数组变量。这时, 两个变量将引用同一个数组:
int[] a=b; a[5]=12;//now b is also 12
如果想拷贝整个数组值到一个新数组 ,使用Arrays的copyOf方法
int[] c=Arrays.copyOf(a,a.length);
第2个参数是新数组的长度。这个方法通常用来增加数组的大小:
a=Arrays.copyOf(a,2*a.length);
如果数组元素是数值型,那么多余的元素将被赋值为0;如果数组元素是布尔型,则将赋值为false。相反,如果长度小于原始数组的长度,则只拷贝最前面的数据元素。
在Java SE 6之前,用System类的arraycopy方法将一个数组的元素拷贝到另一个数组中。调用这个方法的语法格式为:
System.out.println(from,formIndex,to,toIndex,count); //数组to必须有足够的空间存放拷贝的元素。
int[] a={1,2,3,4,5,6}; int[] b={101,102,103,104,105,106,107}; System.arraycopy(a,2,b,3,4); //从a的第2+1个元素开始,一共拷贝4个元素,目标数组起始位置为3 for(int element:b) System.out.println(element);
输出结果: 101 102 103 3 4 5 6
相关文章推荐
- MyEclipse------带进度条的输入流
- 【java基础概念】(2016/3/28)
- mac上同时安装多个jdk,选择版本
- JAVA中关于DATE时间日期加减、String与Date类型的转换
- JavaWeb测试题总结
- Java 字节流与字符流的区别
- Spring的简单应用
- Java in Tarena_Spring Note04
- 开课第一天java
- activiti自定义流程之Spring整合activiti-modeler5.16实例(三):流程模型列表展示
- Java垃圾回收机制
- JAVA第三次作业
- 解决java compiler level does not match the version of the installed java project facet
- java 你好!我的java学习之路 day1
- Java第三次作业
- java 使用freemarker 生成word模板
- Spring MVC DispatcherServlet contextConfigLocation设置
- Java学习:动态代理
- java PreparedStatement需要关闭,不然会内存溢出
- Spring事务的隔离级别