Java基础部分学习:06、类变量类方法、代码块、单例模式、final关键字

一、类变量:static

1、定义:

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

2、特点:

a、static变量是同一个类所有对象共享

b、static类变量,在类加载的时候就生成了,因此可以不用创建对象再来使用

public class Static01 {
  public static void main(String[] args) {
    System.out.println(AA.age);   // 无需创建对象
  }
}

class AA {
  public static int age = 20;
}
3、注意事项:

a、什么时候使用:需要让某个类的所有对象都共享一个变量时,就可以考虑使用类变量。

b、类变量与普通变量区别:

类变量是所有对象共享的,而实例变量是每个对象独享的。

c、类变量可以使用 类名.类变量名 或者 对象名.类变量名 来访问,但是推荐使用类名访问。

d、实例变量不可通过类名访问。

e、类变量实在类加载时就初始化了,即使没有创建对象,只要类加载了,就可以使用类变量了。

f、类变量的生命周期是随类的加载开始,随着类的消亡而销毁。

二、类方法:

1、使用与类变量一样。

2、注意事项:

a、类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区。

b、类方法可以通过类名调用,也可以通过对象名调用。

c、普通方法和对象有关,需要通过对象名调用,不能通过类名调用。

d、类方法中不允许使用和对象有关的关键字,比如this和super。

e、类方法(静态方法)中,只能访问静态变量或静态方法;普通方法可以访问非静态也可以访问静态成员

如果我们不想要创建对象也可以使用方法,那么就可以将该方法写成静态方法。

3、关于main方法:

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

1、main方法是由虚拟机来调用。

2、因为是JVM调用,因此访问权限必须是public。

3、JVM在执行main()方法时,不必创建对象,所以该方法必须是static。

4、该方法接收String类型的数组参数,该数组中保存执行Java命令时传递参数。
就是在Java 文件名时传递参数。

4、代码块

1、定义:

代码块又称为初始化块,属于类中的成员,将逻辑语句封装在方法体中,通过{}包围起来。

理解:
a、相当于对构造器的补充,可以做构造器初始化。
b、使用场景:如果多个构造器都有重复的语句,可以抽取到代码块中,提高代码的重用性。
c、每个构造器都会自动调用代码块的内容。

2、分类:

普通代码块、静态代码块(有static修饰)

public class Block {
  public static void main(String[] args) {
    new AA("张三");     // 每个构造器都会自动调用代码块内容
    new AA(20, "李四");
  }
}

class AA {
  private int age;
  private String name;

  {
    System.out.println("我是代码块1");
    System.out.println("我是代码块2");
    System.out.println("我是代码块3");
  }

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

  public AA(int age, String name) {
    this.age = age;
    this.name = name;
  }
}

3、代码块的理解:

a、相当于另一种形式的构造器,可以做初始化操作。

b、使用场景:如果多个构造器都有重复语句,可以抽取到到代码块中,提高代码重用性。


创建对象内存图:

在这里插入图片描述


静态代码块:

static {
	System.out.println("我是静态代码块");
}

1、作用:就是对类进行初始化,它随着类的加载而执行,并且只会执行一次。如果是普通代码块,每次创建一个对象,就会执行一次

2、类什么时候被加载:

a、创建对象实例时(new)。

public static void main(String[] args) {
	Cat cat = new Cat();  // 输出:我是Cat的静态代码块
}
class Cat {
	static {
		System.out.println("我是Cat的静态代码块");
	}
}

b、创建子类对象实例时,父类也会被加载:类的加载顺序:先加载父类,再子类

public static void main(String[] args) {
	Cat cat = new Cat();  // 输出:我是Animal的静态代码块;我是Cat的静态代码块
}
class Animal {
		static {
		System.out.println("我是Animal的静态代码块");
	}
}

class Cat extends Animal{
	static {
		System.out.println("我是Cat的静态代码块");
	}
}

