java基础学习(二)操作符

本文详细介绍了Java中的操作符,包括赋值操作符、比较操作符、逻辑操作符以及特殊操作符如自增自减、按位操作和移位操作。重点讨论了对象复制、引用和基本类型的差异,以及在对象和基本类型上使用操作符的不同行为。同时,文章还提到了类型转换、短路逻辑和布尔操作符的规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java几乎所有的操作符都只能操作 基本类型,例外的操作符是”=”、”==”和”!=”,这些操作符能操作所有的对象。
String类支持”+”和”+=”。当编译器看到一个String后面紧跟一个”+”,而这个”+”后面又紧跟一个非String类型的元素时,就会尝试将这个非String类型的元素转换为String。但是如果是在String前面,则不会转换,会正常的运算。

public static void main(String []args) {
        int a = 999;
        int b = 1;
        System.out.println(a + b + "结果");
        System.out.println("结果:"+a+b);
    }
结果是:
1000结果
结果:9991

赋值操作符”=”
右值可以是任何 常数 、变量或者表达式(只要能生成一个值就行)。
左值必须是一个明确的、已命名的变量。必须有一个物理空间可以存储右值。但是常数不能作为左值。

基本类型存储了实际的数值,而并非指向一个对象的引用,在赋值时,是直接将一个地方的内容复制到了另一个地方。例如:

 public static void main(String []args) {
        int a = 6;
        int b = a;
        a+=1;
        System.out.println("结果:a="+a);
        System.out.println("结果:b="+b);
    }
结果:
结果:a=7
结果:b=6

说明:对a的修改并不会影响b的值。

对一个对象进行复制操作时,真正操作的是对对象的引用,实际是将 “引用”从一个地方复制到另一个地方。

    int level;
    public static void main(String []args) {
        TestString ts_1=new TestString();
        TestString ts_2=new TestString();
        ts_1.level=100;
        ts_2.level=222;
        System.out.println("-------赋值前----------");
        System.out.println("结果:ts_1.level="+ts_1.level);
        System.out.println("结果:ts_2.level="+ts_2.level);
        ts_1.level+=1;
        ts_2=ts_1;
        System.out.println("-------赋值后----------");
        System.out.println("结果:ts_1.level="+ts_1.level);
        System.out.println("结果:ts_2.level="+ts_2.level);
        System.out.println("-------引用地址----------");
        System.out.println("结果:ts_1.level="+ts_1);
        System.out.println("结果:ts_2.level="+ts_2);
    }
结果:
-------赋值前----------
结果:ts_1.level=100
结果:ts_2.level=222
-------赋值后----------
结果:ts_1.level=101
结果:ts_2.level=101
-------引用地址----------
结果:ts_1.level=chapter02.TestString@14ae5a5
结果:ts_2.level=chapter02.TestString@14ae5a5

说明,两个对象指向同一个引用地址。
当对 ts_2 赋值时,它本身的引用被覆盖了,也就是丢失了,而那个不再被引用的对象会由垃圾回收器自动清理。

将一个对象作为参数传递给方法时,也只是传递一个引用。

    int value;
    public static void main(String[]args){
        TestCopy x=new TestCopy();
        x.value=88;
        System.out.println("-------调用方法前--------");
        System.out.println("结果:x.value="+x.value);
        change(x);
        System.out.println("-------调用方法后--------");
        System.out.println("结果:x.value="+x.value);
    }
    public static void change(TestCopy y){
        y.value=1111;
    }
结果:
-------调用方法前--------
结果:x.value=88
-------调用方法后--------
结果:x.value=1111

自增自减操作符
前缀递增(++)和前缀递减(–):先执行运算(+或-),再生成值(赋值)。
后缀递增(++)和后缀递减(–):先生成值(赋值),在执行运算(+或-)。

 public static void main(String[]args){
        int x=5;
        System.out.println("x="+x);
        System.out.println("前缀递增:++x="+(++x));
        System.out.println("x="+x);
        System.out.println("后缀递减:x--"+(x--));
        System.out.println("x="+x);
    }
