Java基础 DAY16

类变量和类方法

类变量(静态变量)

问题:有一群小孩在玩堆雪人,不时有新的小孩加入,请问如何知道现在共有多少人在玩?,编写程序解决。

传统的解决方法:
在这里插入图片描述

类变量快速入门

package com.static_;

public class ChildGame {
    public static void main(String[] args) {
    //定义一个变量 count, 统计有多少小孩加入了游戏
    int count = 0;

    Child child1 = new Child("白骨精");
    child1.join();
    //count++;
    child1.count++;

    Child child2 = new Child("狐狸精");
    child2.join();
    //count++;
    child2.count++;

    Child child3 = new Child("老鼠精");
    child3.join();
    //count++;
    child3.count++;

    //===========
    //类变量,可以通过类名来访问
    System.out.println("共有" + Child.count  + " 小孩加入了游戏...");
    //下面的代码输出什么
    System.out.println("child1.count=" + child1.count);//3
    System.out.println("child2.count=" + child2.count);//3
    System.out.println("child3.count=" + child3.count);//3
    }
}
class Child{ //类
    private String name;
    //定义一个变量 count ,是一个类变量(静态变量) static修饰-》 静态
    //该变量最大的特点就是会被Child类的所有的对象实例共享
    public static int count = 0;
    public Child(String name) {
        this.name = name;
    }
    public void join() {
        System.out.println(name + " 加入了游戏..");
    }

}

类变量的内存布局

静态变量放在哪里?

说法不一,但是不管static变量在哪里,共识:(1)static变量是同一个类所有对象共享(2)static类变量,在类加载的时候就生成了
在这里插入图片描述

什么是类变量

类变量也叫静态变量/静态属性,是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取到的都是相同的值,同样任何一个该类的对象去修改它时,修改的也是同一个变量。

如何定义类变量

在这里插入图片描述

如何访问类变量

在这里插入图片描述

package com.hspedu.static_;

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

        //类名.类变量名
        //说明:类变量是随着类的加载而创建,所以即使没有创建对象实例也可以访问
        System.out.println(A.name);
        A a = new A();
        //通过对象名.类变量名
        System.out.println("a.name=" + a.name);

    }
}

class A {
    //类变量
    //类变量的访问,必须遵守相关的访问权限.
    public static  String name = "education";
    //普通属性/普通成员变量/非静态属性/非静态成员变量/实例变量
    private int num = 10;

}

类变量使用注意事项和细节讨论

在这里插入图片描述
在这里插入图片描述

类方法(静态方法)

类方法快速入门

在这里插入图片描述
类方法的调用:
在这里插入图片描述

  1. 当方法使用了static修饰后,该方法就是静态方法
  2. 静态方法就可以访问静态属性/变量
package com.static_;

public class StaticMethod {
    public static void main(String[] args) {
        //创建2个学生对象,叫学费
        Stu tom = new Stu("tom");
        //tom.payFee(100);
        Stu.payFee(100);//对不对?对

        Stu mary = new Stu("mary");
        //mary.payFee(200);
        Stu.payFee(200);//对
        
        //输出当前收到的总学费
        Stu.showFee();//300
    }
}
class Stu{
    private String name;普通成员
    //定义一个静态变量,来累积学生的学费
    private static double fee = 0;

    public Stu(String name) {
        this.name = name;
    }

    //说明
    //1. 当方法使用了static修饰后,该方法就是静态方法
    //2. 静态方法就可以访问静态属性/变量
    public static void payFee(double fee){
        Stu.fee += fee;//累计
    }
    public static void showFee(){
        System.out.println("总学费有:" + Stu.fee);
    }
}

类方法经典使用场景

当方法中不涉及到任何和对象相关的成员,则可以将方法设计成静态方法,提高开发效率。
在这里插入图片描述
在实际开发中(开发自己的工具时),往往会将一些通用的方法,设计成静态方法,这样我们就不需要创建对象就可以使用了,比如打印一维数组,冒泡排序,完成某个计算任务。
在这里插入图片描述

类方法使用注意事项和细节讨论

在这里插入图片描述
在这里插入图片描述

package com.hspedu.static_;

public class StaticMethodDetail {
    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);//错误
    }
    
    //类方法(静态方法)中 只能访问 静态变量 或静态方法
    //口诀:静态方法只能访问静态成员.
    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:
在这里插入图片描述
(count先输出后++)

练习2:
在这里插入图片描述
练习3:
在这里插入图片描述

main方法语法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

main方法特别提示

在这里插入图片描述

package com.hspedu.main_;

public class Main01 {

    //静态的变量/属性
    private static  String name = "韩顺平教育";
    //非静态的变量/属性
    private int n1 = 10000;

