您的位置:首页 > 编程语言 > Java开发

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,一种Boolean

1 整型

类型存储要求取值范围
int4字节-2 147 483 648~2 147 483 647(正好超过20亿)
short2字节-32 768~32 767
long8字节-9 223 372 036 854 775 808~9 223 372 036 854 775 807
byte1字节-128~127
在java中,整型的取值范围固定,与平台无关,这就解决了移植性的问题,而c/c++需要针对不同的处理器选择最为有效的整型,会导致整数溢出问题


2 浮点型

类型存储要求取值范围
float4字节大约±3.402 823 47E+38F(有效位数为6~7位)
double8字节大约±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从左向右
== !=从左向右
&从左向右
^从左向右
按位或从左向右
&&从左向右
从左向右
?:从右向左
= += -= *= /= %= &= 或= ^= <<= >>= >>>=从右向左
8 枚举类型

这里先不做解释

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十进制整数159s字符串hello
x十六进制整数9fc字符h
o八进制整数237b布尔true
f定点浮点数15.9h散列码42628b2
e指数浮点数1.59e+01tx日期时间见下面详解
g通用浮点数%百分号%
a十六进制浮点数0x1.fccdp3n与平台有关的行分隔符
System.out.printf(",.2f",10000.0/3.0);//3,333.33


标志目的举例
+打印正数和负数的符号+3333.33
空格在正数之前添加空格空格3333.33
0数字前面补0003333.33
-左对齐3333.33
(将负数括在括号内( 3333.33)
添加分组分隔符3,333.33
(对于f格式)包含小数点3,333
(对于x或0格式)添加前缀0x或00xcafe
美元符给定被格式化的参数索引。例如, %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
FISO 8601日期2004-02-09
D美国格式的日期(月/日/年)02/09/2004
T24小时时间18:05:19
r12小时时间06:05:19 pm
R24小时时间没有秒18:05
Y4位数字的年(前面补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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: