栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

day14笔记:java中的static关键字、单例设计模式(饿汉式、懒汉式)、代码块的使用、final关键字

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

day14笔记:java中的static关键字、单例设计模式(饿汉式、懒汉式)、代码块的使用、final关键字

java中的static关键字、单例设计模式(饿汉式、懒汉式)、代码块的使用、final关键字
  • 1、static关键字
  • 2、单例(Singleton)的设计模式
  • 3、理解main()函数的语法(了解)
  • 4、代码块
  • 5、final 关键字

1、static关键字

1、static 静态的
2、static 可以用来修饰:属性、方法、代码块、内部类,不能用来修饰构造器

3、使用static修饰属性:静态变量(类变量)
  3.1、属性,按是否使用static修饰,分为:静态属性 和 非静态属性(实例变量)
实例变量: 当我们创建了多个对象,每个对象都独立的拥有一套类中的非静态属性,当修改其中一个对象中的非静态属性时,不会导致其他对象中的同样属性值的修改。(实例变量随着类的创建而加载,在实例化变量的时候才会被加载)
静态变量: 当我们创建了多个对象,多个对象共享同一个静态变量,当通过某个对象修改静态变量时,会导致其他对象调用此对象时是修改过的。(静态变量随着类的加载而加载)
可以理解为实例变量是房间里的东西,静态变量是客厅里的东西,房间里的东西是每个房间主人的,客厅里的东西是共有的。

  3.2、static修饰属性的其他说明。
(1)、静态变量随着类的加载而加载。可以通过 类.变量名 的方式来调用。
(2)、静态变量的加载早于对象的创建。
(3)、由于类只会加载一次,则静态变量在内存也只存在一份,存在方法区的静态域中。
(4)、可否通过类,对象去调用实例变量?

类变量实例变量
yesno
对象yesyes

  3.3、静态属性举例,System.out,Math.PI。

public class StaticTest {
    public static void main(String[] args) {
        Chinese c1 = new Chinese();
        c1.name = "XiaoMing";
        c1.age = 40;
        c1.nation = "CHN";//给c1的static nation赋值为CHN

        Chinese c2 = new Chinese();
        c2.name = "PanHu";
        c2.age = 30;
        //此时堆空间中有c1和c2两个对象,
        //age每个对象各有一份,修改一个属性时,不会影响另一个对象属性值修改。
        System.out.println(c2.nation);//注:nation只给了c1赋值,没有给c2赋值   输出结果CHN。

        //给c2的赋值static nation赋值,再输出c1的nation
        c2.nation = "CHINA";
        System.out.println(c1.nation);//输出结果CHINA
    }
}
//中国人
class Chinese{
    String name;
    int age;
    static String nation;
}

内存结构如下:
栈:主要存局部变量
堆:new出来的结构(对象、数组)
方法区:类的加载信息、静态域、常量池

类变量与实例变量内存的解析:
4、使用static修饰的方法,静态方法
(1)、随着类的加载而加载
(2)、可否通过类或对象调用静态或非静态方法?

静态方法非静态方法
yesno
对象yesyes
public class Static_test {
    public static void main(String[] args) {
        Static_test.run();//类名.方法名 调用
//        Static_test s = new Static_test();
//        s.eat();//需要实例化对象才能调用
    }
    public void eat(){
        System.out.println("干饭!");
    }
    public static void run(){
        System.out.println("跑的贼快!");
        //eat();
    }
}

(3)、在静态的方法中,只能调用静态的方法或属性,对于非静态方法,既可以调用非静态的方法或属性,也可以调用静态的方法或属性。(主要原因是静态方法是类加载的时候就已经加载了,而非静态方法需要在类被实例化的时候才会被加载,生命周期没有静态变量长)
5、static注意点
(1)、在静态方法内,不能使用this关键字、super关键字。(静态结构前面省略的关键字不是 this. 或 super. ,省略的是 类名.)
(2)、关于静态属性和静态方法的使用,都可以从生命周期的角度去理解。

总结:
在开发中,如何确定一个属性是否要声明成static?

属性是可以被多个对象所共享的,不会随着对象的不同而不同的
类中的常量也常常声明为static

在开发中,如何确定一个方法是否要声明成static?

操作静态属性的方法,通常设置为静态的
工具类中的方法,习惯上声明的是static的,比如:Math、Arrays、Collection

例1:

//static关键字的应用,创建圆
public class CircleTest {
    public static void main(String[] args) {
        Circle c1 = new Circle();
        Circle c2 = new Circle();
        Circle c3 = new Circle();

        System.out.println("c1的id="+c1.getId());
        System.out.println("c2的id="+c2.getId());
        System.out.println("c3的id="+c3.getId());
        System.out.println("创建圆的个数:"+Circle.getTotal());
    }

}

class Circle{
    private double radius;
    private int id;
    public Circle(){//每次构造器调用,就指行下面操作,使得id自动增加
        id=init++;//体现共享的概念,init的值不会变回1001
        total++;
    }
    public Circle(double radius){
        this();//调用无参的Circle
//        id=init++;
//        total++;
        this.radius = radius;

    }
    private static int total=0; //基类圆的个数
    private static int init = 1001;//static声明的属性被所有对象共享。

    public double findArea(){
        return 3.14*radius*radius;
    }

    public double getRadius() {
        return radius;
    }

    public void setRadius(double radius) {
        this.radius = radius;
    }

    public int getId() {
        return id;
    }

    public static int getTotal() {
        return total;
    }
}

例2:
编写一个类实现银行账户的概念,包含的属性有“帐号”、“密码”、“存款余额”、“利率”、“最小余额”,定义封装这些属性的方法。账号要自动生成。
编写主类,使用银行账户类,输入、输出3个储户的上述信息。
考虑:哪些属性可以设计成static属性。

//账户类
public class Account {
    private int id;
    private String pwd = "000000";
    private double balance;

    private static double interestRate;
    private static double minMoney = 1.0;
    private static int init = 1001;//用于自动生成id

    public Account(){
        id = init++;//自动生成id
    }

    public Account(String pwd,double balance){//带参,设置账户
        id = init++;
        this.pwd = pwd;
        this.balance = balance;
    }

    public int getId() {
        return id;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    public double getBalance() {
        return balance;
    }

    public static double getInterestRate() {
        return interestRate;
    }

    public static void setInterestRate(double interestRate) {
        Account.interestRate = interestRate;
    }

    public static double getMinMoney() {
        return minMoney;
    }

    public static void setMinMoney(double minMoney) {
        Account.minMoney = minMoney;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", pwd='" + pwd + ''' +
                ", balance=" + balance +
                '}';
    }
}
//测试类
public class AccountTest {
    public static void main(String[] args) {
        Account acct1 = new Account();
        Account acct2 = new Account("123456",250);
        System.out.println(acct1.toString());//Account{id=1001, pwd='000000', balance=0.0}
        System.out.println(acct2.toString());//Account{id=1002, pwd='123456', balance=250.0}

        System.out.println(acct1.getInterestRate());//0.0
        System.out.println(acct1.getMinMoney());//1.0
    }
}


2、单例(Singleton)的设计模式

设计模式: 是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模免去我们自己再思考和摸索。
就像是经典的棋谱,不同的棋局,我们用不同的棋谱。”套路”

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

//1、单例设计模式就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。
//2、如何实现
public class SingletonTest1 {
    public static void main(String[] args) {
        //Bank bank = new Bank();
        Bank bank1 = Bank.getIntstance();
        Bank bank2 = Bank.getIntstance();

        System.out.println(bank1==bank2);//true
        //bank1和bank2是一样的,创建出来的对象是唯一的一个,称为单例
    }
}

//饿汉式
class Bank{
    //私有化构造器:目的是避免在bank类外面去调用构造器,即不能在类的外面实例化
    private Bank(){

    }
    //2、内部创建对象,要求此对象是静态的
    private static Bank intstance = new Bank();

    //3、提供公共的静态方法,返回类的对象
    public static Bank getIntstance(){
        return intstance;
    }
}

2、懒汉式

public class SingletonTest2 {
    public static void main(String[] args) {
        Order order1 = Order.getInstance();
        Order order2 = Order.getInstance();

        System.out.println(order1==order2);//true
    }
}

class Order{
    //1、提供私有的构造器
    private Order(){

    }
    //2、声明当前类对象,没有初始化
    private static Order instance = null;

    //3、声明一个public static的返回当前类的对象的方法
    public static Order getInstance(){
        if(instance==null) {//判断是否实例化过对象
            instance = new Order();
        }
            return instance;

    }
}

懒汉式和饿汉式的区别在于是否一开始就实例化好对象
饿汉式:一开始就实例化
坏处:对象加载时间过长,与static关键字相同。
好处:饿汉式是线程安全的。

 private static Bank intstance = new Bank();

懒汉式:不急着实例化
好处:延迟创建对象,不浪费内存空间。
目前写法坏处:线程不安全问题。

 private static Order instance = null;

单例设计模式的好处
由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。举例 java.lang.Runtime
应用场景

3、理解main()函数的语法(了解)
package Singleton_test;

public class MainTest {
    public static void main(String[] args) {//入口
        Main.main(new String[100]);

        MainTest mainTest = new MainTest();
        mainTest.show();
    }
    public void show(){

    }
}
class Main{
    public static void main(String[] args) {
        args = new String[100];
        for(int i=0;i 

面试题:
此处,Something类的文件名叫OtherThing.java

class Something {
public static void main(String[] something_to_do) { 
System.out.println("Do something ...");
}
}

上述程序是否可以正常编译、运行?

4、代码块

类的成员之四:代码块(初始化块)
1、代码块的作用:用来初始化类或者对象
2、代码块如果有修饰的话,只能使用static。
3、分类:静态代码块、非静态代码块。
4、静态代码块:

内部可以有输出语句
随着类的加载而执行,且只执行一次
作用:初始化类的信息
如果一个类中定义了多个静态代码块,那么按照声明的先后顺序执行
静态代码块的执行,优先于非静态代码块。
静态代码块内,只能调用静态的属性和静态的方法,不能调用非静态的结构

5、非静态代码块:

内部可以有输出语句
随着对象的创建而执行,且每创建一个对象,就执行一次
作用:可以在创建对象是,对对象的属性进行初始化。
(对属性可以赋值的位置:默认初始化、显示初始化、构造中初始化、有了对象以后,可以通过“对象,属性“或”对象,方法"的方式,进行赋值、在代码块中赋值)
如果一个类中定义了多个非静态代码块,那么按照声明的先后顺序执行
非静态的代码块内,可以调用静态的属性,静态的方法或非静态的属性和非静态的方法
非静态代码块的执行顺序小于构造函数

构造器与静态代码块的先后是静态代码块优先

public class BlockTest {
    public static void main(String[] args) {
        Person.desc = Person.desc;
        System.out.println(Person.desc);//My name is XiaoMing
        Person p1 = new Person();
        Person p2 = new Person();
    }
}

class Person{
    //属性
    String name;
    int age;
    static String desc = "我是一个人";
    //构造器
    public Person(){
        System.out.println("123");
    }
    public  Person(String name,int age){

        this.age = age;
        this.name = name;
    }

    //代码块
    static {
        System.out.println("hello,static block-1");
        desc = "My name is XiaoMing";
    }
    static {
        System.out.println("hello,static block-2");
        desc = "My name is XiaoMing";
        run();//调用静态方法
        //eat()//不能调用非静态的方法
    }

    {
        System.out.println("hello,block");
        run();//调用静态方法
        eat();//调用非静态方法
    }

    //方法
    public void eat(){
        System.out.println("干饭!");
    }
    public static void run(){
        System.out.println("跑的贼快!");
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }
}

hello,static block-1
hello,static block-2
跑的贼快!
My name is XiaoMing
hello,block
跑的贼快!
干饭!
123
hello,block
跑的贼快!
干饭

例1:

//总结:由父及子,静态先行
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();
	}
}

Root的静态初始化块
Mid的静态初始化块
Leaf的静态初始化块
Root的普通初始化块
Root的无参数的构造器
Mid的普通初始化块
Mid的无参数的构造器
Mid的带参数构造器,其参数值:父类
Leaf的普通初始化块
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) { // 由父及子 静态先行
		System.out.println("77777777777");
		System.out.println("************************");
		new Son();
		System.out.println("************************");

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

11111111111
44444444444
77777777777


22222222222
33333333333
55555555555
66666666666


22222222222
33333333333
55555555555
66666666666


22222222222
33333333333

//对属性可以赋值的位置:
// 1、默认初始化、
// 2、显示初始化、
// 3、构造中初始化、
// 4、有了对象以后,可以通过“对象,属性“或”对象,方法"的方式,进行赋值、
// 5、在代码块中赋值
//顺序:1--2/5--3--4
public class OrderTest {
    public static void main(String[] args) {
        Order order = new Order();
        System.out.println(order.orderId);
    }
}

class Order{
    {
        orderId = 4;
    }
    int orderId = 3;

}
5、final 关键字

final:最终的
1、final可以用来修饰的结构:类、方法、变量

2、final修饰一个类:此类不能被其他类所继承,如:String类、System类、StringBuffer类等

3、final修饰一个方法:表明此方法不能被重写。 如:Object类中的getClass();

4、final 修饰一个变量:此时的”变量“就称为是一个常量。
    4.1、final修饰一个属性,可以考虑的位置有:显示初始化,代码块中赋值、初始化、构造器中初始化
    4.2、final修饰一个局部变量:尤其是使用final来修饰形参时,表示此形参是一个常量,我们调用此方法时,给常量赋一个实参,一旦赋值以后,就只能在此方法体内使用,但是不能修改。

static final :
用来修饰属性:全局常量。
用来修饰方法:该方法可直接通过类来调用,但这个方法,不能被重写

(1)final修饰一个类:此类不能被其他类所继承
2、final修饰一个方法:表明此方法不能被重写

3、修饰一个变量,这个变量不能被修改
4、final修饰一个局部变量

public class FinalTest {
    public static void main(String[] args) {
        FinalTest finalTest = new FinalTest();
        finalTest.show(20);
    }

    public void show(){
        final int NUM = 10;
       // NUM+=20;
    }
    public void show(final int num){
        System.out.println(num);//20
       // num=30//传入的形参只能使用,不能修改
    }
}

例1:

public class Something {
	public int addOne(final int x) {
		return ++x;//这个不行,x变化
		// return x + 1;//这个可以,x没变
	}
}

例2:

public class Something {
	public static void main(String[] args) {
		Other o = new Other();
		new Something().addOne(o);
	}
	public void addOne(final Other o) {
		// o = new Other();
		o.i++;//o是常量,但是i是变量
	}
}
class Other {
	public int i;
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/343603.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号