附-Java基本概念

附-Java基本概念


#注释

在Java中,注释有三种,分别为:

  • /** 这是一种多行注释,它是Java所特有的注释方式。使用该种注释方式,可以使得JDK的工具javadoc可以提取出该注释中的内容,构成该源代码文件的说明书。 javadoc命令的使用方法为: javadoc 源程序文件名 */
  • /* 这也是一种多行注释,它的功能同C中的一样,它同第一种注释的区别在于,这种注释中的内容是javadoc不会提取该注释中的内容 */
  • // 这是一种单行注释,它只能用于一行的行尾,它的功能同C中的也是一样的,同样它的注释内容也不能由javadoc提取
    注意: 注释是不能嵌套使用的

#标识符

  • 标识符是某种语法成分的 名字 ,如类名、变量名、方法名等;
  • 标识符是没有长度限制的Java letters 和 Java digits 的序列,第一个必须是Java letter,标识符不能和关键字, boolean常量和null常量一样。
    • Java letters包括ASCII 拉丁字母 A–Z, 和 a–z, 还包括ASCII下划线 (_) 和美元符号 ( ) 。 )。 ) 通常是用于机器自动产生的代码中;
    • Java digits包括ASCII数字字符0-9。
  • 标识符区分大小写
  • 在定义标识符时,最好见名知义

#标识符命名规范

  • 类名、接口名

    • 类名应该是英文名词,尽量见名知义,如果类名由多个单词构成,每个单词的首字母大写,如:ImageSprite;
  • 包名

    • 所有都用小写字母
  • 变量名、对象名、方法名等标识符首单词字母全小写,其他单词首字母大写,也要尽量见名知义

    • 方法名应该是动词,如:getBackground();
    • 变量名,除了临时变量以外,避免使用单字母名字,如:float myWidth;
  • 常量名

    • 常量名全部用大写,单词之间用“_”隔开,如:int MIN_WIDTH=4;
  • 成员变量

    • static成员变量名以s开始
    • 非public、非static成员变量名以m开始
    • 其它以小写字母开始
    • 如:
    public class MyClass {
    	public static final int SOME_CONSTANT = 42;
    	public int publicField;
    	private static MyClass sSingleton;
    	int mPackagePrivate;
    	private int mPrivate;
    	protected int mProtected;
    }
    
  • 对于简称,最好也把它当作单词来用,如下表:

    建议不建议
    XmlHttpRequestXMLHTTPRequest
    getCustomerIdgetCustomerID
    HtmlHTML
    urlURL
    idID
  • 示例:

    • 合法标识符
      • String、i3、MAX_VALUE、isLetterOrD、_123Test、HelloWorld、public1
      • main也为合法标识符,但是我们建议只把它作为类的执行入口方法的名字,不做其他使用
    • 不合法标识符
      • 123Test、Hello-World、HelloWorld#、public、Hello World

#关键字

关键字是Java系统所定义有特定语法含义的字符序列,如:class、public等等,关键字不能作为标识符使用。

  • 下列字符序列作为关键字:
  • abstract boolean break byte case catch char class const continue do double default else extends final finally float for goto if implements import instanceof int interface long native new package private protected public return short static strictfp super switch synchronized this throw throws transient try void volatile while
  • boolean常量true和false,以及 null常量也应该看作关键字。

#类型

我们在学习一门计算机语言的时候,一定要了解这个语言支持哪些数据类型。Java语言是强类型(strongly typed)语言,这意味着在Java中,所有的数据,包括常量、变量和表达式都会有一个类型。

Java语言的类型分为两类:基本类型(primitive types)和引用类型(reference types):

  • 基本类型包括数字类型以及布尔类型boolean,数字类型包括:
    • 整数类型(integral types):byte, short,int, long, 和char;
    • 浮点类型(floating-point types):float 和double。
  • 引用类型有class 类型、interface 类型、array 类型,以及枚举类型。

每种基本类型均有相应的封装类与之对应,这些封装类封装了对应的基本类型的相关操作,如下表:

基本类型封装类
booleanBoolean
byteByte
shortShort
intInteger
charCharacter
floatFloat
doubleDouble

#基本类型

基本类型同其他面向过程的语言的类型类似,对于这种类型,我们所关注的是这些类型的类型名,相应类型数据的取值范围,数值的取值范围是同该种类型的数据在内存中所占大小密切相关的。下面来看看各基本类型在内存中的占用情况。

  • 整数类型integral types 有byte, short, int, 以及 long, 他们的值分别为8-bit,16-bit, 32-bit 和 64-bit 有符号(signed)补码整数,char类型的值为16-bit 无符号(unsigned) 整数,它的值为Unicode字符编码。由此,它们的取值范围如下:
    • byte -27~27-1
    • short -215~215-1
    • int -231~231-1
    • long -263~263-1
    • char ‘\u0000’~‘\uffff’
  • 浮点类型floating-point types 有float和double ,它们的值分别为 32-bit和 64-bit 的 IEEE 754 浮点数。
  • boolean类型有两个值true和false,不讨论它的大小

#字面量(literal)