结果:
x=5
前缀递增:++x=6
x=6
后缀递减:x--6
x=5

对于前缀形式,在执行完运算后才得到值,
对于后缀形式,在执行运算前就得到值。

关系操作符
等于(=)和不等于(!=)适用于所有的基本数据类型。
大于、小于、小于或等于、大于或等于 ,这些比较符不适用与boolean类型。因为布尔值只能为true或false。比较大小没有意义。

关系操作符==和!=也适用于所有对象。比较的是对象的引用,而不是对象的内容:

public static void main(String[]args){
        Integer a=new Integer(21);
        Integer b=new Integer(21);
        System.out.println("a==b的结果:"+(a==b));
    }
结果:
a==b的结果:false

对于基本类型,直接使用”==”和”!=”即可。
对于其他所有java类库的对象,比较是否相等,可以使用equals()方法即可,大多数java类库都实现了equals()方法。

public static void main(String[]args){
        Integer a=new Integer(21);
        Integer b=new Integer(21);
        System.out.println("a==b的结果:"+a.equals(b));
    }
结果:
a==b的结果:true

但是,对于自己创建的新类,除非在新类中,覆盖equals()方法,否则该方法的默认比较引用

int value;
    public static void main(String[]args){
        Equivalence a=new Equivalence();
        Equivalence b=new Equivalence();
        a.value=b.value=100;
        System.out.println("a==b的结果:"+a.equals(b));
    }
结果:
a==b的结果:false

覆写equals()方法

public boolean equals(Object otherObject){
        //检测this与otherObject是否引用同一个对象
        if(this==otherObject)  return true;
        //检测otherObject是否为null
        if(otherObject==null) return false;
        //比较this与otherObject是否属于同一个类
        //如果equals的语义在每个子类中有所改变,则使用getClass()检测
        if(getClass()!=otherObject.getClass()) return false;
        //如果所有的子类都拥有统一的语义,就使用instanceof检测
        if(!(otherObject instanceof ClassName)) return false;
        ClassName other=(ClassName)otherObject;
        //对域进行比较,基本类型用 ==  ,使用equals比较对象域
        return (this.value==other.getValue) && (this.name.equals(other.getName));
    }

覆写equals()方法必须覆写hashCode方法:不同的对象应该有不同的哈希值,相同的对象应该哈希值也相同:

//重写equals方法后,但是未覆写hashCode()方法
int value;
    public static void main(String[]args){
        Equivalence a=new Equivalence();
        Equivalence b=new Equivalence();
        a.value=b.value=100;
        System.out.println("a==b的结果:"+a.equals(b));
        System.out.println("a的哈希值:"+a.hashCode());
        System.out.println("b的哈希值:"+b.hashCode());
    }
结果:
a==b的结果:true
a的哈希值:21685669
b的哈希值:2133927002

说明,a与b是相同的对象,但是hashCode的值是不同的。对象的哈希码,是由Object类的本地方法生成的,确保每个对象有一个哈希码。
应该覆写hashCode()方法:

public int hashCode(){
        //一个对象中易变化的值生成hashCode
        //org.apache.commons.lang3.builder.HashCodeBuilder
        return new HashCodeBuilder().append(value).toHashCode();
    }

覆写equals()方法和hashCode()方法后,最后结果:

a==b的结果:true
a的哈希值:729
b的哈希值:729

逻辑操作符
操作符 或( || )、与( && )、非 (!)只可应用于布尔值。不可将一个非布尔值当做布尔值在逻辑表达式中使用。
布尔值可以自动转换为String值。
短路:一旦能够明确无误的确定整个表达式的值,就不再计算表达式余下的部分。整个逻辑表达式靠后的部分有可能不会被运算。

