- 使用了静态导入后,就可以省略类名来访问静态成员(成员变量、方法、嵌套类)
静态导入的经典使用场景:
import static java.lang.Math.PI; public class Main { public static void main(String[] args) { System.out.println(2 * PI * 10); System.out.println(2 * PI * 20); } }
正确使用静态导入,可以消除一些重复的类名,提高代码可读性;
过度使用静态导入,会让读者分不清静态成员是在哪个类中定义的;
建议:谨慎使用静态导入。
===========================================================================
编译器会自动为未初始化的成员变量设置初始值;
如何手动给实例变量提供初始值?
- 在声明中
- 在构造方法中
- 在初始化块中
编译器会将初始化块复制到每个构造方法的头部(每创建一个实例对象,就会执行一次初始化块)
如何手动给类变量提供初始值?
- 在声明中
- 在静态初始化块中
当一个类被初始化的时候执行静态初始化块;
当一个类第一次被主动使用时,JVM 会对类进行初始化;
public class Person { static { // 静态初始化块 System.out.println("static block"); } { // 初始化块 System.out.println("block"); } public Person() {} public Person(int age) {} public static void main(String[] args) { new Person(); // static block // block new Person(20); // block } }
一个更复杂的示例:
public class Person { static { System.out.println("Person static block"); } { System.out.println("Person block"); } public Person() { System.out.println("Person constructor"); }
public class Student extends Person {
static { System.out.println("Student static block"); } { System.out.println("Student block"); } public Student() { System.out.println("Student constructor"); }
}
**执行顺序**:父类静态块 -> 子类静态块 -> 父类代码块 -> 父类构造器 -> 子类代码块 -> 子类构造器
public static void main(String[] args) {
new Student(); // Person static block // Student static block // Person block // Person constructor // Student block // Student constructor
}
[](https://gitee.com/vip204888/java-p7)单例模式(Singleton Pattern) ========================================================================================== 如果一个类设计成单例模式,那么在程序运行过程中,这个类只能创建一个实例。 **饿汉式单例模式**:像饿汉一样,上来就直接创建了唯一的那个实例。(线程安全)
/*
- 饿汉式单例模式
*/
public class Rocket {
private static Rocket instance = new Rocket(); private Rocket(){} public static Rocket getInstance() { return instance; }
}
**懒汉式单例模式**:像懒汉一样,只有用到的时候采取创建实例。(线程不安全)
/*
- 懒汉式单例模式
*/
public class Rocket {
private static Rocket instance = null; private Rocket(){} public static Rocket getInstance() { if (instance == null) { instance = new Rocket(); } return instance; }
}
[](https://gitee.com/vip204888/java-p7)final、常量(Constant) ===================================================================================== 被 `final` 修饰的类:**不能被子类化,不能被继承** 被 `final` 修饰的方法:**不能被重写** 被 `final` 修饰的变量:**只能进行1次赋值** 常量的写法: * `public static final double PI = 3.14159265358979323846;` * `private static final int NOT_FOUND = - 1;` 如果将**基本类型**或**字符串定义为常量**,并且**在编译时就能确定值**: * **编译器会使用常量值替代各处的常量名**(类似于 C 语言的宏替换) * 称为**编译时常量**( compile-time constant) 例如下面的情况,**编译时会被替换**:
public class Main {
static final int A = 123456; static final String B = "HELLO"; public static void main(String[] args) { System.out.println(A); // 编译时直接被替换为下面 // System.out.println(123456); System.out.println(B); // 编译时直接被替换为下面 // System.out.println("HELLO"); }
}
下面这种情况,**编译时无法确定值,不会被替换**:
public class Main {
static int NUMBER = getNum(); static int getNum() { int a = 10; int b = 20; return a + b * 2 + 6; } public static void main(String[] args) { System.out.println(NUMBER); // 不会被替换 }
}
[](https://gitee.com/vip204888/java-p7)嵌套类(Nested Class) ==================================================================================== * **嵌套类**:定义在另一个类中的类; * 在嵌套类外层的类,称为:**外部类**(Outer Class) * 最外层的外部类,称为:**顶级类**(Top-level Class)
public class OuterClass { // 顶级类
// 静态嵌套类 static class StaticNestedClass { } // 非静态嵌套类(内部类) class InnerClass { }
}
[](https://gitee.com/vip204888/java-p7)内部类(Inner Class) ----------------------------------------------------------------------------------- **内部类**:没有被 `static` 修饰的嵌套类,**非静态嵌套类** 跟实例变量、实例方法一样,内部类与外部类的实例相关联: * 必须先创建外部类实例,然后再用外部类实例创建内部类实例 * 内部类不能定义除**编译时常量**以外的任何 static 成员 **内部类与外部类**: * 内部类可以直接访问外部类中的所有成员(即使是 `private`) * 外部类可以直接访问内部类实例的成员变量、方法(即使是 `private`) 内部类示例:先有公司 `company` 才能有员工 `employee`,将 `employee` 设置为 `company` 的内部类,而 `company` 可以访问 `employee` 的实例的成员变量、方法(包括`private`),`employee` 可以访问 `company` 的所有成员(包括 `private`)。
public class Company {
private String name; public Company(String name) { this.name = name; } public void fire(Employee e) { // 外部类可以直接访问内部类实例的成员变量(包括 private) System.out.println(name + " fire " + e.no); } public class Employee { private int no; public Employee(int no) { this.no = no; } public void show() { // 内部类可以直接访问外部类中的所有成员(包括 private) System.out.println(name + " : " + no); } } public static void main(String[] args) { Company c = new Company("Google"); Employee e = c.new Employee(17210224); e.show(); c.fire(e); }
}
**内部类的细节**:如果有**同名变量**,默认访问内部的,访问外部的需要特别指出。
public class OuterClass {
private int x = 1; // 外部类变量x public class InnerClass { private int x = 2; // 内部类变量x public void show() { // 默认访问内部 System.out.println(x); // 2 System.out.println(this.x); // 2 // 访问外部类的同名变量需要这么写 System.out.println(OuterClass.this.x); // 1 } } public static void main(String[] args) { new OuterClass().new InnerClass().show(); }
}
### [](https://gitee.com/vip204888/java-p7)内部类内存分布
public class Person {
private int age; public class Hand { private int weight; } public static void main(String[] args) { // 必须先有Person对象才能创建Hand对象 Person p1 = new Person(); Hand h1 = p1.new Hand(); Person p2 = new Person(); Hand h2 = p2.new Hand(); }
}
在 `Hand` 类被释放前,`Person` 类不会被释放(被 `Hand` 指向着) ![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/20200425081915382.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzczNDA5NQ==,size_16,color_FFFFFF,t_70) [](https://gitee.com/vip204888/java-p7)静态嵌套类(Static Nested Class) --------------------------------------------------------------------------------------------- **静态嵌套类**:被 `static` 修饰的**嵌套类**; 静态嵌套类在**行为上**就是一个顶级类,只是定义的代码写在了另一个类中; 对比一般的顶级类,静态嵌套类多了一些特殊权限 * 可以直接访问外部类中的成员(即使被声明为 `private`)