3.1  更简单的打印语句

学习编程语言的通许遇到的第一个程序无非打印"Hello, world"了,然而在Java中要写成

System.out.println("Hello, world");

我们都会感觉太冗长了,能不能简单一些呢?静态导入可以省略掉System,就像这样

import static java.lang.System.*;
public class Hello {
    public static void main(String[] args) {
        out.println("Hello, world");
    }
}

能不能再简单一些呢?像C语言那样?实际上,这里的System是类,out是System的一个PrintStream类型的静态成员,因为在System类中是这样写的

public final class System {
    // ......
    public final static PrintStream out = null;
    // ......
}

可以得到启发,自己也写一个类,然后静态导入此类,就可以像C语言那样直接输出内容了

package p1;
import static java.lang.System.*;
public class Print {
    public static void println(String x) {
        out.println(x);
    }
}

然后写一个Hello程序

import static p1.Print.*;
public class Hello{
    public static void main(String[] args) {
        println("Hello,world");
    }
}

NOTE:大家可以将自己写的打印输出类打包成jar文件,使用命令jar cvf p1.jar p1/Print.class,其中p1是包名,Print是类名,然后放在jdk目录下的lib目录中,比如D:\jdk\lib\p1.jar,然后修改环境变量,在CLASSPATH中添加%JAVA_HOME%\lib\p1.jar,这样就可以一劳永逸了,只需要import static p1.Print.*;就可以直接使用println方法了。

3.2  使用Java操作符

这里提到操作符的副作用,这篇博文讲得很详细 http://www.cnblogs.com/lazycoding/archive/2011/04/27/side-effect.html

简单说,变量X在一个表达式的运算后,如果值未变,操作符没有副作用,如果值改变了,操作符产生副作用。

3.3  优先级

优先级 运算符 结合性
1 ( ) [ ] . 从左至右
2 ! +(正) -(负) ~ ++(递增) --(递减) 从右向左
3 * / % 从左至右
4 +(加) -(减) 从左至右
5 << >> >>> 从左至右
6 < , <= , > , >= , instanceof 从左至右
7 == != 从左至右
8 &(按位与) 从左至右
9 ^(异或) 从左至右
10 |(按位或) 从左至右
11 &&(逻辑与,短路与) 从左至右
12 ||(逻辑或,短路或) 从左至右
13 ?: 从右向左
14

= , += , -= , *= , /= , %= , &= , |= , ^= , ~=,<<= , >>= , >>>=

从右向左

其实不需要刻意去记,因为万能的小括号( )可以减少错误,还使程序易于阅读。

3.4  赋值

赋值很简单,不外乎为一个变量赋值,比如

;

初学者需要注意的是左值的问题,不能写成

;
 = x;// 左值不能是直接量,常量
x +  = ;// 左值不能是表达式

3.5  算术操作符

算术操作符有 +(加), -(减),*(乘),/(除),%(取模)

int sum = 9 - 8 + 6 / 3 * 5 % 3;// sum = 2

这5个算术操作符只是数学的基本的运算符,自然会像数学那样先乘除取模,再加减。所以这个例子中,先是6 / 3 = 2,再2 * 5 = 10,再10 % 3 = 1,最后9 - 8 + 1 = 2

为了简化语句,可以使用C语言那样的简化操作符,如下

int a = 5;
int b = 6;
int c;
int d = a += b -= c = 2;// d = 9

如优先级第 14 行所述,赋值和简化操作符都是从右至左地运算的,因此上面的程序先是c = 2,再是b -= c,得出b =4,接着是a += b,得出a = 9,最后是d = a,得出d = 9。

3.6  自动递增和递减

递增操作符分为前缀递增和后缀递增,递减操作符也分为前缀递增和后缀递减,分别是

x++ 和 ++x, x-- 和 --x

前缀递增 ++x 的意思是先对 x 加1,然后再使用 x;而后缀递增 x++ 的意思是先使用 x,再对 x 加1,递减操作符也是同样的道理,比如下面的程序

int a = 5;
print(++a);
int b = 5;
print(b++);
int c = 5;
print(--c);
int d = 5;
print(c--);

再看复杂一点的程序

int x = 5;
int y = x++ + x-- + ++x + --x;// x = 5, y = 22

上面的程序相当于

int x = 5;
int y = x++;
y = x--;
y = ++x;
y = --x;

注意,不能对同一个变量使用2个或2个以上的递增递减操作符,比如下面的程序

x++--;// 错误,不能对同一个变量同时使用2个递增递减操作符

3.7  关系操作符

关系操作符有<(小于),<=(小于或等于),>(大于),>=(大于或等于),==(等于)和!=(不等于),运算的结果是一个boolean值,如下所示

int x = 7;
out.print(x < 8); // true
out.print(x <= 8);// true
out.print(x > 8); // false
out.print(x >= 8);// false
out.print(x == 8);// false
out.print(x != 8);// true

