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

Thinking In Java笔记(第三章 操作符)

2015-04-27 21:45 232 查看

第三章 操作符

3.2使用Java操作符

操作符接受一个或者多个参数,并生成一个新值。参数的形式和普通方法调用不同,但是效果是相同的。普通的加减乘除和正负号都是和其他编程语言类似。

有些操作符可能会产生“副作用”,改变操作数的值,这些擦佐夫最普通的用途就是用来产生副作用的。使用此类操作符产生的值和没有副作用的操作符产生的值没区别。

几乎左右的操作符都只能操作“基本类型”,例外的是“=”,“==”,“!=”,这些操作符能操作所有对象。除此意外,String类支持“+”和“+=”。

3.3优先级

操作符的优先级决定了各个部分的计算顺序,Java堆计算顺序做了特定的规定。其中,最简单的规则就是先乘除后加减,如果忘记了优先级的顺序,应多用括号来标识执行的先后顺序。例如如下两个语句:

a = x + y - 2/2 + z;
b = x + (y - 2)/(2 + z);


两个计算意义就不同。

3.4 赋值

赋值运用操作符“=”,意思是将右值复制给左值。右值可以是任何的常数、变量或者表达式(要求表达式产生一个值)。但是左值必须是一个明确的,已命名的变量。可以a = 4,但是不能4 = a;

对基本类型的赋值很简单。基本类型直接存储了实际的数值,而不是指向了一个对象的引用,基本类型之间a=b,即b的值付给了a,改变a的数值b不受影响。

但是在给对象“赋值”的时候,对一个对象进行操作的时候,我们真正操作的是对象的引用。实际上只是将对象的地址在两个引用之间传递,如果在同一类型的两个引用之间a=b,改变a指向的对象中的值,b也会受影响,实际上是他们俩指向了同一块对象内存空间,就好像这个对象内存空间有两个名字一样。

class Cat {
    public int age;
}

public class Test {
    public static void main(String[] args) {
        Cat hello = new Cat();
        Cat kitty = new Cat();
        hello.age = 1;
        kitty.age = 2;
        //两个引用之间的赋值,实际上指向了同一块内存空间,也就是kitty先指向的那块新建的内存空间
        hello = kitty;
        hello.age = 3;
    }
}


上面的例子中,新建了两个对象,用hello和kitty两个引用指向了这两个对象,接着执行了hello = kitty;这条语句,用hello这个引用指向了kitty指向的那块内存,更改了age的值,这时候就相当于给kitty这只猫取了另外一个名字叫hello,他俩实际上说的是同一个东西~。而之前hello指向的那块内存实际上丢失了,会被Java回收器回收。

如果只是想让这两个指向的对象具有相同的age,应该写成这样 hello.age = kitty.age;要记住直接对基本类型操作是安全的,是对数值直接的操作。

3.5算术操作符

Java基本算术操作符与其他大多数程序设计语言是相同的。其中包括:+、-?*、/、%。

需要注意的是整数之间的除法(/)会直接去掉小数位,而不是四舍五入的取整。

Java也使用一种来自C和C++的简化符号同时进行运算和赋值操作,表示形式就是操作符后面紧跟一等号,如“+=”。a+=4表示a = a + 4;

3.5.1 一元加、减操作符

也就是一元减号“-”和一元加号“+”。例如语句:

x = - a;
x = a * -b;


编译器会自动的识别成为 x = a * (-b);一元减号用于转变数据的符号,而一元加号只是为了和一元减号对应,其唯一的作用仅仅是将较小类型的操作数提升为int。

3.6自动递增和递减

和C类似,Java提供了大量的快捷运算。有时候能使代码更容易阅读,但有时候会使代码难以阅读。

自增“++”和自减“–”是两种相当不错的快捷运算,前者意为“减少一个单位”,后者意为“增加一个单位”。

两种操作符都有“前缀式”和“后缀式”,“前缀式”表示“++”位于操作数之前,例如“++a”,先计算再生成值,而“a++”是先生成值,再计算。

a = 1;
x = a++;
//执行完上面一条语句,a的值为2,x为1
y = --a;
//在这里a的值变为1,y的值也为1;


这两个操作符时除了涉及赋值的操作符之外,唯一具有“副作用”的操作符,即会改变操作数,而不仅仅是使用自己的生成值。

3.7关系操作符

关系操作符生成的是一个boolean(布尔)类型的结果,计算的是操作数的值之间的关系。为真则时true,为假则是false。

3.7.1对象的等价性

下面的例子:

public class Test{
    public static void main(String[] args) {
        Integer n1 = new Integer(47);
        Integer n2 = new Integer(47);
        System.out.println(n1 == n2);
    }
}


输出结果为false,尽管两个引用指向的对象的内容相同,但是它们指向的对象是不相同的。涉及到比较两个对象的实质内容是否相同,应用到equals()方法,要注意基本类型不适用于equals()。若上面输出

System.out.println(n1.equals(n2));则会输出true。

但是如果是涉及到自己定义的类,例如:

class A{
    public int x;
}
public class Test{
    public static void main(String[] args) {
        A a1 = new A();
        A a2 = new A();
        System.out.println(a1.equals(a2));
    }
}


这里输出的则又变成了false,原因如下。

J***A当中所有的类都是继承于Object这个基类的,在Object中的基类中定义了一个equals的方法,这个方法的初始行为是比较对象的内存地 址(也就是==的比较方法),但在一些类库当中这个方法被覆盖掉了,如String,Integer,Date在这些类当中equals有其自身的实现,而不再是比较类在堆内存中的存放地址了。

