day15_static丶单列模式丶代码块丶final

关键字static

当我们编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上 的对象,只有通过new关键字才会产生出对象,这时系统才会分配内存空间给对象, 其方法才可以供外部调用。我们有时候希望无论是否产生了对象或无论产生了多少 对象的情况下,某些特定的数据在内存空间里只有一份,例如所有的中国人都有个 国家名称,每一个中国人都共享这个国家名称,不必在每一个中国人的实例对象中 都单独分配一个用于代表国家名称的变量。

  • 一般情况下类中的变量是一个实例变量(instance variable),它属于类的 每一个对象,不能被同一个类的不同对象所共享。
  • 如果想让一个类的所有实例共享数据,就用类变量!

类属性、类方法的设计思想

  • 类属性作为该类各个对象之间共享的变量。在设计类时,分析哪 些属性不因对象的不同而改变,将这些属性设置为类属性。相应 的方法设置为类方法。
  • 如果方法与调用者无关,则这样的方法通常被声明为类方法,由 不需要创建对象就可以调用类方法,从而简化了方法的调用。

关键字:static

使用范围:

  • 在Java类中,可用static修饰属性、方法、代码块、内部类

被修饰后的成员具备以下特点:

  • 随着类的加载而加载,由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法区的静态域中。
  • 优先于对象存在
  • 修饰的成员,被所有对象所共享
  • 访问权限允许时,可不创建对象,直接被类调用

static修饰属性:静态变量(或类变量)

格式:

举例

package demo03;
 
public class Student {
    private String name;
    private int age;
    // 学生的id
    private int sid;
    // 类变量,记录学生数量,分配学号
    public static int numberOfStudent = 0;
 
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
        // 通过 numberOfStudent 给学生分配学号
        this.sid = ++numberOfStudent;
    }
 
    // 打印属性值
    public void show() {
        System.out.println("Student : name=" + name + ", age=" + age + ", sid=" + sid);
    }
}

定义测试类

package demo03;
 
public class Student {
    private String name;
    private int age;
    // 学生的id
    private int sid;
    // 类变量,记录学生数量,分配学号
    public static int numberOfStudent = 0;
 
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
        // 通过 numberOfStudent 给学生分配学号
        this.sid = ++numberOfStudent;
    }
 
    // 打印属性值
    public void show() {
        System.out.println("Student : name=" + name + ", age=" + age + ", sid=" + sid);
    }
}

总结:

  • 类变量(类属性)由该类的所有实例共享
  • 没有对象的实例时,可以用类名.方法名()的形式访问由static修饰的类方法。
  • static方法内部只能访问类的static修饰的属性或方法,不能访问类的非static的结构。
  • 因为不需要实例就可以访问static方法,因此static方法内部不能有this(不能有super ? YES!)
  • static修饰的方法不能被重写

静态方法

当 static 修饰成员方法时,该方法称为类方法 。静态方法在声明中有 static ,建议使用类名来调用,而不需要创建类的对象。调用方式非常简单。

  • 类方法:使用 static关键字修饰的成员方法,习惯称为静态方法。

定义格式:

注意事项: 

  • 静态不能直接访问非静态。原因:因为在内存当中是【先】有的静态内容,【后】有的非静态内容。
  • 静态方法当中不能用this。原因:this代表当前对象,通过谁调用的方法,谁就是当前对象。

调用

  • 被static修饰的成员可以并且建议通过类名直接访问。虽然也可以通过对象名访问静态成员,原因即多个对象均属于一个类,共享使用同一个静态成员,但是不建议,会出现警告信息。

格式:

静态原理图解 

static 修饰的内容:

  • 是随着类的加载而加载的,且只加载一次。
  • 存储于一块固定的内存区域(静态区),所以,可以直接被类名调用。
  • 它优先于对象存在,所以,可以被所有对象共享。 

                           

单例 (Singleton)设计模式

  • 设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、 以及解决问题的思考方式。设计模免去我们自己再思考和摸索。就像是经典的棋谱,不同的棋局,我们用不同的棋谱。”套路”
  • 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对 某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。 如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造器的访问权限设置为private,这样,就不能用new操作符在类的外部产生 类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无 法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象, 静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象 的变量也必须定义成静态的。