直接常量
直接常量后面的后缀字符标志它的类型:
大写或小写的L,代表long;
大写或小写的F,代表float;
大写或小写的D,代表double;
十六进制:0x或0X位前缀,后面跟0-9或大写(小写)的a-f来表示;
八进制:0前缀,后跟0-7的数字表示。

指数记数法
其中e代表“10的幂次”
编译器通常将指数作为双精度(double)处理。

按位操作符
按位操作符用来操作整数基本数据类型中的单个”比特”(bit),即二进制位。

原码:符号位加上真值的绝对值,即第一位表示符号(0为正,1为负),剩余位表示值。例如:1000 0011最高位1代表负数,真正数值是-3。

反码:正数的反码是原码,负数的反码,在原码的基础上,符号位不变,其余各个位取反。例如:-3的反码是:1111 1100.

补码:正数的补码是原码,负数的补码是它的反码+1。例如:-3的补码:1111 1101。

正数的原码、反码、补码都是一样的。
计算机中负数使用补码表示。

public static void main(String[]args){
        int a=-3;
        int b=9;
        System.out.println("负数的二进制(补码表示):a="+Integer.toBinaryString(a));
        System.out.println("正数的二进制(原码),全0省略:b="+Integer.toBinaryString(b));
    }
结果:
负数的二进制(补码表示):a=11111111111111111111111111111101
正数的二进制(原码),全0省略:b=1001

位操作符规则:
这里写图片描述
位操作符可以与”=”联合使用,合并运算和赋值。
&=、|=、^=都是合法的。
~是一元操作符,不可与”=”联合使用。

public static void main(String[]args){
        int a=-3;
        int b=9;
        System.out.println("负数的二进制(补码表示):a="+Integer.toBinaryString(a));
        System.out.println("正数的二进制(原码),全0省略:b="+Integer.toBinaryString(b));
        a&=b;
        System.out.println("a&=b运算后,a="+Integer.toBinaryString(a));
        a|=b;
        System.out.println("a|=b运算后,a="+Integer.toBinaryString(a));
        a^=b;
        System.out.println("a^=b运算后,a="+Integer.toBinaryString(a));
    }
结果:
负数的二进制(补码表示):a=11111111111111111111111111111101
正数的二进制(原码),全0省略:b=1001
a&=b运算后,a=1001
a|=b运算后,a=1001
a^=b运算后,a=0

布尔类型作为一种 单比特值(0或1)对待。可以执行 &、|、^运算。但是不能执行按位 ~运算(避免与逻辑not混淆)。
对于布尔值,按位操作符具有与逻辑操作符相同的效果,多了一个异或运算。但是不会中途短路。

        boolean x=true;
        boolean y=false;
        x&=y;
        System.out.println("x&=y运算后,x="+x);
        x|=y;
        System.out.println("x|=y运算后,x="+x);
        x^=y;
        System.out.println("x^=y运算后,x="+x);
结果:
x&=y运算后,x=false
x|=y运算后,x=false
x^=y运算后,x=false

移位操作符
移位操作符的运算对象也是二进制的位。只可用来处理整数类型(基本类型的一种)。
这里写图片描述
移位操作符可以与等号(=)组合使用。在移动表达式中,不能使用布尔运算。

 public static void main(String[] args){
        int i=-1;
        int j=6;
        System.out.println("-1的二进制:"+Integer.toBinaryString(i));
        i<<=3;
        System.out.println("左移3位后,低位补0,-1的二进制:"+Integer.toBinaryString(i));
        i>>=4;
        System.out.println("有符号右移4位后,符号为负,高位插入1,-1的二进制:"+Integer.toBinaryString(i));
        System.out.println("6的二进制:"+Integer.toBinaryString(j));
        j>>>=5;
        System.out.println("无符号右移5位后,无论正负,高位插入0,6的二进制:"+Integer.toBinaryString(j));
    }