所谓字面量是那种一看就知道其值的常量,比如:1.23、“abc”、true、'a’等。因为在java中所有的数据都有类型,那么字面常量也有其类型,每种类型的字面常量也有其特定的写法。literal常量的类型有:基本类型、 String 类型的值,包括null。

  • 整数常量(integer literal)有三种表示形式,十进制表示(decimal (base 10)), 十六进制(hexadecimal (base 16)), 或八进制(octal (base 8))
    • 一个十进制数是0到9的序列(第一个不能是0,因为0是八进制数的起始数字),表示正整数;
    • 一个十六进制数由0x 或 0X 开头,后跟若干位十六进制补码数字,因为补码数的特点,十六进制数码本身是包含符号的,因此十六进制数字可以表示正数、负数和0;
    • 一个八进制数以0开头,后跟若干八进制数,表示正数、负数和0,道理同上;
    • 在java7以后允许二进制表示,以0b或0B开头,后跟0、1的组合
    • 在java7以后数字间还可以加_作为数字分隔,如:0xffff_ffff、0377_7777_7777
    • 整数后跟 L 或 l ,建议使用L(小写l在视觉上同数字1不好区分,当然,计算机是可以明白无误区分的),表示该数的类型为long类型,若无后缀,则为int类型。
  • 浮点常量floating-point literal 可以有以下部分:whole-number(整数) part, a decimal point (小数点), a fractional part(小数部分), an exponent(指数部分),和一个类型后缀
    • 如果为十进制表示,则在整数部分或者小数部分至少有一位数字,同时,小数点、指数、类型后缀这三者至少出现一个。其它部分可选。指数部分由 e 或 E 后跟可带符号的整数;
    • 如果为十六进制表示,以0x或0X开头,则在整数部分或者小数部分至少有一位数字,必须有指数部分,指数部分由 p 或 P 后跟可带符号的整数;类型后缀可选。
    • 浮点数后跟 F 或 f ,则其类型为float,若无后缀,则其类型为double, 即是后缀D 或 d可选。
    • float常量的例子:
      • 1e1f 2.f .3f 0f 3.14f 6.022137e+23f
    • double 常量的例子:
      • 1e1 2. .3 0.0 3.14 1e-9d 1e137
  • boolean 常量
    • boolean 有两个值true 和 false。
  • 字符常量
    • character literal 是单引号(single quotes)括起来的字符
    • 下面为char 常量(三种形式)
      • 第一种形式(单引号中为需表达的字符)
        • ‘a’
        • ‘%’
      • 第二种形式(单引号中为转义的字符)
        • ‘\t’
        • '\ ’
        • ‘’’
      • 第三种形式(以十六进制或者八进制表示的的字符)
        • ‘\u03a9’
        • ‘\uFFFF’
        • ‘\177’
    • 转义(Escape)序列:
      • \b /* \u0008: 退格backspace BS */
      • \t /* \u0009: horizontal tab HT */
      • \n /* \u000a: linefeed LF使得打印机走纸到下一行*/
      • \f /* \u000c: form feed FF 使得打印机走纸到下一页*/
      • \r /* \u000d: carriage return CR使得打印头回到行首*/
      • " /* \u0022: 双引号double quote" */
      • ’ /* \u0027: 单引号single quote ’ */
      • \ /* \u005c: 反斜线backslash \ */
      • \OctalDigit
      • \OctalDigit OctalDigit
      • \ZeroToThree OctalDigit OctalDigit
    • native2ascii的使用:该命令为JDk中所提供的工具,可以通过该命令查看某个字符的unicode编码。如图:img
  • 字符串常量(string literal)由双引号括起来的零个(含)以上的字符序列。
    • 每个字符都可能由转义序列(escape sequence)组成。
    • 字符串的类型为String(String为一种java类名,它表示字符串),两个值相同的字符串常量其实是类 String 的同一实例。
    • 字符串例子:
      • “” // 空字符串
      • “”" // 只包含 " 的字符串
      • “This is a string” // 一个包含16个字符的字符串
      • "This is a " + “two-line string” /* 由两个字符串连接成的字符串常量 */
  • null是个常量值,但这个常量值没有具体的类型,它可以成为任何引用类型的值

#变量

顾名思义,变量就是其值可以改变的量,但在java中并不是所有的变量值都是可以改变的。变量是计算机内存中的一块存储区域,这块区域有名字类型作用域,通过变量名使用变量中的数据,变量的类型决定该变量可取值和可进行的运算与操作。

  • 变量必须定义,通过定义,可以知道变量的名字及其类型,其定义形式如下: type variablename

  • 根据其类型来分类,可分为两种

    • 基本类型的变量中存放该变量的值
    • 引用类型的变量中存放该变量值的引用(实际就是地址),注意不是变量值,变量值本身为对象,在堆中存放,变量中存放该对象在堆中的地址,我们称为引用。
  • 在java中,变量定义的位置有四种,这四种位置决定了变量的作用域(Scope),变量作用域就是变量名字起作用的范围,有四类作用域,如图所示:

    • 成员变量(member variable),是类或对象的组成部分,表示对象的属性,它在类的方法或构造方法(constructor)之外定义。成员变量的作用域充满整个类。如果对成员变量的使用如果是在某个初始化语句之中,该成员变量的定义必须出现在该语句之前。如下例:

      public class Test {//本例没有任何问题
      	int j = f(); //定义一个成员变量j,并进行初始化
      
      	int f(){
      		int j;//这里的j是局部变量j,不是上面所定义的成员变量j
      		j = i;
      		return j;
      	}
      
      	int i=9;
      }  
      
      public class Test {
      	int j = f(i);//虽然i这个成员变量的作用域在这里是有效的,但这里无法使用i,会出现“非法前向引用”错误
      	int i = 9;
      
      	int f(int x){
      		int j;
      		j = x;
       				return j;
      	}
      }
      
    • 局部变量(local variable),在一块代码内定义的变量称为局部变量(local variables),这种变量的作用域从其定义位置开始到它所在的块结束为止。如下程序段:

      {int x=90;
      	{ int x=80;}
      }//不允许:局部变量不允许再次定义
      {int x=90;
      	{ int y=80;}
      }//可以
      
    • 方法参数(method parameter),这种变量类似局部变量,用来给方法或构造器传值,它的作用域在它所在的方法体中。

    • catch异常参数(exception handler parameter),它的作用域在它所在的catch块中。