下面是Java官方文档中对Integer类中equals的实现介绍。

equals
public boolean equals(Object obj)
Compares this object to the specified object. The result is true if and only if the argument is not null and is an Integer object that contains the same int value as this object.
Overrides: 
equals in class Object 
Parameters:
obj - the object to compare with. 
Returns:
true if the objects are the same; false otherwise.


3.8逻辑操作符

逻辑操作符与(&&),或(||),非(!)能根据参数的逻辑关系生成一个boolean值。和C、C++中不同的是:不可以将一个非boolean值当成boolean值使用在逻辑表达式中。例如if(a=b),这样类似的作为逻辑判断。

3.8.1短路

在使用逻辑操作符的时候,一旦表达式的boolean值已经确定,后续的表达式将不被再计算,比如
if(a>b && c>d && e>f)
这个表达式,如果a>b成立了,后续的两个表达式将不会再被比较。

3.9直接常量

当使用常量的时候,需要给编译器加上适当的提示,例如“float f = 1F;”等。在C、C++和Java中,二进制数没有直接常量表示方法。但是,在使用十六进制和八进制计数法时,以二进制形式显示结果将非常有用。通过使用Integer和Long类型的静态方法toBinaryString()很容易实现。如果将比较小的类型传给Integer.toBinaryString()方法,则会自动被转型为int

3.10按位操作符

按位操作符用来操作整数基本数据类型中的单个bit,即二进制位。按位操作符会对两个参数中对应的位执行布尔代数运算,最后产生一个结果。

按位操作符来源于C语言面向底层的操作,这种操作中经常需要直接操纵硬件。

如果输入位都是1,则按位“与”操作符(&)生成一个输出位1;否则生成一个输出位0;

但是两个输入位里有一个是1,则按位“或”操作符(|)生成一个输出位1,同时为0才输出0;

如果输入位某一个是1,但不全都是1,则按位“异或”操作(^)生成一个1,否则输出位为0;

按位非(~),也成为取反操作符,它属于一元操作符,输出位与输入位相反。

按位操作符(除了一元操作符(~))都可以和等号联合使用,合并为运算赋值。

我们将布尔类型作为一种单比特值对待,可以对其进行按位“与”等运算,但是不能执行按位“非”(可能是为了避免与逻辑NOT混淆)。在对boolean值进行按位运算的时候,具有和逻辑操作符相同的效果,只是不会中途出现短路现象。

3.11移位操作符

左移位操作符(<<)能按照操作符右侧指定的位数将操作符左边的操作数向左移动(低位补0)。“有符号”右移操作符(>>)按照操作符右侧指定的数字将操作数右移,移动过程中高位补位按照操作数符号来补。Java中增加了一种“无符号”右移操作符(>>>),它使用“零扩展”,无论操作数的符号,一律高位补0。是C和C++中没有的。

三元操作符也成为条件操作符,形式如下:

boolean-exp ? value0 : value1


意思就是说如果boolean-exp表达式的值为true,则三元操作符返回value0,否则返回value1。这个操作符由C语言创建。

3.13字符串操作符+和+=

这两个操作符可以用来链接字符串。C++中引入了操作符重载(operator overloading)机制,和C++相比,操作符重载在Java中更容易实现,但是由于仍然过于复杂,Java程序员不能像C++和C#程序员那样实现自己的重载操作符。

如果表达式以一个字符串开始,后续所有操作数都必须是字符类型的(编译器会自动的将双引号内的字符序列转化成字符串), 有时会出现如下的情况:

int a = 1;
String b = "hello";
System.out.println(b + a):


这也行?那是因为这是一个简单的调用方法,在本例中可以避免了Integer.toString()方法的调用。

3.15类型转换操作符

类型转换(cast)的原意是“模型铸造”。在适当的时候,Java会将一种数据类型自动转换成另一种。例如我们将一浮点变量赋一整数值,编译器会自动将int转换成float。如果需要执行类型转换,需要讲希望得到的数据类型至于圆括号内,并放在进行类型转换的值的左边。

public class Casting {
    public static void main(String[] args){
        int i = 200;
        long lng = (long)i;
    }
}


C和C++中,类型转换有时会让人头痛,但是在Java中,类型转换则是一种比较安全的操作。然而,如果要执行一种名为窄化转换(narrowing conversion)的操作(也就是说,将能容纳更多信息的数据类型转换成无法容纳那么多信息的类型),就有可能丢失信息。编译器会强制要求我们进行显示类型转换。Java允许我们把任何基本数据类型转化成其他基本数据类型,除了boolean类型之外。“类”数据类型不允许进行类型转换。为了将一种类转换成另一种,必须采用特殊的方法。

3.15.1 截尾和舍入

public static void main(String[] args) {
    double above = 0.7;
    float below = 0.4;
    float fabove = 0.7f;
    float fbelow = 0.4f;
    System.out.println((int)above);
    System.out.println((int)fabove);
    System.out.println((int)below);
    System.out.println((int)fbelow);
}


上面的输出结果都为0,因为在将float和double转型成int的时候,会对数字截尾。如果想要得到四舍五入的结果,则需要使用java.lang.Math中的round()方法:

System.out.println(Math.round(above));
System.out.println(Math.round(fabove));
System.out.println(Math.round(below));
System.out.println(Math.round(fbelow));


上面的输出结果为1,0,1,0。和四舍五入是一样的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: