面向对象--this和static关键字

本文深入解析Java中this与static关键字的使用场景与规则,包括this关键字在构造方法调用、成员变量访问中的作用,以及static关键字在方法、变量修饰上的特性与限制。通过具体案例,帮助读者掌握这两个关键字在实际编程中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 this关键字

定义:
this代表当前类的对象(谁调用我我就代表谁),记录的是对象的地址。
应用:
(1)访问对象的成员(包括属性、方法);
(2)调用类的构造方法;

引言

一个类可以创建无数个对象,无数个对象都去调用一个构造方法,那么如果不指名到底是哪个对象,这样就会造成问题,因为构造方法并不知道到底是给哪个对象进行初始化的,所以java提供了this来对对象进行标识。
(1)this(参数):就会调用对应的构造方法
(2)this可以标识成员变量,可以进行省略,但是如果当局部变量和成员变量同名时,就必须要明确this.来标识是成员变量。

1.1 案例
public class Person {
//	属性
	String name;
	int age;
//	无参构造方法
	public Person(){
	}
//	带参构造方法一(一出生就有名字)
	public Person(String name){
		//	调用无参构造方法,可省略不写,但要定义在第一行
		this();
		//	this.name代表成员变量,name代表局部变量
		this.name = name;
	}
//	带参构造方法二(一出生就有名字和年龄)
	public Person(String name,int age){
		//	调用带参构造方法一:
		this(name);
		this.age = age;
	}
//	成员方法一
	public void speak(){
		//局部变量要进行初始化
		String name = "小红";
		int age = 66;
//(1)当方法中定义了变量时,this.name代表成员变量,age代表局部变量
//(2)当方法中没有定义变量,this可以省略不写,this下不屑均代表成员变量
		System.out.println("name="+name+",age="+age);
	}
//	成员方法二
	public void call(){
		//调用成员方法一
		this.speak();
//在一个方法中,调用其他方法时,也是有this的指向,但此处this可以省略不写
	}
}
public class PersonDemo {
	public static void main(String[] args) {
		//	创建对象
		Person p1 = new Person("coco",18); 
		Person p2 = new Person("xiaoran",28);
		//	调用方法
		p1.speak();
		p2.speak();
	}
}

堆栈运行图:
在这里插入图片描述
初始化过程文字描述:
(1)new Person()生成一个首地址值,main方法压栈,p1=0x0011
(2)new Person(“coco”,18)对象调用带有两个参数的构造方法(this=0x0011),方法进栈先执行this(name),又调用带有一个参数的构造方法(this=0x0011)。
(3)this.name指的是对象里面的name成员变量。继续执行则this.name=name=”coco”,方法弹栈。在继续执行this.age=age=18,含有两个参数的构造方法弹栈。

1.2 注意事项

(1)一般方法中不能够调用构造方法,而构造方法中可以调用一般方法。
一般方法中不能调用构造方法,是因为构造方法是创建对象时只调用一次对对象进行初始化。构造方法中可以调用一般方法,是因为构造方法进行初始化时需要某些功能(也可以理解为对构造方法中的部分代码也进行封装)。
(2)调用构造方法的语句要放在构造方法第一行,因为要先完成初始化对象。
(3)一个构造方法中不能同时调用两个构造方法(即一个构造方法只能有一个this)。
(4)两个构造方法之间不能互相调用。
(5)自己调用自己,进入死循环,报错。
在这里插入图片描述

2 static关键字

引言
public class Static_introduce {
	// 属性
	String name;
	int age;
	// 构造方法
	public Static_introduce(String name, int age) {
		this.name = name;
		this.age = age;
	}
	// 一般方法一
	public void speak() {
		System.out.println("name=" + name + "age=" + age);
	}
	// 一般方法二
	public static void sleep() {
		System.out.println("天黑了,该睡觉了");
	}
}
public class Static_introduce_demo {

	public static void main(String[] args) {
		//	创建对象
		Static_introduce person = new Static_introduce("coco",18);
		//对象调用方法
		person.speak();
		person.sleep();
	}
}

对封装类方法的调用时,speak()方法调用了对象内部的成员变量,成员变量随着对象的产生而产生,因此需要创建对象对象名调用方法。创建对象是为了产生实例,并进行数据的封装,而调用sleep()方法时却没有使用到对象封装的数据,
那么对象创建还有意义吗?
—答案肯定是没有意义的。虽然创建对象编译运行都没有问题,但是会在堆内存中创建对象,空间较为浪费。因为封装在对象中的数据一个都没有进行使用,所以不建议创建对象。
java就给出了一个解决办法:使用静态static关键字。

2.1 static调用方法

