【JavaSE】- 面向对象(高级)

文章详细阐述了Java中类变量的定义、访问、细节及应用场景,包括静态和实例变量的区别,以及如何通过类名或对象访问它们。同时,介绍了main方法的作用、注意事项和参数使用。此外,讨论了代码块的概念,包括静态和普通代码块的执行时机和顺序,以及它们在构造器中的作用。
摘要由CSDN通过智能技术生成

1.1🌠类变量的定义

先看这段代码

public class ChildGame {
    public static void main(String[] args) {
        Child jack = new Child("jack");
        Child tom = new Child("tom");
        Child marry = new Child("marry");

        jack.join();
        jack.count++;
        tom.join();
        tom.count++;
        marry.join();
        marry.count++;

        System.out.println("共有"+Child.count+"名小孩加入了游戏");
        System.out.println(jack.count);
        System.out.println(tom.count);
        System.out.println(marry.count);
    }
}
class Child{
    private String name;
    public static int count = 0;

    public Child(String name) {
        this.name = name;
    }
    public void join(){
        System.out.println(name+"加入了游戏...");
    }
}

run
在这里插入图片描述
解析
当一个类里的成员被static关键字所修饰时,这就意味着这个类成员会被这个Child类所有实例化的对象所共享

内存分析
在这里插入图片描述
解析
先进行类加载,再加载类变量,之后加载Child这个类的信息,然后是默认初始化,接着是显式初始化,最后是构造器初始化,初始化后,child1对象和child2对象都指向方法区里的静态域里的count变量

总结
(1)static变量是在同一个类中被所有实例化的对象所共享
(2)static变量在类加载中就已经生成了

1.2🌭访问类变量

(1).类变量是随着类的加载而加载,不创建对象也可以访问
(2).创建对象来访问

public class VisitStatic {
    public static void main(String[] args) {
        // 访问类变量
        // (1).类变量是随着类的加载而加载,不创建对象也可以访问
        System.out.println(A.name);
        //System.out.println(A.n); //err
        
        // (2).创建对象来访问
        A a = new A();
        System.out.println(a.name);
        //System.out.println(a.n); //err
    }
}

class A{
    // 类变量
    public static String name = "小明";
    // 私有类变量
    private static int n = 10;
}

run
在这里插入图片描述

1.3🍐类变量细节

(1).类变量是该类的所有对象所共享的,而实例变量是每个对象独享的
(2).static变量是叫类变量或静态变量,否则称为实例变量/普通变量/非静态变量
(3).类变量可以通过类名.成员名或对象.成员名访问,而普通变量只能通过对象.成员名访问。(前提是满足访问修饰符的访问权限)
(4).类变量是在类加载时就初始化了,在没有创建对象之前,类加载了,就可以使用类变量了
(5).类变量的生命周期是随着类的加载开始随着类消亡而消亡


public class StaticDetail {
    public static void main(String[] args) {
        B b = new B();
        //System.out.println(B.n1);
        System.out.println(B.n2);

        //静态变量是类加载的时候,就创建了,所以我们没有创建对象实例
        //也可以通过类名.类变量名来访问
        System.out.println(C.address);

    }
}

class B {
    public  int n1 = 100;
    public static int n2 = 200;
}

class C {
    public static String address = "北京";
}

在这里插入图片描述

1.4🍷类变量应用场景

使用场景
如果在方法中不涉及和对象有关的成员,则可以将方法设计成静态方法提高开发效率

System.out.println("9的开平方结果:"+Math.sqrt(9));
System.out.println(MyTools.sum(10,20));

class MyTools{
    public static double sum(int n1,int n2){
        return n1+n2;
    }
}

通过上面的例子不难看出,不用创建对象就能调用方法,实在是太裤辣!!!

1.5🍼类方法细节

(1).类方法中不能使用this和super这种和对象有关的关键字
(2).普通方法中可以访问静态方法和静态变量
(3).静态方法只能访问静态方法和静态变量

public class Test {
    public static void main(String[] args) {
        D.hi();//ok
        //非静态方法,不能通过类名调用
        //D.say();, 错误,需要先创建对象,再调用
        new D().say();//可以
    }
}
class D {
    private int n1 = 100;
    private static int n2 = 200;
    
    //非静态方法,普通方法
    public void say() {
    }

    //静态方法,类方法
    public static  void hi() {
        //类方法中不允许使用和对象有关的关键字,
        //比如this和super。普通方法(成员方法)可以。
        // System.out.println(this.n1); // err
    }

    //静态方法只能访问静态成员.
    public static void hello() {
        System.out.println(n2);
        System.out.println(D.n2);
        //System.out.println(this.n2);不能使用
        hi();//OK
        //say();//错误
    }
    //非静态方法可以访问 静态成员和非静态成员
    public void ok() {
        //非静态成员
        System.out.println(n1);
        say();
        //静态成员
        System.out.println(n2);
        hello();
    }
}

多说不练假把式

1.6🌽类方法练习

class Test {
    static int count = 9;
    public void count() {
        System.out.println("count=" + (count++));
    }
    public static void main(String args[]) {
        new Test().count(); 
        new Test().count();
        System.out.println(Test.count);
    }
}

run
9 、10 、 11
解析
静态变量随着类加载而加载,随着类结束而消亡

class Person {  
   private int id;
   private static int total = 0;
   public static int getTotalPerson() {
       //id++;//错误, 注销

       return total;
   }
   public Person() {//构造器
       total++;  //total = 1
       id = total;//id = 1
   }
}
class TestPerson {
   public static void main(String[] args) {
       System.out.println("Number of total is " +Person.getTotalPerson()); //0
       Person p1 = new Person();
       System.out.println( "Number of total is "+ Person.getTotalPerson()); //1
   }
}

run
0、1


class Person { 
    private int id;
    private static int total = 0;
    public static void setTotalPerson(int total){
        // this.total = total;//错误,因为在static方法中,不可以使用this 关键字
        Person.total = total;
    }
    public Person() {//构造器
        total++;
        id = total;
    }
    //编写一个方法,输出total的值
    public static void m() {
        System.out.println("total的值=" + total);
    }
}
class TestPerson {
    public static void main(String[] args) {
        Person.setTotalPerson(3);
        new Person(); 
        Person.m();
    }
}

run
4

2.1🤗详解main方法

public static void main(String[] args){}

1.main方法是jvm虚拟机调用
2.jvm虚拟机需要调用类的main方法,所以该方法的访问权限必须是public
3.jvm虚拟机在执行main方法不需要创建对象,所以是static
4.可以接收String类型数组参数,该数组中保存java命令时所传递的参数
5.java 执行程序 参数1 参数2 参数3 …

2.2🍏main方法注意事项


public class Main01 {
    private static int n1;
    private static void m1(){}
    private int n2;
    private void m2(){}
    
    public static void main(String[] args) {
        // main方法本身就是静态方法
        // (1)静态方法只能包含静态成员
        m1();
        System.out.println(n1);
        
        // (2)静态方法只能包含普通成员
        // m2();  // err
        // System.out.println(n2); // err


        // (3)如果静态方法非要访问普通成员,必须实例化一个对象
        Main01 main01 = new Main01();
        main01.m2();
        System.out.println(main01.n2);
    }
}

2.3🍇main方法中的String数组传参

在这里插入图片描述
在这里插入图片描述
注意要点击右下角的应用
在这里插入图片描述
也是成功运行!

3.1🍍代码块的定义

先看一段代码


public class CodeBlock01 {
    public static void main(String[] args) {

        Movie movie = new Movie("你好,李焕英");
        System.out.println("===============");
        Movie movie2 = new Movie("唐探3", 100, "陈思诚");
    }
}

class Movie {
    private String name;
    private double price;
    private String director;

    //3个构造器 -》重载
    //(1) 下面的三个构造器都有相同的语句
    //(2) 这样代码看起来比较冗余
    //(3) 这时我们可以把相同的语句,放入到一个代码块中,即可
    //(4) 这样当我们不管调用哪个构造器,创建对象,都会先调用代码块的内容
    //(5) 代码块调用的顺序优先于构造器..

    {
        System.out.println("电影屏幕打开...");
        System.out.println("广告开始...");
        System.out.println("电影正式开始...");
    };

    public Movie(String name) {
        System.out.println("Movie(String name) 被调用...");
        this.name = name;
    }

    public Movie(String name, double price) {

        this.name = name;
        this.price = price;
    }

    public Movie(String name, double price, String director) {

        System.out.println("Movie(String name, double price, String director) 被调用...");
        this.name = name;
        this.price = price;
        this.director = director;
    }
}

run
在这里插入图片描述
总结
如果构造器中有重复的语句,可以使用代码块,减少代码冗余

3.2🍈代码块细节

在谈代码块细节之前大家需要知道类在什么时候会被加载

(1).创建对象实例时


public class CodeBlockDetail01 {
    public static void main(String[] args) {
        BB bb = new BB();

    }
}
class BB {
    //静态代码块
    static {
        System.out.println("BB 的静态代码1被执行...");//1
    }
}

在这里插入图片描述

(2).子类对象实例化时,父类也会被加载,而且,父类先被加载,子类后被加载

    
         AA aa2 = new AA();
         
class BB {
    //静态代码块
    static {
        System.out.println("BB 的静态代码1被执行...");//1
    }
}

class AA extends BB {
    //静态代码块
    static {
        System.out.println("AA 的静态代码1被执行...");//2
    }
}

在这里插入图片描述

(3).使用类的静态变量时

         System.out.println(Cat.n1);


class Animal {
    //静态代码块
    static {
        System.out.println("Animal 的静态代码1被执行...");//
    }
}

class Cat extends Animal {
    public static  int n1 = 999;//静态属性
    //静态代码块
    static {
        System.out.println("Cat 的静态代码1被执行...");//
    }
}

在这里插入图片描述
可以看到,执行顺序是父类先加载执行父类的代码块,然后是子类的静态代码块,最后是子类的静态变量

(4).static代码块,是在类加载时,执行的,而且只会执行一次.

        DD dd = new DD();
        DD dd1 = new DD();
    }
}

class DD {
    //静态代码块
    static {
        System.out.println("DD 的静态代码1被执行...");//
    }
}

在这里插入图片描述

(5).普通的代码块,在创建对象实例时,会被隐式的调用。
被创建一次,就会调用一次。
如果只是使用类的静态成员时,普通代码块并不会执行

		DD dd = new DD();
        DD dd1 = new DD();
        System.out.println(DD.n1);//8888, 静态模块块一定会执行


class DD {
    public static int n1 = 8888;//静态属性
    //静态代码块
    static {
        System.out.println("DD 的静态代码1被执行...");//
    }
    //普通代码块, 在new 对象时,被调用,而且是每创建一个对象,就调用一次
    //可以这样简单的,理解 普通代码块是构造器的补充
    {
        System.out.println("DD 的普通代码块...");
    }
}

在这里插入图片描述
总结
(1).只有在创建对象时,普通构造器才会调用,调用静态成员时不会被调用
(2).创建对象实例和调用静态成员时静态代码块会被执行,静态代码块只会执行1次,还要注意类的3个加载方式…

代码块在一个类中的执行顺序
(1)如果有多个静态代码块和多个静态变量初始化,就看他们定义的顺序
(2)如果有多个普通代码块和多个普通变量初始化,就看他们定义的顺序
(3)最后看构造器

public class CodeBlockDetail02 {
    public static void main(String[] args) {
        A a = new A();// (1) A 静态代码块01 (2) getN1被调用...(3)A 普通代码块01(4)getN2被调用...(5)A() 构造器被调用
    }
}

class A {
    //静态属性的初始化
    private static  int n1 = getN1();

    static { //静态代码块
        System.out.println("A 静态代码块01");
    }

    public static int getN1() {
        System.out.println("getN1被调用...");
        return 100;
    }

    //无参构造器
    public A() {
        System.out.println("A() 构造器被调用");
    }

    private int n2 = getN2();//普通属性的初始化

    { //普通代码块
        System.out.println("A 普通代码块01");
    }

    public int getN2() { //普通方法/非静态方法
        System.out.println("getN2被调用...");
        return 200;
    }
}

在这里插入图片描述

构造器中隐含着super和调用普通代码块