结果:
-1的二进制:11111111111111111111111111111111
左移3位后,低位补0,-1的二进制:11111111111111111111111111111000
有符号右移4位后,符号为负,高位插入1,-1的二进制:11111111111111111111111111111111
6的二进制:110
无符号右移5位后,无论正负,高位插入06的二进制:0

对基本类型中的char、byte、short进行移位处理,在移位之前,它们会被转换为int类型,并且得到的结果也是一个int类型,只有数值右端的低5位才有用。

char c='r';
        byte by=1;
        short s=2;
        System.out.println("char的二进制:c="+Integer.toBinaryString(c));
        System.out.println("byte的二进制:by="+Integer.toBinaryString(by));
        System.out.println("short的二进制:s="+Integer.toBinaryString(s));
        c<<=3;
        System.out.println("c左移3位后的二进制:c="+Integer.toBinaryString(c));
结果:
char的二进制:c=1110010
byte的二进制:by=1
short的二进制:s=10
c左移3位后的二进制:c=1110010000

对于byte或short值进行移位操作,先被转换成int类型,再进行右移操作,然后被截断指定的位数,赋给原来的类型,可能会得到-1的结果:

 byte by=-1;
        System.out.println("byte的二进制:by="+Integer.toBinaryString(by));
        by>>>=10;
        System.out.println("byte的二进制:by="+Integer.toBinaryString(by));
        by=-1;
        //右移后,高位补0
        System.out.println("byte类型右移:by="+Integer.toBinaryString(by>>>10));
结果:
byte的二进制:by=11111111111111111111111111111111
byte的二进制:by=11111111111111111111111111111111
byte类型右移:by=1111111111111111111111

在C或C++中,对于非0值,boolean值是true。
但是在java中,并不会按照布尔值处理。

类型转换操作符
窄化转换:将能容纳更多信息的数据类型转换为无法容纳那么多信息的类型,就有可能面临信息的丢失。此时,编译器会强制转换,必须显式进行类型转换。
扩展转换:不必显式进行类型转换,不会造成任何信息的丢失。

java允许把任何基本数据类型转换为别的基本数据类型,但是布尔类型除外,后者根本不能进行任何类型的转换。

将float或double转型为整形值时,总是对该数字执行截尾。

public static void main(String[] args){
        float f1=3.45F;
        double lg=32.87;
        System.out.println("float转为int:"+(int)f1);
        System.out.println("double转为int:"+(int)lg);
    }
//结果:
float转为int:3
double转为int:32

需要四舍五入的结果时,使用Math.round()方法:

        float f1=3.45F;
        double lg=32.87;
        System.out.println("float转为int:"+Math.round(f1));
        System.out.println("double转为int:"+Math.round(lg));
//结果:
float转为int:3
double转为int:33

对基本数据类型执行算术运算或按位运算,只要类型比int小(char、byte、short),在运算之前,会将这些值自动转换为int。那么最终的结果也是int类型。
如果要把结果赋值给较小的类型,必须使用类型转换,就有可能出现信息丢失。
表达式中出现的最大的数据类型决定了表达式最终结果的数据类型。

Java不需要sizeof()操作符数据项分配的字节数。因为所有数据类型在所有机器中的大小都是相同的。

总结:
char、byte、short:先转为int类型,可以使用算术运算符、关系运算符、位运算、移位运算、类型转换。但是不能使用逻辑运算(或与非运算),也不能强转为布尔类型。

int、long:可以使用算术运算符、关系运算符、位运算、移位运算、类型转换。但是不能使用逻辑运算(或与非运算),也不能强转为布尔类型。

float、double:可以使用算术运算符、关系运算符、类型转换。但是不能使用逻辑运算(或与非运算)、位运算、移位运算,也不能强转为布尔类型。

boolean:可以使用关系运算中的(==、!=),其他关系运算不适用,可以使用逻辑运算,位运算中只能使用(&、|、^),不能使用(~),不能使用移位运算,算术运算和进行强转类型。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值