== 和 != 还可以用来比较对象,比如

public class Person {
    private int age;
    public Person(int newAge) {
        age = newAge;
    }
    public static void main(String[] args) {
        String s1 = "abc";
        String s2 = "abc";
        Person xiaoMing = new Person(18);
        Person xiaoFu = new Person(18);
        out.println(s1 == s2);// true
        out.println(xiaoMing == xiaoFu);// false
    }
}

结果出乎意料了,第 11 行是true,可第 12 行却是false!这是因为,== 和 != 比较的是对象的地址,而非对象的内容。String类型的 s1 和 s2 引用的是同样一个字符串常量,因此相等,而Person类型的xiaoMingxiaoFu虽然内容一样,但是属于两个不同的对象,就像同一班里有两个小明,虽然它们年龄相等,但是他们的基因不一样。

既然这样,那我们应该如何比较两个对象的内容呢?可以使用从根类Object继承下来的equals()方法

out.println(s1.equals(s2));// true
out.printlnl(xiaoMing.equals(xiaoFu));// false

结果又让人费解,为什么第 1 行的结果是true,而第 2 行的结果还是false?其实类String覆盖了类Objectequals()方法,而这个例子尚未覆盖它,实际上从类Object继承的equals()方法默认是这样的

public boolean equals(Object obj) {
   return (this == obj);
}

我们可以在类Person中重写(覆盖)equals()方法,然后比较两个对象,如下

public class Person {
    private int age;
    public Person(int newAge) {
        age = newAge;
    }
    public boolean equals(Object obj) {
        if (age == ((Person)obj).age)
            return true;
        else
            return false;
    }
    public static void main(String[] args) {
        Person xiaoMing = new Person(18);
        Person xiaoFu = new Person(18);
        out.println(xiaoMing.equals(xiaoFu));// true
    }
}

我们再来看看两个String对象的比较,如下

String s1 = "abc";
String s2 = "abc";
String s3 = new String("abc");
String s4 = new String("abc");
out.println(s1 == s2);// true
out.println(s2 == s3);// false
out.println(s3 == s4);// false
out.println(s2.equals(s3));// true

实际上,引用变量s1所指向的字符串常量"abc"是放在常量池的,当s2也要引用"abc"时,JVM并不会再开辟一个内存空间,而是让s2也引用已经存在的"abc",因此s1会等于s2。s3和s4就不同了,它们所引用的对象是存在于堆中,而且是不同的对象,尽管它们的内容相同,所以两者是不相等的。由于类String实现了equals()方法,使之能比较两String对象的内容,而不是地址,所以第 8 行的结果是true

3.8  逻辑操作符

逻辑操作符“与”(&&)、“或”(||)、“非”(!)能根据参数的逻辑关系,生成一个布尔值(truefalse)。

值得注意的是,&& 和 || 是短路的,比如 p&&q,如果 p 为假,则不必再计算 q,如果 p 为真,则继续计算 q,比如 p||q,如果 p 为真,则不必计算 q,如果 p 为假,则继续计算 q。

public class Demo {
    boolean flag;
    public static void main(String[] args) {
        boolean x = new Demo(false).flag && new Demo(true).flag
            && new Demo(true).flag;// false
        boolean y = new Demo(false).flag || new Demo(true).flag
            || new Demo(true).flag;// false true
    }
    Demo(boolean newFlag) {
        flag = newFlag;
        print(flag + " ");
    }
}

上面的程序,因为短路,第 5 行的结果是false和空格,第7行的结果是false true和空格

3.9  直接常量

直接引用《Java编程思想》的代码

public class Literals {
    public static void main(String[] args) {
        int i1 = 0x2f;//十六进制,小写
        out.println("i1: " + Integer.toBinaryString(i1));
        int i2 = 0X2F;//十六进制,大写
        out.println("i2: " + Integer.toBinaryString(i2));
        int i3 = 0177;//八进制,以0开始
        out.println("i3: " + Integer.toBinaryString(i3));

        char c = 0xffff;//十六进制,char类型的最大值
        out.println("c: " + Integer.toBinaryString(c));
        byte b = 0x7f;//十六进制,byte的最大值
        out.println("b: " + Integer.toBinaryString(b));
        short s = 0x7fff;//十六进制,short的最大值
        out.println("s: " + Integer.toBinaryString(s));

        long n1 = 200L;//long类型,后缀大L
        long n2 = 200l;//long类型,后缀小l
        long n3 = 200;//long类型,无后缀
        float f1 = 1;//float类型,无后缀
        float f2 = 1F;//float类型,后缀大F
        float f3 = 1f;//float类型,后缀小f
        double d1 = 1d;//double类型,后缀小d
        double d2 = 1D;//double类型,后缀大D
    }
}/*输出结果
i1: 101111
i2: 101111
i3: 1111111
c: 1111111111111111
b: 1111111
s: 111111111111111
*/

