“在最底层,java中的数据是通过操作符来操作的”
一.java静态导入(更简单的输出语句)
从Java 5 开始引入了静态导入语法(import static),其目是为了减少字符输入量,提高代码的可阅读性,以便更好地理解程序。
格式:import static 包名….类名.方法名;
利用静态导入可以不通过调用包名直接使用静态方法
举例:
import static java.lang.System.out;
public class StaticImport{
public static void main(String[] args) {
out.println("Static Import Test");
}
}
通过这种方式可以不用写System直接调用out.println()方法
需要注意的是:
引入的方法必须是静态的,如果有同名的方法需要写上包名
开发中常用场景举例:
import static java.lang.System.out;
import static java.lang.Math.PI;
public class StaticImport{
public static void main(String[] args) {
out.println("Static Import Test");
out.println(PI);
}
}
在一些计算中Math中的多数方法都需要重复写Math,通过静态导入可以使代码更简洁易懂。
二.使用java操作符
操作符接受一个或者多个参数,并生成一个新值,参数的形式与普通的方法调用不同,但效果是相同的。
操作符作用于操作数,生成一个新值,另外,有些操作符可能会改变操作数自身的值,这被称为“副作用”,哪些能改变操作数的操作符最普遍的用途就是用来产生副作用,但是使用此类操作符生成的值与使用没有副作用的操作符生成的值没有什么区别。
几乎所有操作符都只能操作基本类型,例外的是"=""==""!="这些操作符能操作所有的对象,除此之外String类支持“+”和“+=”。
三.优先级
当一个操作表达式中存在多个操作符时,操作符的优先级决定了各部分的计算顺序,java对计算顺序做了特别的规定,其中最简单的规则就是先乘除后加减,用括号可以明确计算顺序。
操作符优先级表:
1、 该表中优先级按照从高到低的顺序书写,也就是优先级为1的优先级最高,优先级14的优先级最低。
2、 结合性是指运算符结合的顺序,通常都是从左到右。从右向左的运算符最典型的就是负号,例如3+-4,则意义为3加-4,符号首先和运算符右侧的内容结合。
3、 instanceof作用是判断对象是否为某个类或接口类型,后续有详细介绍。
4、 注意区分正负号和加减号,以及按位与和逻辑与的区别
四.赋值
赋值使用操作符“=”。它的意思是“取右边的值(即右值),把他复制给左边的值(即左值)”右值可以是任何常数,变量或者表达式(只要可以生成一个值)但是左值必须是一个明确的已命名的变量,也就是说必须有一个无力攻坚可以存储等号右边的值,举例来说可以讲一个常数赋值给一个变量
a = 3;
但是不能把任何东西赋值给一个常数,常数不能作为左值
对基本数据类型的赋值是很简单的,基本类型存储了实际的数值,而并非指向了一个对象的引用,所以在为其赋值的时候,是直接将一个地方的内容复制到了另一个地方,例如对基本数据类型使用a = b那么b的内容就复制给a,若接着修改a的值对b是没有影响的。
但是为对象“赋值”的时候,对一个对象进行操作时,真正操作的其实是对对象的引用,所以如果“将一个对象赋给另一个对象”,实际上是将“引用”从一个地方复制到另一个地方,这意味着假若对对象使用c=d,那么c和d都指向原本d指向的那个对象。
//: operators/Assignment.java
// Assignment with objects is a bit tricky.
import static net.mindview.util.Print.*;
class Tank {
int level;
}
public class Assignment {
public static void main(String[] args) {
Tank t1 = new Tank();
Tank t2 = new Tank();
t1.level = 9;
t2.level = 47;
print("1: t1.level: " + t1.level +
", t2.level: " + t2.level);
t1 = t2;
print("2: t1.level: " + t1.level +
", t2.level: " + t2.level);
t1.level = 27;
print("3: t1.level: " + t1.level +
", t2.level: " + t2.level);
}
} /* Output:
1: t1.level: 9, t2.level: 47
2: t1.level: 47, t2.level: 47
3: t1.level: 27, t2.level: 27
*///:~
修改t1的同时t2也发生了改变,这是由于t1和t2包含的是相同的引用,所以修改t1的同时也改变了t2,这种现象叫做“别名现象”,是java操作对象的一种基本方式,在这个例子中,可以这样避免别名现象:
t1.level = t2.level;
这样可以保持两个对象彼此独立,但是直接操作对象内的域容易导致混乱,并且违背了良好的面向对象程序设计的原则。
方法调用中的别名问题:
//: operators/PassObject.java
// Passing objects to methods may not be
// what you're used to.
import static net.mindview.util.Print.*;
class Letter {
char c;
}
public class PassObject {
static void f(Letter y) {
y.c = 'z';
}
public static void main(String[] args) {
Letter x = new Letter();
x.c = 'a';
print("1: x.c: " + x.c);
f(x);
print("2: x.c: " + x.c);
}
} /* Output:
1: x.c: a
2: x.c: z
*///:~
f()实际改变的是作用域之外的对象。
五.算数操作符
各种算数操作符的用法:
//: operators/MathOps.java
// Demonstrates the mathematical operators.
import java.util.*;
import static net.mindview.util.Print.*;
public class MathOps {
public static void main(String[] args) {
// Create a seeded random number generator:
Random rand = new Random(47);
int i, j, k;
// Choose value from 1 to 100:
j = rand.nextInt(100) + 1;
print("j : " + j);
k = rand.nextInt(100) + 1;
print("k : " + k);
i = j + k;
print("j + k : " + i);
i = j - k;
print("j - k : " + i);
i = k / j;
print("k / j : " + i);
i = k * j;
print("k * j : " + i);
i = k % j;
print("k % j : " + i);
j %= k;
print("j %= k : " + j);
// Floating-point number tests:
float u, v, w; // Applies to doubles, too
v = rand.nextFloat();
print("v : " + v);
w = rand.nextFloat();
print("w : " + w);
u = v + w;
print("v + w : " + u);
u = v - w;
print("v - w : " + u);
u = v * w;
print("v * w : " + u);
u = v / w;
print("v / w : " + u);
// The following also works for char,
// byte, short, int, long, and double:
u += v;
print("u += v : " + u);
u -= v;
print("u -= v : " + u);
u *= v;
print("u *= v : " + u);
u /= v;
print("u /= v : " + u);
}
} /* Output:
j : 59
k : 56
j + k : 115
j - k : 3
k / j : 0
k * j : 3304
k % j : 56
j %= k : 3
v : 0.5309454
w : 0.0534122
v + w : 0.5843576
v - w : 0.47753322
v * w : 0.028358962
v / w : 9.940527
u += v : 10.471473
u -= v : 9.940527
u *= v : 5.2778773
u /= v : 9.940527
*///:~
生成随机数首先创建一个Random的对象,如果在创建过程中没有传递任何参数,那么java就会将当前时间作为随机数生成器的种子,并由此在程序每一次执行时都产生不同的输出。通过在创建随机数是提供种子可以在每一次执行程序时生成相同的随机数,所以输出是可以验证的(随机数生成器对于特定的种子总是产生相同的随机序列)。
六.自动递增和递减
递减操作符是“--” 意味“减少一个单位”
递增操作符是“++”意味“增加一个单位”
这两个操作符各有两种使用方式:前缀式和后缀式
需要注意的是前缀递增和前缀递减会先执行运算再生成值,后缀递增和后缀递减会先生成值在进行运算。
//: operators/AutoInc.java
// Demonstrates the ++ and -- operators.
import static net.mindview.util.Print.*;
public class AutoInc {
public static void main(String[] args) {
int i = 1;
print("i : " + i);
print("++i : " + ++i); // Pre-increment
print("i++ : " + i++); // Post-increment
print("i : " + i);
print("--i : " + --i); // Pre-decrement
print("i-- : " + i--); // Post-decrement
print("i : " + i);
}
} /* Output:
i : 1
++i : 2
i++ : 2
i : 3
--i : 2
i-- : 2
i : 1
*///:~
可以看出:前缀形式在执行完操作后才得到值,后缀形式则是在运算执行之前就得到值,它们是那些涉赋值操作符以外唯一具有“副作用”的操作符。
七.关系操作符
关系操作符生成一个boolean结果,他们计算的是操作数的值之间的关系,如果关系是真实的,关系表达式会生成true,如果关系不真实会生成false,关系操作符包括大于(>),小于(<),小于等于(<=),大于等于(>=),等于(==),(不等于!=),等于和不等于适用于所有的基本数据类型,而其他操作符不适用于boolean类型,因为boolean的值只能为true或者false
测试对象的等价性:
//: operators/Equivalence.java
public class Equivalence {
public static void main(String[] args) {
Integer n1 = new Integer(47);
Integer n2 = new Integer(47);
System.out.println(n1 == n2);
System.out.println(n1 != n2);
}
} /* Output:
false
true
*///:~
==和!=比较的是对象的引用。
如果想比较两个对象实际内容是否相同,必须使用所有对象都适用的特殊方法equals(),但这个方法不适用于基本类型。
//: operators/EqualsMethod.java
public class EqualsMethod {
public static void main(String[] args) {
Integer n1 = new Integer(47);
Integer n2 = new Integer(47);
System.out.println(n1.equals(n2));
}
} /* Output:
true
*///:~
但是如果是自己创建的类,equals()默认行为是比较引用,所以除非在自己的新类中覆盖equals()方法,否则不会表现出我们希望的行为:
//: operators/EqualsMethod2.java
// Default equals() does not compare contents.
class Value {
int i;
}
public class EqualsMethod2 {
public static void main(String[] args) {
Value v1 = new Value();
Value v2 = new Value();
v1.i = v2.i = 100;
System.out.println(v1.equals(v2));
}
} /* Output:
false
*///:~
八.逻辑操作符
逻辑操作符与(&&)或(||)非(!)能根据参数的逻辑关系生成一个布尔值,与或非操作只可以用于布尔值,不可将一个非布尔值当做部分之在逻辑表达式中应用,例如//! 注释掉的语句
//: operators/Bool.java
// Relational and logical operators.
import java.util.*;
import static net.mindview.util.Print.*;
public class Bool {
public static void main(String[] args) {
Random rand = new Random(47);
int i = rand.nextInt(100);
int j = rand.nextInt(100);
print("i = " + i);
print("j = " + j);
print("i > j is " + (i > j));
print("i < j is " + (i < j));
print("i >= j is " + (i >= j));
print("i <= j is " + (i <= j));
print("i == j is " + (i == j));
print("i != j is " + (i != j));
// Treating an int as a boolean is not legal Java:
//! print("i && j is " + (i && j));
//! print("i || j is " + (i || j));
//! print("!i is " + !i);
print("(i < 10) && (j < 10) is "
+ ((i < 10) && (j < 10)) );
print("(i < 10) || (j < 10) is "
+ ((i < 10) || (j < 10)) );
}
} /* Output:
i = 58
j = 55
i > j is true
i < j is false
i >= j is true
i <= j is false
i == j is false
i != j is true
(i < 10) && (j < 10) is false
(i < 10) || (j < 10) is false
*///:~
短路性:一旦能明确无误的表达整个表达式的值就不会再计算表达式余下的部分了。
九.直接常量
直接常量后面的后缀字符标志了它的类型:大写L表示long 大写F表示float 大写D表示double
十六进制数适用于所有整数数据类型以前缀0x后面跟随0-9或‘a-f’来表示,如果试图讲一个变量初始化成超出自身表示范围的值,编译器会报错,
指数计数法:
//: operators/Exponents.java
// "e" means "10 to the power."
public class Exponents {
public static void main(String[] args) {
// Uppercase and lowercase 'e' are the same:
float expFloat = 1.39e-43f;
expFloat = 1.39E-43f;
System.out.println(expFloat);
double expDouble = 47e47d; // 'd' is optional
double expDouble2 = 47e47; // Automatically double
System.out.println(expDouble);
}
} /* Output:
1.39E-43
4.7E48
*///:~
在科学与工程领域,e代表自然对数的基数,约等于2.718,但是在编程语言中表示的是“10的幂次”
十.三元操作符
三元操作符也成为条件操作符
形式:
boolean-exp ? value0 : value1
如果boolean-exp的结果为true就计算value0而且这个结果也就是操作符最终产生的值,如果boolean-exp结果为false就计算value1,同样结果也就成为了操作符的最终产生的值。
十一.类型转换操作符(强制类型转换)
想要执行类型转换,需要将希望得到的数据类型置于圆括号内,放在要进行类型转换的值左边:
//: operators/Casting.java
public class Casting {
public static void main(String[] args) {
int i = 200;
long lng = (long)i;
lng = i; // "Widening," so cast not really required
long lng2 = (long)200;
lng2 = 200;
// A "narrowing conversion":
i = (int)lng2; // Cast required
}
} ///:~
如果要执行窄化转化的操作,也就是说能容纳更多信息的数据类型转化成无法容纳那么多信息的类型,就有可能面临数据丢失的危险,此时编译器会强制我们进行类型转换,也就是说“这可能是一件危险的事情,如果无论如何要这么做,必须显式的进行类型转换” 而对于扩展转化,则不必进行显式的类型转化。
十二.截尾和舎入
将float或者double转型为整型时,总是对该数字进行截尾操作,如果想得到舎入的结果,则需要使用java.lang.Math中的round()方法:
//: operators/RoundingNumbers.java
// Rounding floats and doubles.
import static net.mindview.util.Print.*;
public class RoundingNumbers {
public static void main(String[] args) {
double above = 0.7, below = 0.4;
float fabove = 0.7f, fbelow = 0.4f;
print("Math.round(above): " + Math.round(above));
print("Math.round(below): " + Math.round(below));
print("Math.round(fabove): " + Math.round(fabove));
print("Math.round(fbelow): " + Math.round(fbelow));
}
} /* Output:
Math.round(above): 1
Math.round(below): 0
Math.round(fabove): 1
Math.round(fbelow): 0
*///:~
java没有sizeof() 因为c/c++使用sizeof()最大的原因是为了“移植”不同的数据类型在不同的机器上可能有不同的大小,所以在进行一些与存储空间有关的运算时,程序员必须获悉哪些数据类型有多大。java没有这方面的需求,因为我们不需要考虑移植。