    //静态方法
    public static  void hi() {
        System.out.println("Main01的 hi方法");
    }
    //非静态方法
    public void cry() {
        System.out.println("Main01的 cry方法");
    }

    public static void main(String[] args) {

        //可以直接使用 name
        //1. 静态方法main 可以访问本类的静态成员
        System.out.println("name=" + name);
        hi();
        //2. 静态方法main 不可以访问本类的非静态成员
        //System.out.println("n1=" + n1);//错误
        //cry();
        //3. 静态方法main 要访问本类的非静态成员,需要先创建对象 , 再调用即可
        Main01 main01 = new Main01();
        System.out.println(main01.n1);//ok
        main01.cry();
    }
}

main方法(idea传递参数)

在这里插入图片描述
如何在idea传递参数?
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

代码块

代码块基本介绍

基本介绍:

代码化块又称初始化块,属于类中的成员(即是类的一部分),类似于方法,将逻辑语句封装在方法体中,通过{}包围起来。
但和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显式调用,而是加载类时,或创建对象时隐式调用

基本语法在这里插入图片描述

代码块的好处

在这里插入图片描述

package com.static_.CodeBlock01;

public class codeBlock {
    public static void main(String[] args) {
        Movie movie = new Movie("hello");
        System.out.println("===============");
        Movie movie2 = new Movie("fine", 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;
    }

}

在这里插入图片描述

代码块使用注意事项和细节讨论

在这里插入图片描述
1)

package com.static_.CodeBlock01;

public class CodeBlockDetail01 {
    public static void main(String[] args) {
        //类被加载的情况举例
        //static代码块,是在类加载时,执行的,而且只会执行一次.
        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 的普通代码块...");
    }
}

在这里插入图片描述

2)① 创建对象实例时(new)

package com.static_.CodeBlock01;

public class CodeBlockDetail01 {
    public static void main(String[] args) {
        //类被加载的情况举例
        //2)① 创建对象实例时(new)
        AA aa = new AA();
    }
}
class AA {
    
    static {//静态代码块
        System.out.println("AA的静态代码块1被执行...");
    }
}

在这里插入图片描述
2)②创建子类对象实例,父类也会被加载, 而且,父类先被加载,子类后被加载

package com.static_.CodeBlock01;

public class CodeBlockDetail01 {
    public static void main(String[] args) {
        //类被加载的情况举例
        //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)③使用类的静态成员时(静态属性,静态方法)

package com.static_.CodeBlock01;

public class CodeBlockDetail01 {
    public static void main(String[] args) {
        //类被加载的情况举例
        //2)③使用类的静态成员时(静态属性,静态方法)
        System.out.println(Cat.n1);
    }
}
class Cat{
    public static  int n1 = 999;//静态属性
    static { //静态代码块
        System.out.println("Cat 的静态代码1被执行...");//
    }
}

在这里插入图片描述
例:创建子类对象实例,父类也会被加载, 而且,父类先被加载,子类后被加载(静态代码块也一样)

package com.static_.CodeBlock01;

public class CodeBlockDetail01 {
    public static void main(String[] args) {
        //类被加载的情况举例
        //2. 创建子类对象实例,父类也会被加载, 而且,父类先被加载,子类后被加载
       AA aa2 = new AA();
        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被执行...");
    }
}

在这里插入图片描述

在这里插入图片描述
静态优先,同级看顺序,最后构造器。

package com.static_.CodeBlock01;

public class CodeBlockDetail02 {
    public static void main(String[] args) {
          A a = new A();
    }
}
class A {
    { //普通代码块
        System.out.println("A 普通代码块01");
    }

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

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

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

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

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

}

在这里插入图片描述

package com.static_.CodeBlock01;

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() 构造器被调 用....");
    }
}

在这里插入图片描述

package com.static_.CodeBlock01;

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 { //B02子类

    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)
    }
}
package com.static_.CodeBlock01;

public class CodeBlockDetail04 {
    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();
    }
}

题 1:下面的代码输出什么?

package com.static_.CodeBlock01;

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

class Test {
    public static void main(String[] args) {
        System.out.println("total = "+ Person.total);
        //使用类的静态变量,类被加载,执行,且只会执行一次//100
        System.out.println("total = "+ Person.total);
        //100
    }
}

在这里插入图片描述
问题2:

package com.static_.CodeBlock01;

public class CodeBlockExercise02 {
}

class Sample
{
    Sample(String s)
    {
        System.out.println(s);
    }
    Sample()
    {
        System.out.println("Sample默认构造函数被调用");
    }
}
class Test02{
    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");
    }
    Test02()//构造器
    {
        System.out.println("Test默认构造函数被调用");//
    }
    //主方法
    public static void  main(String  str[])
    {
        Test02 a = new Test02();//无参构造器
    }
}