在C、C++或者Java中,二进制都没有直接常量的表示方法,不过用十六进制和八进制来表示二进制会更加直观、简洁和更易于阅读。

既然是直接常量,程序就休想修改它的值了,比如下面的代码不能编译

int x = ++5;

3.10  按位操作符

按位操作符用来操作整数基本数据类型中的单个“比特”(bit),即补码的二进制位。按位操作符会对两个参数中对应的位执行布尔代数运算,并最终生成一个结果。

按位操作符有  按位与(&)、按位或(|)、按位异或(^)和按位非(~),它们的计算方式如下

实际应用如下:

十进制7的补码:00000111
十进制9的补码:00001001
7 & 9,即 00000111 & 00001001 = 00000001(十进制1)
7 | 9,即 00000111 | 00001001  = 00001111(十进制15)
7 ^ 9,即 00000111 ^ 00001001 = 00001110(十进制14)
~7,   即 ~00000111 = 11111000(十进制-8)

按位操作符和逻辑操作符都使用了同样的符号,因此我们能方便地记住它们的含义:由于位是非常“小”的,所以按位操作符仅使用了一个字符。

按位操作符可与等号(=)联合使用,以便合并运算和赋值:&=、|=、和^=都是合法的(由于~是一元操作符,所以不存在~=)

我们将布尔类型作为一种单bit值对待,因而它会有些独特。对于布尔值,用按位操作符的话,将不再短路。我们可以对布尔值进行&、|、^,但不能~(为了避免与!混淆),其中按位异或(^)使用如下

boolean p = true;
boolean q = false;
boolean r;
r = p ^ p;// false
r = p ^ q;// true
r = q ^ p;// true
r = q ^ q;// false

3.11  移位操作符

移位操作符有左移<<有符号右移>>,无符号右移>>>,它们的运算方式如下:

x<<n;   // 将x向左移动n位,在低位补0
x>>n;   // 将x向右移动n位,若x是正数,则高位补0,若x是负数,则高位补1
x>>>n; // 将x向右移动n位,无论如何,在高位补0
// 无论对0怎么移动,结果都是0

如果对charbyte或者short类型的数值进行移位处理,那么在移位之前,它们先转换成int类型,并且得到的结果也是一个int类型的值。

“移位”可与“等号”(<<=或>>=或>>>=)组合使用

3.12  条件操作符

条件操作符的语法如下形式:

expression ? value1 : value2;

其实它相当于 if-else语句,如下

if (expression)
    value1;
else
    value2;

如果expression为true,结果为value1,否则为value2。需要注意的是,条件操作符的结合性是从右至左的,比如

int x = 2 > 1 ? 10 : 100 > 99 ? 1000 : 10000;// x = 10

先执行100 > 99 ? 1000 : 10000;结果为1000,再执行2 > 1 ? 10 : 1000;所以结果为10

3.13  字符串操作符+和+=

简单展示一下应用

String s1 = "Hello,";
String s2 = "world";
String s3 = s1 + s2;// s3 = "Hello,world"
String s1 += s2;// s1 = "Hello,world"

3.14  类型转换

学过C语言的应该都清楚类型转换是怎么回事。只要类型比int小(即bytecharshort),那么在运算之前,这些值会自动转换成int,这样一来,最终生成的结果就是int类型了。如果想 把结果赋值给较小的类型,就必须使用强制类型转换(既然把结果赋给了较小的类型,就可能出现信息丢失)。通常,表达式中出现的最大的数据类型决定了表达式 最终结果的数据类型。如果将一个float值与一个double值相乘,结果就是double;如果将一个int和一个long相加,结果为long

类型转换的应用:精确到小数点后 n 位
// 精确到小数点后3位
double pi = 3.141592653;
double x = (int) Math.round(pi * 1000) / 1000.0;// x = 3.142

