面向对象编程高级部分
类变量和类方法
类变量
在类属性中加一个变量conut,在构造时+1,来统计该类的对象个数
public class staticbianl {
public static void main(String[] args) {
Child c1 = new Child("mxy");
Child c2 = new Child("yll");
Child c3 = new Child("Yll");
System.out.println(c3.count);
}
}
class Child{
private String name;
public static int count = 0;
public Child(String name) {
this.name = name;
count++;
}
}
在JDK8之前存在方法区的静态域中,JDK8以后存放在堆中的这个类对应的class对象的最后。
不管static在哪里,所有对象使用没区别,且都符合以下共识:
被同一个类的所有对象共享
在类加载时就形成
什么是类变量
静态变量/静态属性,一个类的所有对象共享的变量,任一对象访问均取到相同值,任一对象修改也修改同一变量。
定义语法
- 访问修饰符 static 数据类型 变量名(推荐)
- static 访问修饰符 数据类型 变量名
访问
- 类名.类变量名(推荐)
- 对象名.类变量名
- 注意访问必须遵守其访问权限
细节
- 需要让所有对象共享一个属性时,使用类对象
- 加上static称为类变量或者静态变量,否则是普通变量
- 推荐使用 类名.类变量名来访问(满足访问权限情况下)
- 实例变量不能通过类名.变量名来访问
- 静态变量在类加载的时候就已经创建了,所以我们在没有创建对象实例的时候就能通过类名.类变量来使用
- 类变量的生命周期随着类的加载而开始,随着类的消亡而销毁
- 普通成员方法和静态成员方法都可以修改静态变量
类方法
创建:访问修饰符 static 数据返回类型 方法名(){} (推荐)
调用:类名.类方法名 或 对象名.类方法名
使用场景:方法中不涉及到任何和对象相关的成员,可以将方法设计成静态方法,这样不创建实例就能调用某个方法(当作工具使用),提高开发效率
好处:不用实例化对象就可以调用,在内存中不用重新开辟空间
可以参考Math类,其中有很多类方法
注意事项
类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区
类方法中没有this参数,但是普通方法隐含this参数

类方法可以通过类名或对象名调用
普通方法和对象有关,需要通过对象名来调用,比如对象名.方法名(参数),不能通过类名调用
类方法中只能访问静态变量或静态方法 不能 访问非静态变量或非静态方法
一个小用法:
public static void payFee(double fee){
Child.fee = fee;
}
小结:
1. 静态方法只能访问静态成员
2. 非静态方法可以访问所有成员
3. 注意要遵守访问权限规则
理解main方法语法
public static void main(String[] args){}
细节
-
main方法由JVM调用
-
JVM需要调用main方法,因此访问权限必须是public
-
JVM在执行main方法时不必创建对象,因此该方法必须是static
-
接收String类型的数组参数,该参数中保存执行Java命令时传递给所允许的类的参数
-
在main方法中可以使用当前类中的所有静态方法或静态属性,但是非静态方法和非静态属性需要通过创建对象来使用
-
args 数组参数从何处传入?在执行过程中输入的(执行程序时通过命令行控制)
public class Main01 {
public static void main(String[] args) {
for(String arg: args){
System.out.println(arg);
}
}
}


代码块
语法
[修饰符]{
代码
};
public class CodeBlock1 {
public static void main(String[] args) {
Movie movie = new Movie("三体");
}
}
class Movie{
private String name;
private double price;
private String author;
{
System.out.println("电影开始放映了...");
}
public Movie(String name) {
System.out.println("构造器被调用");
this.name = name;
}
public Movie(String name, double price) {
this.name = name;
this.price = price;
}
public Movie(String name, double price, String author) {
this.name = name;
this.price = price;
this.author = author;
}
}
注意
-
修饰符可选,写的话只能写static
-
代码块分为两类,一类是用static修饰的静态代码块,一类是没有static修饰的 普通代码块
-
代码可以为任何逻辑语句
-
;号可以写上,可以用省略
-
代码块先于构造器调用
-
static代码块 随着类的加载而执行,只会执行一次,如果是普通代码块,每创建一个对象就执行一次
-
注意普通代码块在对象创建时执行,在类加载时不执行,比如A.a1;时,普通代码块就不会执行
public class CodeBlock1 {
public static void main(String[] args) {
Movie movie = new Movie("三体");
Movie movie1 = new Movie("LaLa Land");
Movie movie2 = new Movie("让子弹飞");
}
}
class Movie{
private String name;
private double price;
private String author;
{
System.out.println("普通代码块");
}
static{
System.out.println("static代码块");
}
public Movie(String name) {
System.out.println("构造器被调用");
this.name = name;
}
public Movie(String name, double price) {
this.name = name;
this.price = price;
}
public Movie(String name, double price, String author) {
this.name = name;
this.price = price;
this.author = author;
}
}
static代码块
普通代码块
构造器被调用
普通代码块
构造器被调用
普通代码块
构造器被调用
执行顺序问题
-
1. 调用静态代码块和静态属性的初始化(静态属性和静态代码块初始化调用的优先级一致,若有多个,按定义顺序调用)
public class CodeBlockDetail {
public static void main(String[] args) {
AA a = new AA();
}
}
class AA{
private static int n1 =getVal();
static {
System.out.println("静态代码块被调用");
}
public static int getVal(){
System.out.println("getVal被调用");
return 699;
}
}
public class CodeBlockDetail {
public static void main(String[] args) {
AA a = new AA();
}
}
class AA{
static {
System.out.println("静态代码块被调用");
}
private static int n1 =getVal();
public static int getVal(){
System.out.println("getVal被调用");
return 699;
}
}
-
2. 普通代码块和普通属性初始化调用的优先级一致,若有多个,按定义顺序调用
-
3. 调用构造方法
构造器 最前面隐藏了super()和调用普通代码块
创建子类对象时,静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法的调用顺序:
-
父类静态成员
-
子类静态成员
-
父类普通代码块和普通属性初始化
-
父类构造器
-
子类普通代码块和普通属性初始化
-
子类构造器
public class CodeBlockDetail {
public static void main(String[] args) {
AA a = new AA();
}
}
class AA extends A{
private static int n1 =getVal();
private int n2;
{
System.out.println("AA的普通代码块被调用");
}
public AA(){
System.out.println("AA的无参构造器");
}
public AA(int n2) {
this.n2 = n2;
}
static {
System.out.println("AA的静态代码块被调用");
}
public static int getVal(){
System.out.println("AA的静态方法被调用");
return 699;
}
}
class A extends B{
public static int a1 = 699;
static{
System.out.println("类A静态代码块");
}
public A() {
System.out.println("A的构造器");
}
}
class B{
static {
System.out.println("类B静态代码块");
}
}
类B静态代码块
类A静态代码块
AA的静态方法被调用
AA的静态代码块被调用
A的构造器
AA的普通代码块被调用
AA的无参构造器