#示例1

/*
	关于变量的作用域:有效范围。作用范围。
	
	出了大括号就不认识了。
*/
public class VarTest03{ //类体	
	
	//声明变量
	int m = 100;
	
	public void m1(){
		int m = 200;//该m不是上面所定义的m,这个m为局部于m1方法中的局部变量
		System.out.println(m); //200 
	}
	
	public static void m(){//这里的m为方法名,它不同于变量,可以同变量同名
		
		int k = 10;
	}
	
	
	public static void main(String[] args){
		
		int i = 10;
		System.out.println(i);
		
		//Error
		//无法访问m方法中的k变量.
		//System.out.println(k);
		
		//for循环
		/*
		for(int j = 0; j < 10; j++){
			System.out.println(j);
		}
		
		//Error,j变量是属于for循环的。
		System.out.println(j);
		*/
		
		//j的作用域从此开始直至main方法结束,这里的j同上面for中的j不同。
		int j;
		
		for(j = 0; j < 10; j++){
			System.out.println(j);
		}
		
		System.out.println(j);

	}
}

#变量初始化(Variable Initialization)与使用

  • 在定义局部变量和成员变量时可以用赋值语句进行初始化。如:

    int i=1

    1

  • 在相同作用域里不能定义同名的局部变量

  • 成员变量的名字可以和成员方法的名字同名

  • 局部变量没有初始化,不可使用;成员变量没有初始化,则系统自动初始化(0,null,false),所以成员变量定义后,未显式初始化,也可使用

#final variable

可以把某个变量定义为值不可改变的变量,这种final变量的值一旦得到第一个值以后就不能再改变了。它的定义方式为在变量定义前加上关键字final,如:

final int aFinalVar = 0; 

1

上面的语句定义了一个final变量,并且同时初始化了它,之后再改变它的值,就会出现编译错。
如果需要,可以推迟final局部变量的初始化(注意是局部变量),如:

final int blankfinal; 
. . . 
blankfinal = 0; 

1
2
3

一个final局部变量定义了但是没有初始化,称为:blank final。

#表达式(Expressions)

expression 就是一系列操作数及运算符连接起来的式子,单独一个常量、变量、方法也均可以看作一个表达式,所以说一个普通的表达式可以看作由子表达式组合而成。

表达式有两方面含义:执行计算和返回结果。有一类表达式为常量表达式,在编译时就计算值,如:

true
(short)(1*2*3*4*5*6)
Integer.MAX_VALUE / 2
2.0 * Math.PI
"The integer " + Long.MAX_VALUE + " is mighty big."

表达式运算结果的值和类型依赖于运算符和操作数的类型。表达式的计算顺序依赖于运算符的优先级,优先级( Precedence )是指运算符计算的优先顺序。除了‘=’, ‘==’ 和 ‘!=’可用于对象以外,其它所有的运算符只支持简单类型。另外, String 类支持 ‘+’ 和 ‘+=’,表示字符串的连接运算;

#Java运算符(Operators)

#Java运算符的分类

根据运算符所能够进行运算的操作数的个数,我们可以把运算符分为:一元运算符、二元运算符、三元运算符。通常一元运算符的优先级最高,三元运算符的优先级最低,二元运算符的优先级处于中间。

根据运算符的功能我们大致可分为赋值运算符、算术运算符、逻辑运算符、关系运算符、位运算符及其他运算符等。

有些运算符会改变它的操作数的值,比如所有的赋值运算,自增自减运算等,这种现象称为副作用。

#赋值运算(Assignment)

赋值运算符为‘=’,它可以同其他的二元运算符组合为复合赋值运算,这一点同C相似。

赋值号左边必须变量,赋值号右边可以是一般意义上的表达式,它的含义是将赋值号右边的表达式的计算结果放在赋值号左边的变量中存储起来。因为赋值也是运算,所以说赋值运算也有运算结果,它的结果同赋值号左边变量中的值一致,这一点很重要。比如:a = 3 ,这个赋值运算表达式的值为3。

另外,大家考虑 a = b = c = 3 这个表达式的计算意义,它的计算过程不是:3放入c,再把c的值放入b,b的值再放入a,而应该考虑作 a = (b = (c = 3))),即是,b 中的值是(c = 3)这个子表达式的值,而不是c的值。

对于基本类型的赋值,为值的复制,如: a = b;把b的值复制到a,a、b中所保存的为相等值的两个不同副本,在该赋值运算之后,如果修改a的值不会影响到b,同理,修改b的值,也不会影响到a的值。

如果赋值号右边为引用类型的结果,我们可以类比C语言中的指针。例如:如果a,b是引用类型的变量,那么a = b ,实际上a和b引用的是同一个对象。如果我们改变a或者b的值,这时a和b就不再引用相同的对象了。但是如果我们通过a或者b改变的是它们所引用对象中的值,因为a、b引用的是同一个对象,所以不管通过a还是b来观察这个对象,所看到的结果都是一致的。比如,我们把a、b看作两个男生,如果b把自己暗恋的女生介绍给a认识,结果a也暗恋上了该女生,那么a、b就暗恋同一个女生,那么如果b送给女生一本《Java语言程序设计基础》,a、b是不是同时都知道该女生有了这本书。但是如果b移情别恋了,a、b就不再有相同的暗恋对象,不管a、b给自己的暗恋女生送什么,对对方都没有影响。如下例:

