final
基本用法
- 修饰类时,表示其不能被继承。final类中的所有成员方法都会被隐式指定为final方法
final不能用来修饰抽象类 - 修饰方法,表示不能被子类覆盖。所有private方法都被隐式指定为final方法
final修饰的方法可以被重载 - 修饰方法参数时,称为最终参数,其不能在方法内被修改
- 修饰变量
- 如果修饰基本数据类型变量,则其数值一旦被赋值就不能再修改
- 如果修饰引用类型变量,则其不能再指向其他对象
-
深入理解
当final变量是基本数据类型或String类型时,如果能在编译期间知道它的确切值,编译器就会将它当作编译期常量使用。也就是需要访问到这个final变量的地方,相当于直接访问这个常量,而无需在运行时确认
- 匿名内部类中使用的外部局部变量只能是final变量
参考文档
浅析Java中的final关键字
Var
简介
- Java10引入,用来进行局部变量的类型自动推断
事实上,var并非是关键字,它只是一个保留类型,也就是说仍然可以用var作为标识符
int var = 10;
var和继承
var依然能实现多态
一旦编译器推断出了var类型变量的值,就不能对其赋值错误的值
var a = 10;
a = "hello"; //不兼容的类型: java.lang.String无法转换为int
-
var和数组初始化
使用var来初始化一个数组时,只能使用以下语法
其他语法都会报错var arr = new int[3]; //正确
var[] arr = new int[3]; // 'var' 不允许用作数组的元素类型
var[] arr = {1,2,3}; //'var' 不允许用作数组的元素类型
var和lambda
lambda表达式中不能捕获非final的局部变量,但因为var可以用来声明不可指类型(匿名),就可以做到类似让lambda捕获非final局部变量
//错误
int count = 0;
List.of("ice1000", "Glavo")
.forEach(e -> count += 1); //error
System.out.println(count);
//var
var context = new Object(){
int count = 0;
};
List.of("ice1000", "Glavo")
.forEach(e -> context.count += 1); //error
System.out.println(context.count);
var的局限
var变量必须初始化
不能进行复合声明
var a = 1,b = 2,c = 3; // 'var' 不允许在复合声明中使用
不能初始化为null
var a = null; //无法推断本地变量 a 的类型 (变量初始化程序为 'null')
不能使用var作为字段类型
- 不能使用var作为参数类型
- 不过Java11允许var作为lambda表达式的参数类型
- 不能使用var作为返回值类型
- catch捕获不能使用var做异常的类型
- var和菱形推断一起使用时,菱形推断得到的是Object类型
var arr = new ArrayList<>();
//编译器将其推断为ArrayList<Object> arr = new ArrayList<Object>();
参考文档
Java10 var关键字详解
Java 10 新特性之局部变量类型推断
static
static方法
- 静态方法不依赖与任何对象就能够访问,所以它是没有this的
且由于这个特性,在静态方法中不能访问类的非静态成员和非静态方法
但是非静态方法是可以访问静态方法和字段的
- 构造器不属于静态方法
-
static字段
静态字段被所有的对象共享,在内存中只有一个副本,在第一次访问时创建,程序结束时销毁
- 静态字段可以通过对象去访问
- static不允许修饰局部变量
- static字段位于静态存储区,普通字段位于堆区
-
静态内部类
-
static代码块
static代码块只会在构造第一个对象时执行一次,所以可以用来为static字段进行一些复杂的赋值操作
- static代码块会在所有构造器前调用,无论超类还是子类
而普通代码块自会在当前类的构造器前调用 - static代码块可以出现在类中的所有非方法内部的位置
且按照定义顺序执行package Test;
public class TestCode extends Base{
//子类static代码块
static{
System.out.println("test static");
}
//子类普通代码块
{
System.out.println("test normal");
}
//子类构造器
public TestCode(){
System.out.println("test constructor");
}
public static void main(String[] args) {
new TestCode();
}
}
class Base{
//超类static代码块
static{
System.out.println("base static");
}
//超类普通代码块
{
System.out.println("base normal");
}
//超类构造器
public Base(){
System.out.println("base constructor");
}
}
/*
输出:
base static
test static
base normal
base constructor
test normal
test constructor
*/
参考文档
构造器时静态方法吗
Java static关键字为什么不能应用于局部变量
Java中的static关键字解析
再议Java中的static关键字
synchronized
- 被synchronized修饰的方法同一时间只能被一个线程访问
transient
- 被transient修饰的字段在对象序列化时会被忽略
volatile
- volatile修饰的字段,每次访问时,都必须从共享内存中重新读取,且在发生变化时,必须将其写入共享内存
访问权限控制符
修饰外部类
- 默认:该类只对同一个包中的其他类可见
-
修饰方法、字段或内部类
默认:只能被同一个包中的其他类访问
- private:只能在类内部被访问
- protected:只对同一个包中的类或者子类访问
- public:能在任何地方被访问
参考文档
浅析Java中的访问权限控制符
Java核心(二):四种权限修饰符的区别、private是否能够修饰class