c、使用类的静态成员时(静态成员、静态方法):先调用静态代码块,再普通代码

public static void main(String[] args) {
	System.out.println(Animal.n1); // 输出:我是Animal的静态代码块;100
}
class Animal {
	public static int n1 = 100;
		static {
		System.out.println("我是Animal的静态代码块");
	}
}

3、普通代码块:创建对象实例时,才会被调用,创建一次,调用一次,如果只是使用类的静态成员时,普通代码块不会执行。

总结:

**1、静态代码块**:随着类加载而调用,只会调用一次。
三种类加载情况:
a、创建对象时。b、创建子类对象也会调用父类静态代码块。
c、使用静态成员(静态变量和静态方法)。

**2、普通代码块**:只会随着对象的创建而调用,创建一次调用一次。


5.1、代码块细节1:

a、static代码块:类加载时调用,只会执行一次,因为类只会加载一次。

b、普通代码块:创建对象时调用,创建一次,调用一次。

5.2、代码块细节2、创建对象时,一个类的调用顺序:

1、如果有:首先调用静态代码块和静态属性初始化(静态代码块和静态属性初始化调用优先级一样,按从上到下写的顺序调用)。因为类加载是最先执行的,因此静态就最先执行。

2、然后调用普通代码块和普通属性的初始化(普通代码块和普通属性的初始化调用顺序优先级一样,也是按写的顺序调用)。

3、最后是调用构造方法。

5.3、代码块细节3:

构造方法的最前面其实隐藏了 super() 和 调用普通代码块两个内容。

class A {
	public A() {
		// 1、super();  这是隐藏的
		// 2、调用普通代码块  这是隐藏的
	}
}

5.4、代码块细节4:

静态代码块只能调用静态成员,普通代码块可以调用任意成员。


public static void main(String[] args) {
	BBB b = new BBB(); 
	/* 
	输出结果:
	super()调用父类AAA无参构造,因为无参构造隐藏了super(AAAsuper调用object的无输出,AAA调用本类普通代码块):
	1、输出第一句:我是AAA的普通代码块
	2、输出第二句:我是AAA的构造器
	3、输出第三句:我是BBB的普通代码块
	4、输出第四句:我是BBB的构造器
	*/
}

class AAA {
	{
		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、首先进行类的加载:先加载父类,再加载子类。 前面4句都是类加载输出的
2、创建对象:从子类构造器开始

public class Test {
	public static void main(String[] args) {
		new B02();
	}
}

class A02 {
	private static int n1 = getVal01();
	static {
		System.out.println("A02的第一个静态代码块");  // 第二句
	}
	{
		System.out.println("A02的第一个普通代码块");  // 第五句
	}
	public int n2 = getVal02();
	public static int getVal01() {
		System.out.println("getval01");  // 第一句
		return 10;
	}
	public int getVal02() {
		System.out.println("getVal02");  // 第六句
		return 11;
	}
	public A02() {
	// 隐藏super();   // 基础obj不输出
	// 隐藏普通代码块和普通属性  // 输出本类普通代码块普通属性
		System.out.println("A02的构造器");  // 第七句
	}
}

class B02 {
	private static int n3 = getVal03();
	static {
		System.out.println("B02的第一个静态代码块");  // 第四句
	}
	{
		System.out.println("B02的第一个普通代码块");  // 第八句
	}
	public int n4 = getVal04();
	public static int getVal03() { 
		System.out.println("getval03");  // 第三句
		return 10;
	}
	public int getVal04() {
		System.out.println("getVal04");   // 第九句
		return 11;
	}
	public B02() {  // 创建对象时从子类无参构造开始走
	// 隐藏super();        // 调用父类无参构造
	// 隐藏普通代码块和普通属性  // 调用本类普通代码块和普通属性
		System.out.println("B02的构造器");  // 第十句
	}
}

过程如下:

在这里插入图片描述

6、单例设计模式:

1、定义:采取一定方法,保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得对象实例的方法。
2、两种方法:饿汉式、懒汉式。

1、饿汉式单例模式:在没有使用对象实例之前就已经创建好了该对象,在类加载的时候就会创建对象,你不使用getinstance方法也会创建对象。

缺点:创建了对象但是没有使用,会造成资源的浪费。

步骤:
a、构造器私有化。 防止外部直接new一个对象。
b、类的内部创建对象。
c、向外暴露一个静态公共方法。

public class Test {
	public static void main(String[] args) {
		GirlFriend instance = GirlFriend.getInstance();
		System.out.println(instance);
	}
}

class GirlFriend {
	private String name;
	
	// 2、类的内部创建对象
	private static GirlFriend gf = new GirlFriend("小美");
	
	// 1、构造器私有化
	private GirlFriend(String name) {
		this.name = name;
	}
	
	// 3、提供一个公共静态方法,返回gf对象
	// 为什么使用静态方法:
	// 可以在外部不用创建对象 就能调用方法
	private static GirlFriend getInstance() {
		return gf;
	}
}
2、懒汉式单例模式:类加载的时候不会创建对象,当你要使用getinstance方法时才会创建,再次调用时,返回的是上一个创建的对象,不会创建两个对象。

1、构造器私有化,防止外面new。
2、定义一个静态属性(cat对象)。
3、提供一个公共的static方法,返回一个Cat对象。

public class Test {
	public static void main(String[] args) {
		Cat instance = Cat.getInstance();
		System.out.println(instance);
	}
}

class Cat {
	private String name;
	// 2、定义一个静态属性(cat对象)
	private static Cat cat;
	
	// 1、构造器私有化,防止外面new
	private Cat(String name) {
		this.name = name;
	}
	
	// 3、提供一个公共的static方法,返回一个Cat对象
	public static Cat getInstance() {
		if(cat == null) {  // 如果cat为空(说明还没有创建对象)
			cat = new Cat("小花");  // 就创建一个对象
		}
		return cat;  // 将创建好的对象返回
	}
}

在这里插入图片描述

7、final关键字:

final关键字可以用来修饰类、属性、方法和局部变量。
7.1、作用:

1、当不希望类被继承时,可以使用final修饰。

2、当不希望父类某个方法被子类覆盖/重写时,可以用final修饰。

3、当不希望类的某个属性值被修改时,可以用final修饰。

4、当不希望某个局部变量被修改时,可以用final修饰。

7.2、使用细节:

1、final关键字修饰的属性又叫常量,一般大写字母命名如:XX_XX_XX。

2、final修饰的属性在定义时必须赋值,并且以后不可再修改。可以在下面三个位置赋值:

// 1、定义时赋值。
public final double TAX_RATE = 1.1;
// 2、构造器中赋值。
public final double TAX_RATE2;
public AA() {
	TAX_RATE2 = 1.1;
}
// 3、代码块中赋值:
public final double TAX_RATE3;
{
	TAX_RATE3 = 1.1
}

3、如果final修饰的属性时静态的,则初始化的位置只能是:
a、定义时。
b、在静态代码块中,不可在构造器中赋值(静态代码块在类加载时调用,此时对象还未创建,不会调用构造器)。

4、final类不能被继承,但是可以实例化对象。

5、如果类不是final类,但是里面含有final方法,则该方法虽然不能被重写,但是可以被子类继承该方法。

6、一般来说,如果一个类是final类,就没必要将方法修饰呈final方法了。因为final类不能被继承,也就没有重写这一说了。

7、final不能修饰构造方法。

8、final和static往往搭配使用,效率更高。因为有final修饰的静态属性调用时不会导致类的加载。

public static void main(String[] args) {
	System.out.println(Demo.i);  // 10;不会加载类,静态代码块不会执行
}

class Demo {
	public static final int i = 10;
	static {
		System.out.println("hello word");
	}
}

9、包装类(Inerger、Double、Float等都是final修饰),不可被继承。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值