java就算y与x的值,Java中容易被你忽略的细节(一)

1.Java中的条件运算符

条件运算符是"? : "是Java中唯一一个三目运算符,格式为:

表达式1 ?表达式2 : 表达式3

表达式1的类型必须是boolean类型(或者是可以通过拆箱转换为boolean类型的Boolean类型)

,当表达式1的值为true时,条件表达式的结果就是表达式2的值,为false时,结果为表

达式3的值。表达式2与表达式3的类型可以是任意类型。根据表达式2与表达式3的类型

不同,条件表达式的类型也会随之不同。具体的判断如下:

1.如果二者(表达式2与表达式3)的类型形同,条件表达式的类型为表达式2(表达式3)的类型

2.如果二者之一类型为boolean,另外一个类型为Boolean,"?:"的类型为boolean

3.如果二者之一为引用常量null,则:

1)如果另外一个为引用类型,条件表达式的类型为引用类型

2)如果另外一个为基本数据类型,条件表达式的类型为基本数据类型对应的包装类型,

即基本数据类型装箱后的类型。

4.如果二者为除boolean外的基本数据类型(或者基本数据类型对应的包装类型),则条件

表达式的类型为基本数据类型中的一种(不包括boolean)

总结:根据表达式2与表达式3的类型不同,条件表达式的类型也会不同。

2.在Java运算中,存在一些关系到顺序的计算,这些计算顺序在C/C++语言中是不确定的,

并且最后的结果也没有保障。而Java不同,Java经过编译之后,生成的是与平台无关的

字节码,并且交互对象是Java虚拟机,与底层的硬件环境无关,这些运算在Java中是

确定的。在Java中,操作数的计算顺序是从左向右的,也就是首先计算左侧的操作数,

然后再计算其右侧的操作数。操作数从左向右的计算规则与运算符的结合性无关,就算

运算符是由右向左结合的,也会在运算之前确定左侧的操作数。

符合运算符可以自动将右侧运算结果类型转换为左侧操作数的类型。

如:byte b=1;

b=b+1; //错误 因为1是int类型的

b+=1; //正确,相当于b=(byte)(b+1);

3.在Java中交换变量的三种方式:

1).int temp;

temp=a;

a=b;

b=temp;

2).a=a+b;

b=a-b;

a=a-b;

3).a=a^b;

b=a^b;

a=a^b;

/**

位异或(^)运算有这样的性质,就是两个整型数据x与y,有:

(x^y^y)=x

就是如果一个变量x异或另外一个变量y两次,结果为x.

*/

4.Java中的Switch语句:

switch表达式可以是byte,short,char,int,以及它们对应的包装类Byte,Short,Character,

Integer类型,也可以是枚举类型,String类型。

switch(表达式)

{

case 常量表达式或枚举常量名1:

语句;

......

default:

语句;

}

case语句可以有0-n个,default语句可以有0个或1个。另外任意两个case表达式的值

不允许相同,case常量表达式或枚举常量的值必须可赋值给switch表达式的类型。

switch语句处理包装类:都是将包装类型间接转换为基本数据类型处理,然后进行

case相等的比较。(包装类型拆箱为基本数据类型)

switch语句处理枚举类型:对于枚举类型,首先会在内部生成一个匿名类,该匿名类

含有一个int[]类型的静态final成员变量,数组的长度为枚举常量的个数,数组元素

的值为枚举常量的序数(ordinal方法返回的值),然后通过该数组元素的值来进行选择。

switch对枚举进行处理时,辅助的静态匿名类(含有静态成员)是由编译器生成。如果

我们自己在程序中声明匿名类,类中不允许有静态成员。

枚举类的Values方法返回该枚举类型的数组,数组包含该枚举类所有的枚举常量。每个

枚举常量都有一个序数,从0开始,依次递增,顺序与声明枚举类时枚举常量在枚举类

中出现的顺序一致。可以使用ordinal方法获得该序数,并且为数组元素依次赋值,

从1开始。

switch语句对String的处理:当switch表达式是String类型的时候,会将switch语句拆分

成两个switch语句来处理,第一个switch语句根据对象的哈希码来对一个临时变量赋值,

第二个switch语句根据该变量的值来匹配case表达式的值。