class Girl{ //女生类,女生都有一本书《计算引论》
	String book = "计算引论";
}

class Boy{ //男生类,每位男生默认情况下没有女朋友
	Girl girlFriend = null;
}

public class Test{
	public static void main(String[] args){
		//两位女生
		Girl g1 = new Girl();
		Girl g2 = new Girl();

		//两位男生
   		Boy b1 = new Boy();
		Boy b2 = new Boy();

		//b1暗恋g1
		b1.girlFriend = g1;

		//b1把自己的暗恋女生介绍给了b2,b2也暗恋上了g1,他们的暗恋对象都是g1
		b2.girlFriend = b1.girlFriend;

		//b1送给g1女生一本《Java语言程序设计基础》
		b1.girlFirend.book = "Java语言程序设计基础";
			
		//通过b2来看,b2暗恋的女生也有一本《Java语言程序设计基础》,
		//奇怪吗?不奇怪,本来就是同一位女生
   		System.out.println(b2.girlFriend.book);

   		//b1移情别恋g2
		b1.girlFriend = g2;

		//b1的暗恋女生有什么书呢?
   		System.out.println(b1.girlFriend.book);

		//痴情的b2的暗恋女生有什么书呢?
   		System.out.println(b2.girlFriend.book);

	}
}

关于复合赋值,它的一般形式为: a Y= b,这里Y代表某种二元运算符,它的等价形式为 a = a Y (b),这里b的左右一定要有小括号,为什么呢?我们考虑这个表达式: a *= b + 2,我们知道该表达式的含义为先计算 b + 2,然后将该值乘以a,最后结果放在a变量中,如果它的等价形式中没有小括号,是不是等价形式就成为: a = a * b + 2,还同原来的表达式含义一致吗?

#算术运算符(Mathematical operators)
运算符使用描述
+op1 + op2二元运算,表示加法,如果其中一个或两个操作数为字符串,则表示字符串连接运算
-op1 - op2二元运算,表示减法
*op1 * op2二元运算,表示乘法
/op1 / op2二元运算,如果两个操作数均为整数,表示整除运算,只要有一个为浮点数,则表示除法
%op1 % op2二元运算,表示除法中的余数,也叫模运算,运算结果的正负取决于%左边的数的符号,与%右边的数的符号无关。如:(-5)%3=-2,而5%(-3)=2。
++op1一元运算,表示符号,如果操作数 op 是byte, short 或者 char,会转换为 int
--op1一元运算,取相反的符号,即原来为负,结果为正,原来为正,结果为负,同样, 如果操作数 op 是byte, short 或者 char,会转换为 int
++++op1一元运算,先将op1增1,然后把增1后的值作为++op1的计算结果
++op1++一元运算,先把op1的值取出作为op1++的计算结果,再把op1增1
–op1一元运算,先将op1减1,然后把减1后的值作为–op1的计算结果
op1–一元运算,先把op1的值取出作为op1–的计算结果,再把op1减1
#关系运算符(Relational operators)

关系运算的结果为boolean值,均为二元运算。六个关系运算符为 小于(<), 大于(>), 小于等于 (<=), 大于等于 (>=), 等于 () 和 不等于 (!=),它们均为二元运算符。其中, == 和 != 的操作数可以是boolean,其它关系运算符的操作数不可以是 boolean。 == 和 != 对于引用是比较两个引用是否为同一对象(那两个男生的暗恋对象是不是一个女生),而不是比较对象是否包含相同内容;在用于比较浮点数时,由于浮点数在计算机中的表示是不精确的,所以我们看起来一样的值,可能计算机比较的结果是不同的,尤其要小心。因此,我们在比较浮点数的相等或不等的时候,我们通常是用一个精确范围来进行比较,而不用与!=来进行比较,用数学的写法即是 |a - b| < Δ ,这里Δ是一个充分小的一个正数,只要a、b的差值落在Δ范围内即认为是相等的。

#逻辑运算符(Logical operators)

与 (&&), 或 (||) and 非 (!) 的操作数是逻辑值,结果依赖于参数的逻辑关系。非为一元运算,其它两个为二元运算。
在进行逻辑运算的时候,如果某个时刻能够得到整个表达式的值时,则计算到此为之,其余部分的表达式不再计算,这种现象称为短路。比如:(a >b) && (c++ > d) && (e >f),如果 a > b 的值已经是false,后面的(c++ > d)和(e > f)均不再计算了,但是,结合运算符的副作用,你就会发现,根据a、b之间的大小关系,该表达式计算完成以后,c的值可能增1,也可能不增1,这种情况,大家要小心。

运算符使用描述
&&op1 && op2如果两个操作数都是true,返回true,否则为false
||op1 || op2如果两个操作数都是false,返回false,否则为true
!!op1取反,true转为false,false转为true
#位运算操作符(Bitwise operators)

按位与 (&),按位或 (|),按位异或 (^),按位非 (~),对操作数的每一位进行运算。按位非为一元运算,其它为二元运算。
按位与、或、异或可以和 = 组合使用: &=, |= 和 ^= (因为 ~ 是一元操作,所以不能和 = 组合使用)。
boolean 类型值可以进行按位与、或、异或,但不能执行执行按位非。
对于 boolean进行按位运算不会发生短路。