[Java编程思想-学习笔记]第3章 操作符的更多相关文章

  1. [Java编程思想-学习笔记]第1章 对象导论

    1.1  抽象过程 Java是一门面向对象的语言,它的一个优点在于只针对待解问题抽象,而不用为具体的计算机结构而烦心,这使得Java有完美的移植性,也即Java的口号"Write Once, ...

  2. [Java编程思想-学习笔记]第2章 一切都是对象

    2.1  创建新的数据类型:类 通过第一章掌握了面向对象的理论后,我们知道每个对象必定属于一个类型,那么Java如何创建新的数据类型?如下程序所示: class Circle { // 属性 // 方 ...

  3. [Java编程思想-学习笔记]第4章 控制执行流程

    4.1  return 关键字return有两方面的用途:一方面指定一个方法结束时返回一个值:一方面强行在return位置结束整个方法,如下所示: char test(int score) { if ...

  4. 《Java编程思想》笔记 第三章 操作符

    1.操作符种类: 运算顺序1-7 一元操作符(单目操作符)  - 负号, + 正号,--递减,++递增 算术操作符 + - *  /  % 移位操作符  <<左移(低位补0),>&g ...

  5. Java编程思想 学习笔记1

    一.对象导论 1.抽象过程 Alan Kay曾经总结了第一个成功的面向对象语言.同时也是Java所基于的语言之一的Smalltalk的五个基本特性,这些特性表现了纯粹的面向对象程序设计方式 1)万物皆 ...

  6. Java编程思想学习(五)----第5章:初始化与清理

    随着计算机革命的发展,“不安全”的编程方式已逐渐成为编程代价高昂的主因之一. C++引入了构造嚣(constructor)的概念,这是一个在创建对象时被自动调用的特殊方法.Java中也采用了构造器,并 ...

  7. Java编程思想_笔记_第二章_一切都是对象

    第二章对于知识只是点到,会在以后章节会详细展开. 笔记的侧重会偏向记录自己知识模糊的地方.比如 xxx 很重要很难很实用,但是已经熟练使用就没有记录,而 “使用对象.成员名称来使用成员变量”,较简单而 ...

  8. Java编程思想 学习笔记11

    十一.持有对象  通常,程序总是根据运行时才知道的某些条件去创建新对象.在此之前,不会知道所需对象的数量,甚至不知道确切的类型. Java实用库还提供了一套相当完整的容器类来解决这个问题,其中基本的类 ...

  9. Java编程思想 学习笔记4

    四.控制执行流程 1.true和false 所有条件语句都利用条件表达式的真或假来决定执行路径.注意Java不允许我们将一个数字作为布尔值使用. 2.if-else 3.迭代 while.do-whi ...

随机推荐

  1. EntityFramework 7 Left Join Where Select 奇怪问题

    这篇博文纪录一下:使用 EF7,当 Linq 查询中使用 "Left Join" 语法(DefaultIfEmpty),Where Select 不同条件语法实现,出现的不同问题. ...

  2. geotrellis使用(十七)使用缓冲区分析的方式解决单瓦片计算边缘值问题

    Geotrellis系列文章链接地址http://www.cnblogs.com/shoufengwei/p/5619419.html 目录 前言 需求分析 实现方案 总结 一.前言        最 ...

  3. 使用CSS3 制作一个material-design 风格登录界面

    心血来潮,想学学 material design 的设计风格,就尝试完成了一个登录页面制作. 这是整体效果. 感觉还不错吧,结尾会附上代码 在编写的过程中,没有使用任何图片或者字体图标,全部使用css ...

  4. 12个不可不知的Sublime Text应用技巧和诀窍

    本文为您提供Sublime Text编辑器的12个技巧和诀窍,深入挖掘这个看似简洁的代码编辑器,背后所隐藏的实现各种高级功能的无限可能. 1) 选择 以下是一些Sublime Text选择文本的快捷键 ...

  5. 大数据实践-数据同步篇tungsten-relicator(mysql->mongo)

    // mongo)";digg_bgcolor = "#FFFFFF";digg_skin = "normal"; // ]]> // [导读] ...

  6. ZOJ Problem Set - 1337 Pi 最大公约数

    这道题目的关键在于怎么求两个整数的最大公约数,这里正好复习一下以前的知识,如下: 1.设整数a和b 2.如果a和b都为0,则二者的最大公约数不存在 3.如果a或b等于0,则二者的最大公约数为非0的一个 ...

  7. js实现可拖拽的div

    前言 下午忙里偷闲想写一个可拖拽的例子,留在脑海里一直都是三个事件mouseDown,mouseUp,mouseMove, 但从没有动手实践过,今天想起了自己实践了并学习了张鑫旭的demo实现. 学习 ...

  8. Qt自适应大小显示图片,添加菜单

    由于后面的图像处理需要UI,OpenCV自带也不怎么会,MFC实在懒得学的.听同学说Qt不错,就用Qt做UI了. 本文主要介绍三个内容:在Qt Creator中使用OpenCV2.Qt中自适应显示图片 ...

  9. 【开源框架】SqlSugarRepository 全库ORM 正式发布

    SqlSugarRepository.dll 全库开发框架支持 四种数据库:SqlServer. MySql .Oracle和Sqlite. SqlSugarRepository是为全库开发而生的OR ...

  10. Windows下程序打包发布时的小技巧

    一.背景 Windows下开发的应用程序在发布时,需要将其依赖的一些动态链接库一起打进安装包里面去.这个时候,快速确定这个程序到底依赖哪些动态链接库变得非常重要.很久以前写过一篇关于Qt程序安装包制作 ...