饿汉式

 
/*
 * 单例设计模式:
 * 1. 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例。
 * 
 * 2. 如何实现?
 * 	 饿汉式  vs 懒汉式
 * 
 * 3. 区分饿汉式 和 懒汉式
 *   饿汉式:	
 *   	坏处:对象加载时间过长。
 *   	好处:饿汉式是线程安全的
 *   
 *   懒汉式:好处:延迟对象的创建。
 * 		  目前的写法坏处:线程不安全。--->到多线程内容时,再修改
 * 
 * 
 */
public class SingletonTest1 {
	public static void main(String[] args) {
//		Bank bank1 = new Bank();
//		Bank bank2 = new Bank();
		
		Bank bank1 = Bank.getInstance();
		Bank bank2 = Bank.getInstance();
		
		System.out.println(bank1 == bank2);
	}
}
 
//饿汉式
class Bank{
	
	//1.私有化类的构造器
	private Bank(){
		
	}
	
	//2.内部创建类的对象
	//4.要求此对象也必须声明为静态的
	private static Bank instance = new Bank();
	
	//3.提供公共的静态的方法,返回类的对象
	public static Bank getInstance(){
		return instance;
	}
}

懒汉式

 
/*
 * 单例模式的懒汉式实现
 * 
 */
public class SingletonTest2 {
	public static void main(String[] args) {
		
		Order order1 = Order.getInstance();
		Order order2 = Order.getInstance();
		
		System.out.println(order1 == order2);
		
	}
}
 
 
class Order{
	
	//1.私有化类的构造器
	private Order(){
		
	}
	
	//2.声明当前类对象,没有初始化
	//4.此对象也必须声明为static的
	private static Order instance = null;
	
	//3.声明public、static的返回当前类对象的方法
	public static Order getInstance(){
		
		if(instance == null){
			
			instance = new Order();
			
		}
		return instance;
	}
	
}

单例模式的优点:

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

单例(Singleton)设计模式-应用场景

  • 网站的计数器,一般也是单例模式实现,否则难以同步。
  • 应用程序的日志应用,一般都使用单例模式实现,这一般是由于共享的日志 文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
  • 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库 资源。
  • 项目中,读取配置文件的类,一般也只有一个对象。没有必要每次使用配置 文件数据,都生成一个对象去读取。
  • Application 也是单例的典型应用
  • Windows的Task Manager (任务管理器)就是很典型的单例模式
  • Windows的Recycle Bin (回收站)也是典型的单例应用。在整个系统运行过程 中,回收站一直维护着仅有的一个实例。

理解main方法的语法

  • 由于Java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是 public,又因为Java虚拟机在执行main()方法时不必创建对象,所以该方法必须 是static的,该方法接收一个String类型的数组参数,该数组中保存执行Java命令时传递给所运行的类的参数。
  • 又因为main() 方法是静态的,我们不能直接访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员,这种情况,我们在之前的例子中多次碰到。
 
/*
 * main()方法的使用说明:
 * 1. main()方法作为程序的入口
 * 2. main()方法也是一个普通的静态方法
 * 3. main()方法可以作为我们与控制台交互的方式。(之前:使用Scanner)
 * 
 * 
 * 
 */
public class MainTest {
	
	
	public static void main(String[] args) {//入口
		
		Main.main(new String[100]);
		
		MainTest test = new MainTest();
		test.show();
		
	}	
	public void show(){
		
	}
}
 
 
class Main{
		
	public static void main(String[] args) {
	
		for(int i = 0;i < args.length;i++){
			args[i] = "args_" + i;
			System.out.println(args[i]);
		}
		
	}
	
}

代码块

代码块(或初始化块)的作用:

  • Java类或对象进行初始化

代码块(或初始化块)的分类:

  • 一个类中代码块若有修饰符,则只能被static修饰,称为静态代码块
  • (static block),没有使用static修饰的,为非静态代码块。

static代码块通常用于初始化static的属性

class Person {
public static int total;
    static {
        total = 100;//为total赋初值
    }
…… //其它属性或方法声明
}

静态代码块:用static 修饰的代码块

  • 可以有输出语句。
  • 可以对类的属性、类的声明进行初始化操作。
  • 不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。
  • 若有多个静态的代码块,那么按照从上到下的顺序依次执行。
  • 静态代码块的执行要先于非静态代码块。
  • 静态代码块随着类的加载而加载,且只执行一次。

非静态代码块:没有static修饰的代码块

  • 可以有输出语句。
  • 可以对类的属性、类的声明进行初始化操作。
  • 除了调用非静态的结构外,还可以调用静态的变量或方法。
  • 若有多个非静态的代码块,那么按照从上到下的顺序依次执行。
  • 每次创建对象的时候,都会执行一次。且先于构造器执行

举例

class Person {
public static int total;
    static {
    total = 100;
    System.out.println("in static block!");
    } 
}
public class PersonTest {
    public static void main(String[] args) {
    System.out.println("total = " + Person.total);
    System.out.println("total = " + Person.total);
    } 
}

 总结:程序中成员变量赋值的执行顺序

                         

关键字:final

概述:学习了继承后,我们知道,子类可以在父类的基础上改写父类内容,比如,方法重写。那么我们能不能随意的继承API中提供的类,改写其内容呢?显然这是不合适的。为了避免这种随意改写的情况,Java提供了 final 关键字,用于修饰不可改变内容。final: 不可改变。可以用于修饰类、方法和变量。

修饰类

格式如下:

查询API发现像 public final class String 、 public final class Math 、 public final class Scanner等,很多我们学习过的类,都是被final修饰的,目的就是供我们使用,而不让我们所以改变其内容。

含义:

  • 当前这个类不能有任何的子类。(太监类)

注意:

  • 一个类如果是final的,那么其中所有的成员方法都无法进行覆盖重写(因为没儿子。)

举例:

package demo01;
 
 
public abstract class Fu {
 
    public final void method() {
        System.out.println("父类方法执行!");
    }
 
    public abstract /*final*/ void methodAbs();
 
}

修饰方法

格式如下:

含义:

  • 当final关键字用来修饰一个方法的时候,这个方法就是最终方法,也就是不能被覆盖重写。

注意事项:

  • 对于类、方法来说,abstract关键字和final关键字不能同时使用,因为矛盾。

举例:

修饰局部变量 

  • 基本类型的局部变量,被final修饰后,只能赋值一次,不能再更改。代码如下:
public class Demo {
    public static void main(String[] args) {
        // 声明变量,使用final修饰
        final int a; // 第一次赋值
        a = 10;
        // 第二次赋值 a = 20;  报错,不可重新赋值
 
        // 声明变量,直接赋值,使用final修饰
        final int b = 10;
        // 第二次赋值 b = 20; 报错,不可重新赋值
    }
}

引用类型的局部变量,被final修饰后,只能指向一个对象,地址不能再更改。但是不影响对象内部的成员变量值的修改,代码如下:

public class Demo {
    public static void main(String[] args) {
        // 创建 User 对象
        final User u = new User();
        // 创建 另一个 User对象 u = new User();  报错,指向了新的对象,地址值改变。
            
        // 调用setName方法 
        u.setName("张三"); // 可以修改 
    }
}

修饰成员变量

对于成员变量来说,如果使用final关键字修饰,那么这个变量也照样是不可变。

  • 由于成员变量具有默认值,所以用了final之后必须手动赋值,不会再给默认值了。
  • 对于final的成员变量,要么使用直接赋值,要么通过构造方法赋值。二者选其一。
  • 必须保证类当中所有重载的构造方法,都最终会对final的成员变量进行赋值。

显示初始化;

public class Demo {
    final String USERNAME = "张三";
    private int age;
}

​​构造方法初始化

public class Demo {
    final String USERNAME;
    private int age;
 
    public Demo(String username, int age) {
        this.USERNAME = username;
        this.age = age;
    }
}
发布了20 篇原创文章 · 获赞 7 · 访问量 6615

猜你喜欢

转载自blog.csdn.net/weixin_44462792/article/details/105049861
今日推荐