运算符使用描述
&op1 & op2两个操作数如果是逻辑类型,就是逻辑与运算,如果两个操作数是数字,执行按位与运算
|op1 | op2两个操作数如果是逻辑类型,就是逻辑或运算,如果两个操作数是数字,执行按位或运算
^op1 ^ op2两个操作数如果是逻辑类型,就是逻辑异或运算,如果两个操作数是数字,执行按位异或运算
~~op1按位取反
#移位运算符(Shift operators)

移位运算符作用于整数类型。分别为左移 (<<) 、带符号右移 (>>)、无符号右移( >>>)。均为二元运算。我们在进行移位运算的时候,我们要将运算符左边被移位的整数以二进制补码数考虑,运算符右边的操作数指定移动的二进制位数。

  • 左移
    • 所谓左移是指,被移位的整数按二进制数考虑,整体向左移动按第二个操作数的要求的二进制位数,左边移出的二进制位舍去,右边空出的位以0填补。每左移一位,相当于×2。
  • 无符号右移
    • 所谓无符号右移是指,右边移出的二进制位舍去,左边空出的若干二进制位均以0填充。被移位数原来如果是负数,移位后的值会成为正数。
  • 带符号右移
    • 所谓带符号右移是指,右边移出的二进制位舍去,左边空出来的二进制位用表示符号的0(表示正)或者1(表示负)来进行填充,比如,如果被移位整数原来是负数,左边空出的若干位均以1填充,如果被移位整数原来是正数,左边空出的若干位均以0填充。每右移一位,相当于整除一次2。

如果被移位的操作数是char、byte、或 short,将先把操作数的类型转变为 int, 结果类型自然就是 int。不管移位运算符的第二个操作数有多大,它的二进制形式的低五位值为移位的位数,比如:123 << 345,大家不要以为是将123左移345位二进制位,而是左移25位,这是因为345转化为二进制数为101011001,它的最右边5位为11001,其值为25,所以移位的位数为25位。

如果被移位的操作数是long类型,不管移位运算符的第二个操作数有多大,它的二进制形式的低六位值为移位的位数。这是为什么呢?

注意:移位操作时不会改变操作符左边的原始数值,比如 a = 10; b = a << 2; 这里b中保存的是移位的结果,而a的值保持不变,依然是10。

#其它运算符
  • 条件运算符
    形式如下: boolean-exp ? value0 : value1,如果 boolean-exp 结果为 true, 则取value0 的结果为整个表达式的结果,如果 boolean-exp 结果为false, 则取value1的结果为整个表达式的结果。
  • 逗号运算符
    形如: exp1,exp2,exp3 ,最后一个exp3为整个表达式的结果值,这种形式的表达式只用于for语句中。
  • 针对引用类型的操作符
运算符使用描述
.op1.op2引用op1的成员op2,大家可以理解做of,或者汉字“的”
newnew op1创建一个新的对象或者数组,op1为一个引用类型
instanceofop1 instanceof op2判断op1的类型是否是op2,op2为一个引用类型的类型名

#运算符的优先级(Precedence)

如下表:

运算符优先级结合性备注
. [] ()1左结合
++ – - ! ~2右结合均为一元运算符
new (type)(type) 为类型的强制转换
* / %3左结合
+ -4左结合
<< >> >>>5左结合
< <= > >= instanceof6左结合
== !=7左结合
&8左结合
^9左结合
|10左结合
&&11左结合
||12左结合
?:13右结合
=及其他复合赋值14右结合

#其他有关运算的问题

  • 字符串的连接

    在Java中 + 可以连接两个字符串。在表达式中,如果 + 两边有一个为String, 那么该运算就是字符串的连接运算,如:

    int x = 0, y = 1, z = 2;
    String sString = "x, y, z ";
    System.out.println(sString + x + y + z);
    

这里,Java 根据从左至右的计算顺序,第一个 + 为字符串连接,它的结果为字符出,所以第二个 + 也为字符串连接运算,第三个也是。依次把 x, y, 和 z 转换为 String并连接在一起,输出结果为 sString012。 java System.out.println(x + y + sString); 这里, Java根据从左至右的计算顺序,第一个 + 好左右均为整数,所以先把x和y相加,第二个 + 的右边为String类型,所以把 x + y 的结果转换为 String ,再连接起来,输出结果为: 1sString。

  • 数据在运算时发生的类型转换
    各种基本类型的混合数据在进行算术运算或位运算的时候,最终会得到一个统一类型的结果值。转换的基本原则是最低类型为int,向参与运算的最高类型靠。所谓最低类型为int是指,所有参与运算的整数类型byte、short、char都会先将值转换为int类型,如果有位数宽于int类型的数据,则均向该最高类型靠。如下表:

    结果数据类型操作数类型
    int操作数类型可以是byte、short、char、int,但不能有宽于int类型的操作数
    long操作数中至少有一个为long类型,但不能有高于long类型的操作数
    float操作数中至少有一个为float,但不能有高于float类型的操作数
    double操作数中至少有一个为double

    凡上表中发生的类型转换均为自动转换,有的时候需要我们强制将某种类型转换为另外一种类型,通常是把高(位数宽的)类型转换为低(位数窄的)类型,它的转换形式为:(type)exp ,比如:

    long i= 200;
    int j=(int)i;
    

    该例将 i 的值(注意是 i 的值,不是 i 这个变量本身,i 的类型依然是 long 类型)强制转换为 int 类型。
    在这种高类型转换为低类型的情况下,Java系统是将高类型的高字节舍去,这有可能造成转换后的值同原来的值不一致,这是要注意的。如图:
    img
    Java 中boolean 不可以进行任何类型的转换,其它的任何基本类型之间都可以进行类型转换。

    对于引用类型的类型转换,待我们学到相关知识的时候再介绍。

    下面为一些特别情况,需要我们留心及体会的:

    byte x = 1, y = 2, z;	/* ok,因为1,2未超出byte的范围,记忆一个规则:	如果一个整数没有超出byte,short,char的取值范围,	可以直接将这个整数赋值给对应的byte,short,char类型变量 */
    
    y=x;//ok,只是赋值运算,不是算术或位运算
    z=x+y;//error,因为此时发生了算术运算
    x=130;//error,超出了byte的范围
    x=1+2;	/* ok,因为1+2这个表达式是常量表达式,它的计算是在编译时就算出了值3,而不是在运行时计算,而3未超出byte的范围*/
    
    x=y+1;//error,这个式子要在运行时计算
    z=(byte)(x+y);//ok,必须强制转换
    x+=y;//ok,复合赋值不需要强制转换
    float a=2.0;//error,因为2.0为double类型
    
  • 基本类型的封装类
    自动装箱(auto boxing)和自动拆箱(auto unboxing)

    Integer iInt=10; //装箱,赋值号右边是基本类型int,而左边引用类型,在其它情况下,属于赋值不兼容的,这里可以
    int i=iInt; //拆箱,赋值号右边是引用类型,而左边是基本类型,在其它情况下,属于赋值不兼容的,这里可以
    

    1
    2