public class CodeBlockDetail03 {
    public static void main(String[] args) {
        new BBB();//(1)AAA的普通代码块(2)AAA() 构造器被调用(3)BBB的普通代码块(4)BBB() 构造器被调用
    }
}

class AAA { //父类Object
    {
        System.out.println("AAA的普通代码块");
    }
    public AAA() {
        //(1)super()
        //(2)调用本类的普通代码块
        System.out.println("AAA() 构造器被调用....");
    }
}

class BBB extends AAA  {
    {
        System.out.println("BBB的普通代码块...");
    }
    public BBB() {
        //(1)super()
        //(2)调用本类的普通代码块
        System.out.println("BBB() 构造器被调用....");
    }
}

在这里插入图片描述

  1. 父类的静态代码块和静态属性(优先级一样,按定义顺序执行)
  2. 子类的静态代码块和静态属性(优先级一样,按定义顺序执行)
  3. 父类普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
  4. 父类的构造方法
  5. 子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
  6. 子类的构造方法
package codeblock_03;

public class CodeBlockDetail04 {
    public static void main(String[] args) {
        //(1) 进行类的加载
        //1.1 先加载 父类 A02 1.2 再加载 B02
        //(2) 创建对象
        //2.1 从子类的构造器开始
        new B02();//对象
    }
}

class A02 { //父类
    private static int n1 = getVal01();

    static {
        System.out.println("A02的一个静态代码块..");//(2)
    }

    {
        System.out.println("A02的第一个普通代码块..");//(5)
    }

    public int n3 = getVal02();//普通属性的初始化

    public static int getVal01() {
        System.out.println("getVal01");//(1)
        return 10;
    }

    public int getVal02() {
        System.out.println("getVal02");//(6)
        return 10;
    }

    public A02() {//构造器
        //隐藏
        //super()
        //普通代码和普通属性的初始化......
        System.out.println("A02的构造器");//(7)
    }

}


class B02 extends A02 { //

    private static int n3 = getVal03();

    static {
        System.out.println("B02的一个静态代码块..");//(4)
    }

    public int n5 = getVal04();

    {
        System.out.println("B02的第一个普通代码块..");//(9)
    }

    public static int getVal03() {
        System.out.println("getVal03");//(3)
        return 10;
    }

    public int getVal04() {
        System.out.println("getVal04");//(8)
        return 10;
    }

    public B02() {//构造器
        //隐藏了
        //super()
        //普通代码块和普通属性的初始化...
        System.out.println("B02的构造器");//(10)

    }
}

在这里插入图片描述

1.静态代码块只能调用静态成员
2.普通代码块可以调用所有成员


public class CodeBlockDetail05 {
    public static void main(String[] args) {

        new C02();
    }

}


class C02 {
    private int n1 = 100;
    private static int n2 = 200;

    private void m1() {

    }

    private static void m2() {

    }

    static {
        //静态代码块,只能调用静态成员
        //System.out.println(n1);错误
        System.out.println(n2);//ok
        //m1();//错误
        m2();
    }

    {
        //普通代码块,可以使用任意成员
        System.out.println(n1);
        System.out.println(n2);//ok
        m1();
        m2();
    }
}

在这里插入图片描述

3.3🍒代码块练习题

public class CodeBlockExercise01 {
    public static void main(String[] args) {
        System.out.println("total = "+ Person.total); //100
        System.out.println("total = "+ Person.total); //100
    }
}
class Person {
    public static int total;//静态变量
    static {//静态代码块
        total = 100;
        System.out.println("in static block!");//(1)
    }
}

在这里插入图片描述


public class CodeBlockExercise02 {
}

class Sample
{
    Sample(String s)
    {
        System.out.println(s);
    }
    Sample()
    {
        System.out.println("Sample默认构造函数被调用");
    }
}
class Test{
    Sample sam1=new Sample("sam1成员初始化");//
    static Sample sam=new Sample("静态成员sam初始化 ");//
    static{
        System.out.println("static块执行");//
        if(sam==null)System.out.println("sam is null");
    }
    Test()//构造器
    {
        System.out.println("Test默认构造函数被调用");//
    }
    //主方法
    public static void  main(String  str[])
    {
        Test a=new Test();//无参构造器
    }

}

在这里插入图片描述

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值