在这里插入图片描述
1、静态成员sam初始化
2、static块执行
3、sam1成员初始化
4、static块执行

单例设计模式

在这里插入图片描述

什么是单例模式

在这里插入图片描述

单例模式应用实例

instance:实例

单例饿汉式

在这里插入图片描述
步骤[单例模式-饿汉式]
1. 将构造器私有化
2. 在类的内部直接创建对象(该对象是static)
3. 提供一个公共的static方法,返回 gf对象

package com.hspedu.single_;

public class SingleTon01 {

    public static void main(String[] args) {
//        GirlFriend xh = new GirlFriend("小红");
//        GirlFriend xb = new GirlFriend("小白");

        //通过方法可以获取对象
        GirlFriend instance = GirlFriend.getInstance();
        System.out.println(instance);

        GirlFriend instance2 = GirlFriend.getInstance();
        System.out.println(instance2);

        System.out.println(instance == instance2);//T
        //System.out.println(GirlFriend.n1);//调用静态属性时会造成类的加载,
        //所以虽然没有调用对象但是gf会自动创建,但是沒有使用

        //...


    }

}

//有一个类, GirlFriend
//只能有一个女朋友
class GirlFriend {

    private String name;
    //public static  int n1 = 100;
    //为了能够在静态方法中,返回 gf对象,需要将其修饰为static
    //對象,通常是重量級的對象,饿汉式可能造成创建了对象,但是沒有使用.
    private static GirlFriend gf = new GirlFriend("小红红");

    //如何保障我们只能创建一个 GirlFriend 对象
    //步骤[单例模式-饿汉式]
    //1. 将构造器私有化
    //2. 在类的内部直接创建对象(该对象是static)
    //3. 提供一个公共的static方法,返回 gf对象
    private GirlFriend(String name) {
        System.out.println("構造器被調用.");
        this.name = name;
    }

    public static GirlFriend getInstance() {
        return gf;

    }

    @Override
    public String toString() {
        return "GirlFriend{" +
                "name='" + name + '\'' +
                '}';
    }
}

单例懒汉式

package com.static_.single_;

/**
 * 演示懒汉式的单例模式
 */
public class SingleTon02 {
    public static void main(String[] args) {
        //new Cat("大黃");
        //System.out.println(Cat.n1);
        Cat instance = Cat.getInstance();
        System.out.println(instance);


        //再次調用getInstance
        Cat instance2 = Cat.getInstance();
        System.out.println(instance2);

        System.out.println(instance == instance2);//T

    }
}


//希望在程序運行過程中,只能創建一個Cat對象
//使用單例模式
class Cat {
    private String name;
    public static  int n1 = 999;
    private static Cat cat ; //默認是null

    //步驟
    //1.仍然構造器私有化
    //2.定義一個static靜態屬性對象
    //3.提供一個public的static方法,可以返回一個Cat對象
    //4.懶漢式,只有當用戶使用getInstance時,才返回cat對象, 後面再次調用時,會返回上次創建的cat對象
    //  從而保證了單例
    private Cat(String name) {
        System.out.println("構造器調用...");
        this.name = name;
    }
    public static Cat getInstance() {

        if(cat == null) {//如果還沒有創建cat對象
            cat = new Cat("小可愛");
        }
        return cat;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                '}';
    }
}

final 关键字

final基本介绍

在这里插入图片描述

package com.static_.final_;

public class Final01 {
    public static void main(String[] args) {
            E e = new E();
             //e.TAX_RATE = 0.09;
    }
}
//要求A类不能被其他类继承
//可以用final修饰A类
final class A{}
//class B extends A{}

class C{
    //要求hi方法不能被子类重写
    //可以用final修饰hi方法
    public final void hi(){}
}
class D extends C{
//    @Override
//    public void hi() {
//        System.out.println("重写了C类的hi方法...");
//    }
}

//当不希望类的某个属性的值被修改,可以用final修饰
class E{
    public final double TAX_RATE = 0.08;
}

//当不希望某个局部变量被修改,可以使用final修饰
class F {
    public void cry() {
        //这时,NUM 也称为 局部常量
        final double NUM = 0.01;
        //NUM = 0.9;
        System.out.println("NUM=" + NUM);
    }
}

final 使用注意事项和细节讨论

在这里插入图片描述
在这里插入图片描述

final 应用实例

在这里插入图片描述

package com.static_.final_;

public class FinalExercise01 {
    public static void main(String[] args) {
        Circle circle = new Circle(5.0);
        System.out.println("面积=" + circle.calArea());
    }
}

class Circle {
    private double radius;
    private final double PI;// = 3.14;
    //构造器
    public Circle(double radius) {
        this.radius = radius;
        //PI = 3.14;
    }
    {
        PI = 3.14;
    }

    public double calArea() {
        return PI * radius * radius;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值