基本数据类型数值同字符串之间的转换,每个包装类中(除了Character)都提供了parseXXX(String s)方法,比如: int i = Integer.parseInt("123"); 它的作用是将"123"转换为整数123。

#语句(Statements)

Java语句构成Java的基本执行单元。

#Java语句的分类

在Java语言中,可以将语句分为表达式语句、定义语句、控制语句。

  • 表达式语句
    下面的表达式后跟 “;”,构成表达式语句
  • 赋值表达式
  • ++ 或 –
  • 方法调用
  • 创建对象
  • 定义语句
    用于定义变量的类型,比如:double aValue = 8933.234;
  • 控制语句
    用于控制语句的执行流程,比如:if语句、for语句等

语句还可以分为简单语句和复合语句

  • 简单语句

    上面的表达式语句和定义语句属于简单语句,虽然程序的书写在语法上允许一行多条简单语句,但是,我们为了程序清晰起见,我们建议每行最多写一条语句。比如:

    argx++;      //推荐
    argc--;       //推荐
    argx++; argc--;    //不推荐
    
  • 复合语句(也叫块 block)

    是由大括号括起来的零(含)个以上的语句,块可以用在语法上只允许单独语句的地方,如:

    if (Character.isUpperCase(aChar)) { //左大括号应该在行尾
    	System.out.println("The character " + aChar + " is upper case."); 
    }  //注意此处没有分号,右大括号独自占一行
    else { 
    	System.out.println("The character " + aChar + " is lower case."); 
    } //此处也没有分号
    

程序的执行流程分为:顺序结构、分支结构、循环结构

语句(statement) 要么是跟上分号的简单语句,要么是复合语句(块)。如无流程控制语句,程序的执行是从头至尾顺序执行的,这就是基本的顺序结构。通过流程控制语句,可以选择执行某个块,也可反复执行某些块。

#控制语句

#分支语句
#if语句

if 语句是基本的流程控制语句,else 部分根据程序的具体情况为可选部分

if (Boolean-expression)
	statement//注意此处语法上为一条语句,如果在功能上一条语句不能完成功能,则需要使用复合语句

if (Boolean-expression)
	statement //注意此处语法上为一条语句,如果在功能上一条语句不能完成功能,则需要使用复合语句
else
	statement //注意此处语法上为一条语句,如果在功能上一条语句不能完成功能,则需要使用复合语句

上述 if 语句是语法上的结构,在实际写 if 语句时,考虑到程序的清晰性,我们应写成:

if ( Boolean-expression ) {
	statement//不管此处为一条语句还是多条语句
}

if ( Boolean-expression ) {
	statement //不管此处为一条语句还是多条语句
} else  {
	statement //不管此处为一条语句还是多条语句
}

或者

if ( Boolean-expression1 ) {
    statement //不管此处为一条语句还是多条语句
} else if ( Boolean-expression2 ){
     statement //不管此处为一条语句还是多条语句
} else {
    statement //不管此处为一条语句还是多条语句
}

上面写法的好处在于,如果需要在 if 或者 else部分增加功能,语句的格式不需要改动很多,而且使得程序结构比较清晰,从而免除了很多潜在的错误。

对于简单的if语句可以写在一行,这时可以写作:

if (condition) body();

但不要写作

if (condition)
	body();  // 不好!

对于多重if-else语句,else总是同最近的没有匹配的if相匹配,例如:

if ( x > 5 )
	if ( y > 5 ) 	
	System.out.println( "x and y are > 5" ); 
else 
	System.out.println( "x is <= 5" ); 

在本例中,程序员视图让 else 同 if(x > 5) 相匹配,但这么写是办不到的,我们建议写成下面的形式:

if ( x > 5 ) { 
	if ( y > 5 ) {
		System.out.println( "x and y are > 5" );
	} 
} else {
     System.out.println( "x is <= 5" );
}

再看一个例子:

if ( grade >= 60 ) 
	System.out.println( "Passed" ); 
else  
	System.out.println( "Failed" );
	System.out.println( "You must take this course again." ); //程序员希望该语句在else部分执行

这种写法依然是错误的,正确的写法是:

if ( grade >= 60 ) {
	System.out.println( "Passed" ); 
} else { 
	System.out.println( "Failed" ); 	
	System.out.println( "You must take this course again." ); 
} 

再一个例子:

if ( grade >= 60 ) 
	System.out.println( "Passed" ); 	
	System.out.println( "You passed this course." ); //程序员希望该语句在if部分执行
else  
	System.out.println( "Failed" ); 	

正确的写法如下:

if ( grade >= 60 ) {
	System.out.println( "Passed" ); 	
	System.out.println( "You passed this course." ); 
} else  {
	System.out.println( "Failed" ); 	
}

下面的代码哪个地方错了?

if ( grade >= 60 ) {
	System.out.println( "Passed" ); 
}else { 
	System.out.println( "Failed" ); 	
	System.out.println( "You must take this course again." ); 
}

是的,在else前面多了一个分号,这个分号就割裂了if-else语句,是的else无法匹配if,造成语法错误。

#switch语句

它的语法形式为:

switch(integral-selector) {
	case integral-value1 : statement;;[break;]
	case integral-value2 : statement;;[break;]
	case integral-value3 : statement;;[break;]
	case integral-value4 : statement;;[break;]
	case integral-value5 : statement;;[break;]
	// ...
	[default: statement;;[break;]]
}//of switch

该语句的执行流程是,计算integral-selector的值,一旦该值同某个case后面的integral-value相等,则从该case后面的语句开始执行,直至遇到break或者执行完switch语句中的最后一条语句。default表示,当integral-selector的值不同任何一个case后面的值相等,则执行default后面的语句,default可以在switch语句中的任何位置,也可以没有。

其中integral-selector的值可以为char、byte、short、int、Character、Byte、Short、Integer等类型,也可为枚举类型

我们考虑下面的案例:

需求:
	1.系统给定学生的成绩,成绩可以带小数。[0-100]
	2.编写程序根据学生的程序判断学生成绩等级:
		[90-100]  优秀
		[70-90)	良好
		[60-70)	及格
		[0-60)	不及格
		
	以上程序只允许使用switch

解决方案:

public class SwitchTest{
	
	public static void main(String[] args){
		
		//假定成绩是合法.
		double score = 95.5;
		//将score取整,并整除10
		int grade = ((int)score)/10;
		
		switch(grade){
				
			case 9:case 10://在大于等于90,小于等于100时,均为优秀
					System.out.println("优秀");
					break;//中断switch的执行,以免执行到case 7后面的语句
			
			case 7:case 8://在大于等于70,小于90时,均为良好
					System.out.println("良好");
					break;
			
			case 6://在大于等于60,小于70时,均为及格
					System.out.println("及格");
					break;
			
			default://上述情况都不满足的时候,表示成绩小于60,为不及格
					System.out.println("不及格");
					break//虽然此处的break看起来是多余的,但是我们仍然建议大家加上该break
		}
		
	}
}
#循环语句(Iteration)

Java语句的循环语句有while、 do-while 、 for 以及 foreach语句, 其中前三个的使用方式同C是一致的, foreach语句用于遍历数组、集合等操作,它的格式,我们在学习相关内容的时候再学习。

  • while 循环的形式为

    while(Boolean-expression)
    	statement
    

建议写为
java while(Boolean-expression){ statement } 空的 while 语句为: java while (condition);

  • do-while 循环的形式为

    do
    	statement
    while(Boolean-expression);
    

建议写为
java do{ statement } while(Boolean-expression); while、 do-while 均是条件为真时循环,它们唯一的不同在于do-while 的循环语句至少执行一次,而while的循环体可能一次也不执行。实际应用中,很少使用 do-while 。while循环体中一定要有改变循环条件的语句存在,这样才可以保证循环能够终止。

  • for循环的形式为

    for(initialization; Boolean-expression; step)
    	statement
    

建议写为: java for(initialization; Boolean-expression; step){ statement } 空的 for 语句为: java for (initialization; condition; update); for 先执行一次初始化(initialization)部分,然后执行条件测试Boolean-expression;,每次循环体执行之后,再执行 “step” 部分,initialization、Boolean-expression 或者 step 均可为空,但是分号不能缺少。initialization、step 表达式中可出现逗号表达式。
java for(int i = 1, j = i + 10; i < 5; i++, j = i * 2){//i,j的作用域只在循环体中有效 System.out.println("Count is: " + i); } 我们来看一个打印九九乘法表的示例: ```java /* 使用嵌套的for循环打印九九乘法表

	1*1=1
	2*1=2 2*2=4
	.......
	9*1=9...............9*9=81
	
*/
public class ForTest03{

	public static void main(String[] args){
	
		for(int i=1;i<=9;i++){
		
			for(int j=1;j<=i;j++){
				System.out.print(i + "*"+ j +"=" + (i*j) + " ");
			}
		
				//一行结束换行
			System.out.println();
		}
	
	}
}
```

while(true) 和 for(;😉 都是无穷循环。

#break和continue

在循环语句中可以使用break 和 continue, break 不再执行循环体中其余部分并退出其所在的那层循环, break还可以用在switch语句中,用于结束switch的执行。continue 结束它所在的当前循环,测试循环条件决定是否执行下次循环。

  • break示例:

    /*
    break;语句:
    1.可以用在switch语句中,结束分支语句.
    2.break;语句可以出现在循环当中,默认情况下结束离它最近的一个循环.
    */
    public class BreakTest01{
    
    	public static void main(String[] args){
    	
    		for(int i=0;i<10;i++){
    			System.out.println(i);
    			if(i==5){
    				break; //只是结束离它最近的一个循环.
    				//return; //结束的是main方法.
    			}
    		}
    
    		System.out.println("Hello World!");
    	
    	}
    }
    
  • continue示例:

    class ContinueDemo {
     		public static void main(String[] args) {
    
       		String searchMe = "peter piper picked a " + "peck of pickled peppers";
       		int max = searchMe.length();
       		int numPs = 0;
    		//在searchMe中查找p字符,每找到一个numPs自增计数
       		for (int i = 0; i < max; i++) {
         		// interested only in p's
       	  		if (searchMe.charAt(i) != 'p')
               		continue;
    
           		// process p's
           		numPs++;
       		}
       		System.out.println("Found " + numPs + " p's in the string.");
    	}
    }
    
  • 标号

    标号label 是个后跟冒号的标识符,如:

    label1:
    

Java中标号只能用在循环前,用于标识该循环。对于嵌套循环而言,我们使用标号可以指定break和continue退出或者继续哪层循环。

```java
class ContinueWithLabelDemo {
	public static void main(String[] args) {

   		String searchMe = "Look for a substring in me";
   		String substring = "sub";
   		boolean foundIt = false;

   		int max = searchMe.length() - substring.length();

		test:
   		for (int i = 0; i <= max; i++) {
       		int n = substring.length();
       		int j = i;
       		int k = 0;
       		while (n-- != 0) {
           		if (searchMe.charAt(j++) != substring.charAt(k++)) {
               		continue test;
           		}
       		}
       		foundIt = true;
           	break test;
	 	}
   		System.out.println(foundIt ? "Found it" : "Didn't find it");
	}
}
```

总结一下: 1. 不带标号的continue回到其所在的循环开始,并进行下次循环 ; 2. 带标号的continue来到标号指定的循环,并进入循环; 3. 不带标号的break 退出其所在的循环; 4. 带标号的break 退出标号指定的循环; 5. break 和continue 一般在嵌套循环里用于退出多重循环。

#方法

方法为类的一个组成部分,它的功能定义只能放在类中。方法用于完成某种特定功能,某些方法还会有计算结果。方法的一般构成:修饰词、方法名、参数表、返回值(方法的计算结果)和方法体,形式如下:

修饰词 returnType methodName( /* Argument list */ ) {
  /* Method body */
}
  • 修饰词用于表示该方法的性质,比如public等等
  • Argument list 为类似于int a,int b这种形式,称为形式参数表,参数之间由逗号隔开,不能是int a,b 参数表表明参数的类型和顺序。 方法名和参数表唯一标识了方法。
  • returnType可以是任何类型,另外还可以是void,表示该方法没有计算结果。对于一个类的构造方法,没有返回值类型。
  • Method body 为方法的功能代码,在这里定义方法的执行功能

#return语句

return的功能是结束一个方法,程序的执行回到调用该方法的代码中。如果方法有返回值,则return会把其后的表达式的值带出该方法,就是该方法的计算结果,如果没有返回值,既方法的返回值类型为void,则return后什么都不跟,只是结束方法的执行。语法为:

return [表达式];

return后面的表达式一般不要加小括号,除非必须用,如:

return (10); //不要这么写
return 10;   //应该这么写

示例:

static int test(int testval, int target) {
	if (testval > target){
		return +1;
	} else if (testval < target) {
		return -1;
	} else {
		return 0; // Match
	}
}

该例中的test方法有三个出口,每个出口带出一个值。

注意:

  • 如果返回类型为void, return 的作用只是退出方法,没有返回值。

  • 对除void返回类型以外,方法执行的最后一条语句必须是return。如果方法的返回类型为void,则执行的最后一条语句不必是return,当然也可是return,但此return后没有表达式。

  • 对于返回值类型为void的方法,如果有多个执行出口,则通常需要使用 return; 结束方法的执行。

  • 简单示例:

    boolean flag() { return true; } //return后必须有值
    float naturalLogBase() { return 2.718f; }
    void nothing() { return; } //该方法返回值类型为void,return后面没有值,只是用于结束该方法
    void nothing2() {} //该方法返回值类型为void,没有使用return,也能结束执行
    

#方法的调用

方法的调用形式:

[对象名(或者类名).]方法(实参表);

如:假如f()无参数,返回值类型为 int. 可以如下调用:

long x = a.f();

这里f的返回值类型和x兼容(赋值兼容就是指赋值号右边的值的类型宽度不得大于左边变量的类型,比如本例中如果x的类型位byte,则就会出错)。

实参表为传递给方法的参数,各参数之间用 “,”隔开,如下:

int storage(String s) {
	return s.length() * 2;
}

这里s为形参,在使用storage的时候:

int doubleLength = storage("abc");

这里 “abc” 就是实参,对应方法定义中的形参s。

形式参数(形参)和实际参数(实参)的区别:形式参数为定义方法时的参数,实际参数为调用方法时的参数。如:定义数学函数f(x)=3x+2,这里x为形参,而f(3),这里3为实参。

在分析方法的调用时,我们可认为在调用方法前,有个将实参值赋值给形参的过程。**切记:**在结束方法的执行时没有相反的将形参值赋值给实参的过程。如上例,我们可以这么分析storage的功能:

s = "abc";//将实参"abc"赋值给形参s,然后再执行方法体中的代码,本例中就是下条语句
return s.length() * 2;

有一种情况,需要大家注意,如下例:

boolean test(int a, int b){
	if(a > b) {
		return true;
	}
}

该例在编译的时候会出错,img 为什么呢?这是因为 a > b的时候返回值为true,那如果 a < b 的时候呢? 因为test的返回值为boolean,test是属于必须有返回值的方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值