前言
MJ我的神
运算符
位运算符>>
和>>>
>>
(有符号位移):最左用符号位补齐
>>>
(无符号位移):最左用0补齐
& | ^也可以用在boolean类型上
^:相同为假,不同为真
&& || 有短路功能
& | 没有短路功能
问:什么是短路功能?
前面的状态可以确定总的状态,后面的就不判断
类型转换
- 拓宽基本类型转换
数据范围小的转为数据范围大的(19种),可以自动转换(隐式转换)
小 -> 大,自动转换
-
窄化基本类型转换
数据范围大的转为数据范围小的,可能会丢失精度和范围,需要强制转换 -
一元数字提升
将byte、short、char类型的一元数字自动提升为int类型(拓宽基本类型转换)
下面情况会执行一元数字提升
数组的索引、创建数组时的数组长度
一元运算符 +
一元运算符 -
按位取反(~)
位移(<<、>>、>>>)
int age = 10;
System.out.println(+age);//10
System.out.println(-age);//-10(不常用)
char c1 = 'A';
System.out.println(c1);//A
System.out.println(-c1);//-65()
方法签名:函数名 + 参数
对象
Java中所有对象都是new出来的,所有对象的内存都是在堆空间,所有保存对象的变量都是引用类型。
Dog dog = new Dog();
等号后面是对象,存储在堆空间;
等号前面是保存对象的引用,存储在栈空间。
方法里面的成员变量(局部变量),存储在栈上
对象里面的成员变量,对象存储在堆,则成员变量也存储在堆
Dog[] dogs = new Dog[7];
dogs里面存储的是Dog对象的地址值,而不是实际的对象
Java程序的内存划分
Java虚拟机在执行Java程序时会将内存划分为若干个不同的数据区域,主要有:
PC寄存器:存储Java虚拟机正在执行的字节码指令的地址
Java虚拟机:存储栈帧
堆(Heap):存储GC所管理的各种对象
方法区(Method Area):存储每一个类的结构信息(比如字段和方法信息、构造方法和普通方法的字节码等)
本地方法栈(Native Method Stack):用来支持native方法的调用(比如用C语言编写的方法)
构造方法
构造方法,也叫构造器,能够更方便地创建一个对象
- 方法名必须和类名一样
- 没有返回值
- 可以重载
this
this是一个指向当前对象的引用,常见用途是:
- 访问当前类中定义的成员变量
- 调用当前类中定义的方法(包括构造方法)
this的本质是一个隐藏的、位置最靠前的方法参数
只能在构造方法中使用this调用其他构造方法
如果在构造方法中调用了其他构造方法
构造方法调用语句 必须是 构造方法中的 第一条语句(构造方法在最前面)
- 如果一个类没有自定义构造方法,编译器会自动为它提供无参数的默认构造方法
- 一旦自定义了构造方法,默认构造方法就不再存在
包(package)
Java中的包就是其他编程语言中的命名空间,包的本质是文件夹,常见作用是
- 将不同的类进行组织管理、访问控制
- 解决命名冲突
命名建议
- 为保证包名的唯一性,一般包名都是以公司域名的倒写开头,比如com.baidu.*
- 全小写
类的第一句代码必须使用 package 声明自己属于哪个包
比如 package com.baidu.yunpan;
为了方便,Java编译器会为每个源文件自动导入2个包:
import java.lang.*
java.lang 包提供了Java开发中最常用的一些类型
import 源文件所在包.*
这样,在同一个包的类,就可以不需要导入包名而直接使用
需要注意的地方
import aa.bb.*
仅仅是 import了直接存放在aa.bb 包中的类型
并不包含 import aa.bb.xx.*;
也就是,只包含包里面文件,不能自动扩展里面的子包内容
继承(Inheritance)
任何类最终都是继承自java.lang.Object,一般称它为基类
方法的重新(Override)
重写:子类的方法签名 与 父类一样。也叫做 覆盖、覆写
方法签名:方法名、参数一样
- 子类 override 的方法权限必须 >= 父类的方法权限
- 子类 override 的方法返回值类型必须 <= 父类的方法返回值类型
子类的构造方法 必须先调用 父类的构造方法,再执行后面的代码
如果子类的构造方法没有显式调用父类的构造方法
编译器会自动调用父类无参的构造方法(若此时父类没有无参的构造方法,编译器将报错)
注解(Annotation)
使用@符修饰的单词,比如@Override
@Override:告诉编译器,这是一个重写后的方法
访问控制(Access Control)
Java中有4个级别的访问权限,从高到底如下所示:
- public:在任何地方都是可见的
- protected:仅在自己的包中、自己的子类中可见
- 无修饰符(package-private):仅在自己的包中可见
- private:仅在自己的类中可见
上述4个访问权限都可以修饰类的成员,比如:成员变量、方法、嵌套类(Nested Class)等
嵌套类(Nested Class): 在一个类A的内部,再创建一个类B,类B就叫做嵌套类
顶级类(Top-level Class): 在java文件夹中,处于最外层的类,叫做顶级类
只有public、无修饰符 可以修饰顶级类
一个Java文件中,可以有多个顶级类
但是只能有一个顶级类被public修饰的,并且,被public修饰的顶级类的类名必须与java文件名保持一致
上述4个访问权限 不可以修饰局部类(Local Class)、局部变量
static
static常用来修饰类的成员:成员变量、方法、嵌套类
static 修饰 成员变量
-
被 static 修饰:类变量 或 静态变量 或 静态字段
在程序运行过程中只占用一份固定的内存(存储在方法区)
可以通过实例、类访问 -
没有被static 修饰:实例变量
在每个实例内部都有一份内存
只能通过实例访问,不可以通过类访问
static 修饰 方法
-
被static 修饰:类方法、静态方法
可以通过实例、类访问
static内部不可以使用this
可以直接访问 类变量、类方法
不可以直接访问 实例变量、实例方法 -
没有被static修饰:实例方法
只能通过实例访问,不可以通过类访问
内部可以使用this
可以直接访问实例变量、实例方法
可以直接访问类变量、类方法
不推荐使用实例 访问 类变量、类方法
在同一个类中:
不能有同名的实例变量 和 类变量
不能有相同签名的实例方法 和 类方法
成员变量的初始化
编译器会自动为未初始化的成员变量设置初始值
问:如何手动给 实例变量 提供初始值?
- 在声明中
- 在构造方法中
- 在初始化块中
什么是初始化块?
在类内部,用{}写的代码
{
int age = 10;
}
编译器会将初始化块 复制到每个构造方法的头部
(每创建一个实例对象,就会执行一次初始化块)
问:如何手动给 类变量 提供初始值?
- 在声明中
- 在静态初始化块中
什么是静态初始化块?
static {
}
上面就是静态初始化块
当一个类被初始化的时候,就执行 静态初始化块
当一个类第一次被主动使用时,JVM会对类进行初始化
只会执行一次,有点类似OC中的+initialize方法差不多
可以用多个初始化块 或者 静态初始化块
按照在源码中出现的顺序被执行
单例模式(Singleton Pattern)
如果一个类设计成单例模式,那么在程序运行过程中,这个类只能创建一个实例
饿汉式单例模式:
即,一上来就创建对象
懒汉式单例模式:
即,用到的时候才创建对象
此懒汉式有线程安全问题
问:子类对象的内存中,是否包含父类中定义的private成员变量?
包含
子类在包括父类的私有成员变量,只是有访问权限控制
final
- 被final修饰的类:不能被继承
- 被final修饰的方法:不能被重写
- 被final修饰的变量:只能进行1次赋值
常量(Constant)
常量的写法:
public static final double PI = 3.1415926;
也就是,Java中一般说的常量,就是指的
static final
建议:这个static final修饰的变量,全部大写,两个字母之间使用_链接(MY_AGE)