当switch类型为String类型时,将switch语句拆分为两个switch语句,分别对String对象

的哈希码及临时变量来辅助完成。

5.在Java中,使用"+"来连接两个字符串。当"+"两边的操作数是String类型时(如果只有

一个操作数是String类型,则系统也会将另外一个操作数转换为String类型),就会执行

字符串连接运算。

当使用"+"对字符串进行连接时,会创建一个临时的StringBuilder对象,该对象调用

append方法负责字符串的连接操作,然后再调用StringBuilder类的toString方法转换

成String对象。

String s1="Hello";

String s2="World!";

System.out.println(s1+s2);

可以认为实际的代码是这样的:

System.out.println((new StringBuilder()).append(s1).append(s2).toString());

当使用运算符"+"连接字符串时,如果两个操作数都是编译时常量,则在编译时期就会

计算出该字符串的值,而不会在运行的时候创建StringBuilder对象。

"+"的性能:如果只是简单几个字符串的连接,使用"+"运算符是非常方便的,但是

在循环中反复执行String对象的连接操作,性能就会变差,因此建议直接使用

StringBuilder来代替"+"的连接,这样可以省去每次系统创建StringBuilder类的开销。

6.System类的nanoTime方法:

long start=System.nanoTime;

long end=System.nanoTime();

long time=end-start;

System.out.println(time);

System类的nanoTime方法返回从某个时间开始所经历的纳秒数,这个时间可以是过去,

也可以是未来。如果是未来,则返回负数值。该方法不是系统时钟,但是可以用来

计算所经历的时间长度。

7.String类型是引用类型,String对象一经修改,就不能修改。String类是final类型的,

我们无法继承该类,并且其所有的成员变量都是私有的(private),没有提供修改私有

成员变量的公有(public)方法。

String的所有数据成员都是私有的,并且没有提供修改数据成员的方法,String内部使用

一个char类型的数组来维护字符序列,所有对字符序列的操作都是在一个新创建的String

对象上面进行的,而不是在该对象本身维护的数组上进行的。当对String对象调用某些

方法时,就会创建一个新的String对象。

String类那些看似修改字符序列的方法实际上都是返回新创建的String对象,而不是

修改自身对象。由于String对象是不可改变的,因此其具有线程安全性,可以自由地

实现共享。

8.在Java中的String类中,是使用一个字符数组来维护字符序列的,其声明如下:

private final char value[];

String的最大长度取决于字符数组的最大长度,在指定数组长度时,可以使用byte,short,

char,int类型,而不能够使用long类型,数组的最大长度就是int类型的最大值,

即0x7fffffff,十进制就是2147483647,这也就是String所能容纳的最大字符数量,获得

String对象长度的length方法返回的是int类型的,而不是long类型的。而这个最大值

只是理论上能够到达的值。

Java中的对象是分配在堆上的,堆的大小直接决定我们所能创建对象的多少,堆越大,

所能创建的对象越多。因此,我们只要改变堆的大小,就能改变所能创建对象的多少。

在Java中,默认的堆空间的最大值是256MB。

9.String字面常量的最大长度与String在内存中的最大长度是不一样的,后者的

最大长度为int类型的最大值,即2147483647,而前者根据字符(字符Unicode值)的不同,

最大长度也不同,最大值为65534(可手动修改class文件,令输出结果为65535)。

String字面常量的最大长度是由CONSTANT_Utf8_info表来决定的,该长度在编译时确定

如果超过CONSTANT_Utf8_info表bytes数组所能表示的上限,就会产生编译错误。

10.Java中equals方法与"=="的区别:

equals比较的是两个对象的内容是否相等

==:比较的是两个对象(地址)是否是同一个对象(对象地址是否相等)

equals方法是在Object类中声明的,访问修饰符为public,而所有类(除Object自身外)

都是Object的直接或间接子类,也就是所有子类的继承了这个方法。

在Object类中,equals方法实现如下:

public boolean equals(Object obj)

{

return (this==obj);

}

在Object中,equals方法与"=="运算符是完全等价的。对于String类,之所以该类可以

比较对象的内容,那是因为String类重写了equals方法,使该方法比较的是字符序列(内容)

在Java API文档中,equals的重写规则:

1.自反性。对于任何非null的引用值x,x.equals(x)应返回true.

2.对称性。对于任何非null的引用值x与y,当且仅当:y.equals(x)返回true时,

x.equals(y)才应返回true.

3.传递性。对于任何非null的引用值x,y与z,如果x.equals(y)返回true,并且y.equals(z)

返回true,那么x.equals(z)也应该返回true.

4.一致性。对于任何非null的引用值x与y,假设对象上equals比较中的信息没有被修改,

则多次调用x.equals(y)始终返回true或始终返回false.

5.对于任何非空引用值x,x.equals(null)应返回false.

在重写equals方法的同时,也必须重写hashCode方法,否则该类与其他类(如实现了Map

接口或其子接口的类)交互时,很可能产生不确定的运行结果。

11.在Java API文档中,关于hashCode方法的几点规定:

1).在Java应用程序执行期间,如果在对象equals方法比较中所用的信息没有被修改,

那么在同一对象上多次调用hashCode方法时,必须一致地返回相同的整数。但如果多次

执行同一个应用时,不要求该整数必须相同。

2).如果两个对象通过调用equals方法是相等的,那么这两个对象调用hashCode方法必须

返回相同的整数。

3).如果两个对象通过调用equals方法是不相等的,不要求这两个对象调用hashCode方法

必须返回不同的整数。

在Object类中,hashCode方法是通过Object对象地址计算出来的,因为Object对象只与

自身相等,故同一个对象的地址总是相等的,计算取得的hashCode码也必然相等。对于

不同的Object对象,地址不同,hashCode码也不会相同。

12.Java中String类中,存在一个专门的区域,用于存储String字面常量,这个区域称为

常量池。常量池由String类进行维护。

当需要将某个String对象加入常量池中时,就可以调用intern方法来完成,这个操作也

称作拘留字符串,系统会自动将String字面常量与String表达式的字符串值加入常量池

中,这也是通过调用intern方法来实现的。当String对象调用intern方法时,如果

常量池中已经含有该对象(通过equals方法来判断),则返回常量池中的String对象。如果

不存在,则将该对象加入常量池中,并返回该对象。

String对象是不可改变的,因此没必要创建两个相同的String对象。只需要将String

对象加入常量池,在需要时取出,这样既可实现String对象的共享。在程序中出现String

编译常量(String字面常量与String常量表达式)时,会自动调用intern方法,如果常量池

中含有相等的String对象,则直接返回常量池中的对象,否则将对象加入常量池中并返回

该对象。对于运行时创建的String对象(非String编译时常量),会分配到堆中,系统不会

自动调用intern方法拘留该对象,不过我们依然可以自行调用该对象的intern方法对该

对象进行拘留。

13.main方法是Java程序的入口点,由Java虚拟机自动调用。main方法的声明:

public static void main(String[] args)或者

public static void main(String args[])

main方法是公有的(public),静态的(static),返回类型为void,这样声明的原因如下:

public:main方法作为应用程序的入口,该方法是在程序启动时由Java虚拟机调用的,

所有应该声明为public.

static:如果不是静态的方法,就需要通过对象来访问。而当Java程序运行,虚拟机调用

main方法的时候,没有必要创建含有main方法类的对象。

void:main方法在退出时,并没有给系统返回退出代码,而是在需要时使用

System.exit(int status)方法来返回,所以返回类型为void.

String[] args:该字符串数组用来在运行时接收用户输入的参数,具体长度取决于用户

输入参数的个数,如果用户没有输入参数,那么args数组长度为0

(并非为null).

JDK1.5后,main方法的args参数也可以使用可变参数类型,声明如下:

public static void main(String...args).

main方法与很多方法的相似之处:

1.main方法的重载(main方法也可重载)

2.调用main方法(其他方法也可以调用main方法)

3.继承main方法(main方法也是可以由子类继承)

4.隐藏main方法(子类可以隐藏父类的main方法)

5.main方法也可以抛出异常

6.main方法也可以带有类型参数

如果子类继承类父类的main方法,并且在子类中重写声明新的main方法,也可以隐藏父

类的main方法,这个表现与隐藏其他方法是一样的。

也可以通过反射机制来调用main方法。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值