Day 12 (static、单例设计模式与final关键字)

1、使用static修饰属性,即静态变量,按照static是否修饰属性,可以分为静态属性和非静态属性(实例变量)。

        (1)非静态属性:创建类的多个对象,每个对象都独立拥有类中的一套非静态变量,当修改其中一个对象的非静态属性时,不会改变其他对象的属性值;

        (2)静态属性:创建类的多个对象,多个对象共享同一个静态变量,当通过某个对象修改静态变量值后,其他对象调用该静态变量时,值是被修改过的;

  • 静态变量随着类的加载而加载,可以通过“类.静态变量”来进行调用或赋值
  • 静态变量早于对象的加载
  • 类只会加载一次,因此静态变量也只会加载一次,存在方法的静态区中 

2、static修饰方法,即静态方法

  • 静态变量随着类的加载而加载,可以通过“类.静态方法”来进行调用
  • 在静态方法中,不能使用this、super关键字,不能调用静态结构(方法或属性),可以调用静态结构(方法或属性)

3、static练习题

public class exe08 {
    public static void main(String[] args) {
        Account a1 = new Account();
        Account a2 = new Account("900990",10000);
        //直接"类名.静态方法名"来设置static变量值
        Account.setInterestRate(0.012);
        Account.setMinAmount(100);
        System.out.println(a1);
        System.out.println(a2);
        //采用对象获取static方法
        System.out.println(a1.getMinAmount());   //100.0
        System.out.println(a2.getInterestRate());  //0.012
    }
}


//Account类的创建
class Account{
    private int id;
    private String password = "000000";
    private double balance;
    //声明为static静态变量
    private static double interestRate;
    private static double minAmount = 1.0;
    //用于自动生成账户id号
    private static int init = 1001;
    public Account(){
        //账号自动加一
        id = init++;
    }
    public Account(String password,double balance){
        //有参构造器id也要自动加一
        id = init++;
        this.balance = balance;
        this.password = password;
    }
    //相关set、get方法  对应静态变量的相关方法也是静态方法
    public int getId() {
        return id;
    }

    public String getPassword() {
        return password;
    }

    public double getBalance() {
        return balance;
    }

    public static double getInterestRate() {
        return interestRate;
    }

    public static double get() {
        return minAmount;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }

    public static void setInterestRate(double interestRate) {
        Account.interestRate = interestRate;
    }
    public static double setInterestRate(){
        return interestRate;
    }
    public static void setMinAmount(double minBalance) {
        Account.minAmount = minBalance;
    }
    public static double getMinAmount(){
        return minAmount;
    }
}

4、单例(singleton)设计模式

        单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造器的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无 法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的

饿汉式单例设计模式
public class Singleton1Test {
    public static void main(String[] args) {
        Singleton1 s1 = Singleton1.getInstance();
        Singleton1 s2 = Singleton1.getInstance();
        System.out.println(s1 == s2);  //true
    }
}
//
//class Singleton1 {
//    // 1.私有化构造器  类外部无法创建该类的实例
//    private Singleton1() {
//    }
//
//    // 2.内部创建当前类的实例
//    // 4.此实例也必须静态化
//    private static Singleton1 single = new Singleton1();
//
//    // 3.提供公共的静态的方法,返回当前类的对象
//    public static Singleton1 getInstance() {
//        if (single == null) { //为空则提供一个新对象
//            single = new Singleton1();
//        }
//        return single; //否则返回该对象
//    }
//}


//懒汉式单例设计  (不安全的)
class Singleton1 {
    // 1.私有化构造器
    private Singleton1() {
    }
    // 2.内部提供一个当前类的实例
// 4.此实例也必须静态化
    private static Singleton1 single;
    // 3.提供公共的静态的方法,返回当前类的对象
    public static Singleton1 getInstance() {
        if(single == null) {
            single = new Singleton1();
        }
        return single; } }

5、代码块的使用

(代码块先于构造器的执行)

        作用:用来初始化类、对象

        划分:只能用static修饰,分为static代码块和非static代码块

        (1)static代码块

  • 可以有输出语句
  • 随着类的加载而执行(static方法和static属性是随着类的加载而加载),而且只执行一次
  • 可以有多个static代码块,按照声明的先后顺序执行
  • static代码块的执行优先于非static代码块的执行
  • static代码块中只能调用static型的属性或方法,不能调用非static的结构
  • 作用:初始类的信息

        (2)非static代码块

  • 可以有输出语句
  • 随着对象的创建而执行,每创建一次对象就执行一次非static代码块
  • 可以调用static或者非static的属性和方法(即可以修改static属性值)
  • 作用:可以在创建对象时,对对象进行初始化操作
public class CodeBlockTest {
    public static void main(String[] args) {
        String str1 = Animal.str; //执行static代码块
        System.out.println(Animal.str);
        System.out.println(Animal.info()); //没有执行static代码块
        Animal dog = new Animal(); //执行非static代码块
        System.out.println(dog.name); //在非static代码块中对name做了初始化
        System.out.println(dog.str);  //在非static代码块中修改了static变量
        System.out.println(Animal.str); //输出在非代码块中修改过的static属性值
    }
}

class Animal{
    //属性
    String name;
    int age;
    static String str = "未修改的str";
    //构造器
    public Animal(){
    }
    public Animal(String name,int age){
        this.name = name;
        this.age = age;
    }
    //代码块
    //用satic修饰的代码块
    static {
        System.out.println("static codeBlock");
        str = "在static代码块修改过的str";
    }
    static {
        System.out.println("static codeBlock 1");
    }
    //非static代码块
    {
        System.out.println("non static codeBlock");
        str = "在非static代码块中修改过的str";
        name = "旺财";
    }

    //方法
    public void play(){
        System.out.println("playing...");
    }
    //toString()方法的重写
    @Override
    public String toString() {
        return "Animal{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    //静态方法
    public static String info(){
        return "It's a kind of animal";
    }
}

        

 6、代码块练习题

(先执行父类(先执行所有static代码块),再执行子类(先执行非static代码块,后执行构造器))

        练习题1:

//先执行父类后执行子类  先执行static代码块 后执行非static代码块 在执行构造器

class Root {
    static {
        System.out.println("Root的静态初始化块");
    }

    {
        System.out.println("Root的普通初始化块");
    }

    public Root() {
        System.out.println("Root的无参数的构造器");
    }
}

class Mid extends Root {
    static {
        System.out.println("Mid的静态初始化块");
    }

    {
        System.out.println("Mid的普通初始化块");
    }

    public Mid() {
        System.out.println("Mid的无参数的构造器");
    }

    public Mid(String msg) {
        //通过this调用同一类中重载的构造器
        this();
        System.out.println("Mid的带参数构造器,其参数值:"
                + msg);
    }
}

class Leaf extends Mid {
    static {
        System.out.println("Leaf的静态初始化块");
    }

    {
        System.out.println("Leaf的普通初始化块");
    }

    public Leaf() {
        //通过super调用父类中有一个字符串参数的构造器
        super("尚硅谷");
        System.out.println("Leaf的构造器");
    }
}

public class LeafTest {
    public static void main(String[] args) {
        new Leaf();
        //new Leaf();
    }
}

输出:

练习题2:

class Father {
	static {
		System.out.println("11111111111");
	}
	{
		System.out.println("22222222222");
	}
	public Father() {
		System.out.println("33333333333");
	}
}
public class Son extends Father {
	static {
		System.out.println("44444444444");
	}
	{
		System.out.println("55555555555");
	}
	public Son() {
		System.out.println("66666666666");
	}
	public static void main(String[] args) { // 由父及子 静态先行
		new Son();
		System.out.println("************************");

		new Son();
		System.out.println("************************");
		
		new Father();
	}
}

输出:

 7、属性赋值顺序

        (1)默认初始化赋值(默认赋值)

        (2)显式赋值(类中初始化时赋值)

        (3)代码块赋值

        (4)构造器初始化(构造器内部赋值)

        (5)“对象.属性”  “对象.方法” 赋值

                执行顺序:(1)- (2)/(5)- (3)-(4)

8、final关键字

  • 用来修饰类,此类不能被继承,比如String、System、StringBuffer类
  • 用来修饰方法,此方法不能被重写,比如Object类的getClass()方法
  • 用来修饰变量,此变量成为常量,此时可以赋值的位置可以是:显式赋值、代码块中赋值、构造器中赋值。(不能采用“对象.属性”  “对象.方法”来赋值,因为在使用构造器声明对象后,推空间里就必须有final修饰的变量的值存在,而方法此时还未被调用
class finalT{
    //显式赋值
    final int num1 = 1;
    final int num2;
    final int num3;
    //代码块中赋值
    {
        num2 = 2;
    }
    //构造器中赋值
    public finalT(){
        num3 = 3;
    }
    //final修饰的方法
    final public void print(){
        System.out.println("yeah");
    }
}
  • static final修饰的属性称为全局常量
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值