被静态修饰的方法有两种调用方法:
(1)可以被对象调用(不建议使用)
Person.sleep();
(2)可以被类名调用
Static_introduce.sleep();

2.2 static的使用

static用于修饰可供外界无需实例化直接使用的方法或属性。

2.3 静态成员特点

(1)静态成员函数只属于类,随着类的加载而加载,随着类的消失而消失。
(2)静态方法不能够访问非静态成员,但是非静态成员中可以访问静态。
原因是优先级,静态是先于对象存在。(静态方法无法访问后面创建的对象中的数据,所以静态无法书写非静态。而非静态成员可以通过创建对象调用或者类名直接调用。)
(3)在静态方法中不允许出现this,super关键字
因为这时候对象还有可能不存在,this没有任何的指向。
(4)静态成员被所有的对象共享使用。

2.4 静态优缺点

(1)弊端在于访问出现了局限性
(2)好处是静态成员可以由类调用,被所有对象共享,节省空间。

2.5 成员变量和静态变量的区别

(1)所属的范围(名称)不同
静态变量(类变量)所属于类
成员变量(实例变量)所属于对象
(2)内存存储区域不同
静态存储在方法区中,也称为数据共享区
成员变量存储在堆内存中
(3)加载时期不同
静态变量随着类的加载而加载
成员变量随着对象的加载而加载
(4)调用不同
静态变量可以被对象和类调用(一般都是类名调用)
成员变量只能够被对象调用

2.6 案例(获取圆的面积)
public class Circle {
	// 属性私有化
	private double radius;
	// 3,14是一个固定不变的值,可以在类中定义一个常量。
	// 每次创建对象都会出现pi占据内存空间,因此可以使用static对成员修饰。
	private static double pi = 3.14;
	// 构造方法
	public Circle(double radius) {
		this.radius = radius;
	}
	// 行为
	public double getArea() {
		// this和Circle可以忽略不写
return this.radius * this.radius * Circle.pi;
	}
}
public class CircleDemo {

	public static void main(String[] args) {
		//	创建对象
		Circle c = new Circle(5.5);
		//	调用获取面积方法getArea();并输出
		double area = c.getArea();
		System.out.println(area);
	}
}

内存图:
在这里插入图片描述
(1)运行程序后执行CircleDemo类,在方法区开辟一块区域,该区域会有一个当前类默认的无参构造方法
(2)执行main方法,存在于静态区中,main方法进栈。
(3)先加载Circle类在创建(new)对象。在方法区开辟一块专门存放Circle类的区域。执行Circle类内部的成员和属性。成员变量radius、构造方法Circle(double radius)和成员方法getArea()存放在Circle类中。而静态变量pi存放静态区中。
(4)创建Circle对象。先在堆中开辟一块区域,自动生成一个首地址值0x0011。有参构造方法Circle(double radius)进栈,this指向该对象,对对象进行初始化,初始化完成后出栈。之后main方法中引用变量c指向该对象,这样对象就不会被回收。
(5)调用getArea()方法,方法进栈,执行后出栈。
补充:
(1)方法区是存在的,堆栈是调用,会进行方法进栈弹栈或者对象回收机制。
(2) Circle类中3,14是一个固定不变的值,可以在类中定义一个常量。
由于每次创建对象都会出现pi都会出现在堆中,占据内存空间,因此可以使用static对成员修饰。使其跟随类的加载而出现,就可以实现对对象数据共享。

3 静态代码块

格式:

		static{
				//静态代码块执行的区域
		}
作用:随着类的加载而加载,只执行一次,用于给类进行初始化。
作用方式:静态代码块是在静态变量显示初始化之后再执行的

应用场景:类不需要创建对象,但是需要初始化。

class Base {
	static {
		System.out.println("a");
	}
}

public class StaticBase {
	static {
		System.out.println("b");
	}
	public static void main(String[] args) {
		new Base();
		new Base();
	}
	static {
		System.out.println("c");
	}
	static {
		System.out.println("d");
	}
}

输出结果:b c d a
static是指创建对象调用类一个static静态代码块只执行一次。

4 构造代码块

格式:
		{
			//代码
		}

作用:给对象初始化,每创建一次对象都会被调用。可以把不同构造方法中相同共性的内容定义在里面。
执行顺序上,构造代码块优先于构造方法。其次,构造代码块是给所有对象进行统一初始化,而构造方法是给对应的对象初始化。

public class StaticExpend {

	public static void main(String[] args) {
		new Demo06(4);
	}
}

class Demo06 {
	int num = 8;
	Demo06() {
		System.out.println("a");
	}
	Demo06(int x) {
		System.out.println("b");
	}
	static {
		System.out.println("c");
	}
	{
		System.out.println("d" + this.num);
	}
}

输出结果:c d8 a

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值