Java面向对象编程(高级部分)学习

面向对象编程高级部分

类变量和类方法

类变量

在类属性中加一个变量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);
        //输出3
    }
}
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){
    //this.fee = fee; 静态方法无this参数,不能使用this
    //但是可以使用类名.静态属性来调用,避免命名冲突
    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代码块
普通代码块
构造器被调用
普通代码块
构造器被调用
普通代码块
构造器被调用
  • 类什么时候被加载 (重要)

    • 创建对象实例的时候(new)
    • 创建子类对象实例的时候,父类也会被加载,且父类先于子类加载
    • 直接使用静态成员时也会被加载
    public class CreateTest {
        public static void main(String[] args) {
            new A();
            System.out.println(A.a1);
        }
    }
    class A extends B{
        
        public static int a1 = 699;
        
        static{
            System.out.println("类A被加载");
        }
    }
    
    class B{
        static {
            System.out.println("类B被加载");
        }
    }
    
    //输出:
    //类B被加载
    //类A被加载
    //699
    

执行顺序问题

  • 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;
        }
    }
    //输出:
    //getVal被调用
    //静态代码块被调用
    
    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;
        }
    }
    //输出:
    //静态代码块被调用
    //getVal被调用
    
  • 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(){
        //super();
        //调用本类普通代码块
        System.out.println("AA的无参构造器");
    }

    public AA(int n2) {
        //super();
        //调用普通代码块
        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的静态代码块被调用

//然后执行父类构造方法super()
A的构造器
    
//然后执行本类普通代码块
AA的普通代码块被调用
    
//然后执行本类无参构造器
AA的无参构造器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值