OnJava01--面向对象基础 & 操作符

OnJava01-面向对象基础 & 操作符

1、对象无处不在

1.1、数据保存在哪

(1)寄存器

速度最快的数据存储方式,直接包存在CPU里。数量很有限,只能按需分配。Java中不能直接控制寄存器的分配。

(2)栈(Stack)
  • 数据存储在随机存取存储器(RAM)里,处理器可以通过栈指针直接操作该数据。
  • 效率仅次于寄存器。
  • Java在创建程序时就要明确栈上所有对象的生命周期,约束了程序的灵活性,因此对象引用(但不仅是对象引用)会保存在栈上,而对象本身不在。
(3)堆(Heap)
  • 通用的内存池,也存储在RAM空间
  • 用于存放所有Java对象
  • 堆的使用非常灵活,可以随时new对象,Java会在堆上为该对象分配内存空间
  • 灵活的代价:分配和清理堆存储要比栈存储花费更多的时间--如今Java的堆内存分配机制已经非常高效,不需过度关注此问题
(4)常量存储
  • 常量通常直接保存在程序代码中,因为值不会改变
(5)非RAM存储

未保存在应用程序中的数据。典型例子:

  • 序列化对象:转换为字节流,并可以发送到其他机器的对象
  • 持久化对象:磁盘上的对象,JDBC、Hibernate等

1.2 特殊情况:基本类型

对于基本类型,Java是直接创建一个“自动变量”,而不是引用,该变量会直接在栈上保存它的值。运行效率也较高。

1.3 无需销毁对象

(1)作用域
  • C/C++、Java的作用域范围都是通过大括号{} 来定义的。
  • Java中不允许在外围的作用域中“隐藏”变量:
1
2
3
4
5
6
{
int x = 12;
{
int x = 96; // 语法错误
}
}
(2)对象的作用域
  • Java对象在其作用域结束后可能会依然存在。

  • 垃圾收集器会监视所有通过new创建的对象,及时发现不再引用的对象,并释放所占用的内存。

1.4 基本类型的默认值

  • 当变量作为类的成员存在时,Java才会初始化为该变量对应的基本类型的默认值
  • 默认值机制不会应用于局部变量
1
2
int x;
System.out.println(x); // 编译错误:java: 可能尚未初始化变量x

2、操作符

2.1 Java操作符

  • 几乎所有操作符都只能操作基本类型,例外的是 = 、==、 != 也能操作对象
  • String类型也支持 + 和 +=

2.2 赋值(=)

  • 基本类型的赋值:将一个地方的内容复制到另一个地方,a = b就是b的内容复制给a,赋值后修改a并不会影响b

  • 对象的赋值:真正操作的是对象的引用,将一个对象赋值给另一对象,实际是将引用复制到另一个地方;c = d就是将c、d都指向d的对象。

    • 这种现象称作“别名”,需要注意,将对象作为参数传递给方法时,也会产生别名
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    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';
    System.out.println("1: x.c: " + x.c);
    f(x); // f方法内修改了x.c的值,实际改变了f()之外的对象
    System.out.println("2: x.c: " + x.c);
    }
    }
    /* Output:
    1: x.c: a
    2: x.c: z
    */

2.3 算术操作符(+ - * / %)

  • 整数的除法会舍弃小数位,非四舍五入
  • 支持快捷运算符,即 +=、 -=、*=、/=、%=

2.4 自动递增、自动递减(++、--)

  • 前缀式、后缀式:先执行运算再生成结果还是相反
  • 是有副作用的操作符:会改变操作数

2.5 关系运算符(<、>、<=、>=、==、!=)

测试对象是否相等:
  • == 和 != 比较的是对象的引用
  • 对于Integer对象的 == 比较:
    • Java中会通过享元模式来缓存 -128 ~ 127 内的对象,所以多次调用Integer.valueOf此范围内的整数,得到的是同一个对象
    • new Integer() 生成的对象都是新创建的,无论什么范围

2.6 位操作符

用来操作整数基本数据类型中的单个二进制位(bit)。

  • 按位与:&
  • 按位或:|
  • 按位异或: ^
  • 按位非(一元操作符,只对一个操作数操作):~

布尔类型:

  • 支持&、|、^,但不支持~(可能是为了避免与!混淆)
  • 按位操作布尔值时,不会“短路”

2.7 移位操作符

只能用来处理基本类型中的整数类型。

  • << :左移,低位补0
  • >> :右移,符号扩展,符号为正,高位插入0,否则插入1
  • >>>: 无符号的右移,零扩展

2.8 类型转换

(1)截尾和舍入
  • 执行窄化转型(eg. float -> int)时,Java做的是截尾操作(29.7 -> int 是29,而不是四舍五入后的30)
  • 舍入需要使用round()方法:
1
Math.round(0.7f);
(2)提升
  • 对小于int类型的基本数据类型(char byte short)执行算术运算或按位运算时,运算执行前就会将值自动提升为int,结果也是int类型。如果要把结果赋值回较小的类型,需要使用强制类型转换。
  • 表达式里出现的最大的数据类型决定了表达式最终结果的数据类型(eg,int + long -> long)