毕25-第一天(day06)-面向对象

本文深入解析Java中的static关键字,探讨其在成员变量和成员方法上的应用,以及它带来的优势和限制。同时,文章还介绍了static代码块的作用和对象初始化过程。
  • static关键字

static是一个静态的修饰符,用于修饰成员(成员变量、成员函数)。当成员被静态修饰后,就多了一个调用方式,除了可以使用对象调用,还可以直接被类名调用,类名.静态成员。

class Person
{
	String name;    //实例变量,或成员变量
	static String country = "CN";    //静态成员变量,或类变量
	public void show() {
		System.out.println(name+"::"+country);
	}
}
public class Main{
	public static void main(String[] args) {
		//使用p.show(),则是对象调用
		Person p = new Person();
		p.name = "zhangsan";
		p.show();
		System.out.println(p.country);
		
		//还可以使用类名.静态变量
		System.out.println(Person.country);
	}
}

static特点:

1、随着类的加载而加载,会随着类的消失而消失。它的生命周期最长。

2、优先于对象而存在。明确一点:静态是先存在的,对象是后存在的。静态成员先被加载入方法区,而不是堆内存中。

3、静态数据被所有对象共享。

4、可以直接被类名所调用。

静态变量(类变量)与非静态变量(实例变量)的区别:

1、存放位置:类变量随着类的加载而存在与方法区中;实例变量随着对象的建立而存在与堆内存中。

2、生命周期:类变量生命周期最长,随着类的消失而消失;实例变量生命周期随着对象的消失而消失。

静态使用注意事项:

1、静态方法只能访问静态成员,非静态方法可以访问静态成员也可以访问非静态成员。

如:若将show方法改为static修饰,则在show方法内部的输出name则会出错,这是因为name为非静态成员变量,不能被静态方法所调用。但是原来的无static修饰的show方法,既可以访问非静态成员变量name,又能访问静态成员变量country。

2、静态方法不可以定义this、super关键字。这是因为静态优先于对象而存在,所以静态方法中不能出现this,this的出现是由于有对象的构建。

static修饰有利有弊:

利:对对象的共享数据进行单独空间的存储,节省空间,没有必要每一个对象中都存有一份静态成员。可以直接被类名调用。

弊:生命周期过长。访问出现局限性。(静态只能访问静态)

  • main函数

public static void main(String[] args)

主函数:是一个特殊的函数,作为程序的入口,可以被jvm所调用。

主函数的定义:

public:代表着该函数具有最大的访问权限;

static:代表主函数随着类的加载就已经存在了;

void:主函数没有具体的返回值;

main:不是关键字,但是是一个特殊的单词,可以被jvm所识别;

String[] args:函数的参数,参数类型是一个数组,该数组中的元素是字符串,表示字符串类型的数组。

主函数是固定格式的:jvm识别。

jvm在调用主函数时,传入的时new String[0];这个通过System.out.println(args.length)得到的结果为0所知道的。

一般不传入参数,但是在使用命令行进行运行Java程序时,可以传入需要的参数,如下面的实例:

class MainTest{
    public static void main(String[] aegs){
        System.out.println(args.length);
    }
}

使用命令行编译与运行:

javac MainTest.java
java MainTest haha hehe heihei

能够得到结果args数组的长度为3。

  • 静态什么时候使用

这包括两方面,因为静态修饰的内容有成员变量和成员方法。

什么时候定义静态变量:当对象中出现共享数据时,该数据被静态所修饰;对象中的特有数据要定义成非静态存在于堆内存中。

什么时候定义静态方法:当方法内部没有访问到非静态数据(对象的特有数据),那么该方法可以被定义为静态的。

静态的应用

比如现在在两个类别中都有一个获得最大值的方法,可以将这些共性的功能抽取出来,独立进行封装以便于复用。

现在可以定义一个工具类ArrayTool来抽取一些获得数组最值、数组排序等功能的类。

class ArrayTool{
	public int getMax(int[] arr){}
	public int getMin(int[] arr){}
	public void sort(int[] arrr){}
}

这样就可以通过建立ArrayTool的对象来使用这些工具方法,对数组进行操作:

int[] arr = {3,6,23,63,21};
ArrayTool at = new ArrayTool();
at.getMax(arr);

但是有一些问题:

1、对象是用于封装数据的,可是ArrayTool对象并未封装特有数据;

2、操作数组的每一个方法都没有用到ArrayTool对象中的特有数据。

因此可以不使用ArrayTool对象,可以将ArrayTool中方法都定义成static的,直接使用类名调用即可:

ArrayTool.getMax(arr);

将方法都静态修饰后,可以方便使用,但是该类还是可以被其他程序建立对象的。为了更严谨,强制该类不能建立对象,可以通过将构造函数私有化来实现:private ArrayTool(){}。

  • 静态代码块

格式:

static{

         静态代码块中的执行语句;

}

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

特点:随着类的加载而执行,只执行一次,并且优先于主函数。用于给类初始化。和前面的构造代码块区别下:构造代码块是给对象属性初始化的。

class StaticTest{
	StaticTest(){
		System.out.println("a");
	}
	static {
		System.out.println("b");
	}
	{
		System.out.println("c");
	}
	StaticTest(int x){
		System.out.println("d");
	}
}
class Main{
	public static void main(String[] args) {
		new StaticTest(4);
	}
}

先调用静态代码块,在调用构造代码块,然后调用对应的构造函数,故输出:b c d。

若StaticTest类中有int num = 9;,即有特定成员变量,则在静态代码块中就不能这样输出:System.out.println("a"+num);,因为num为非静态变量,不能被静态方法所调用。

  • 对象的初始化过程

class Person{
	private String name;
	private int age;
	private static String country = "cn";
	Person(String name,int age){
		this.name = name;
		this.age = age;
	}
	public void setName(String name) {
		this.name = name;
	}
	public void info() {
		System.out.println(this.name+"..."+this.age);
	}
	public static void showCountry() {
		System.out.println("country="+country);
	}
}
class Main{
	public static void main(String[] args) {
		Person p = new Person("zhangsan",20);
	}
}

在上面的程序中Person p = new Person("zhangsan",20);,这条语句都做了如下事情:

1、因为new用到了Person.class,所以会先找到Person.class文件并加载到内存中;

2、执行该类中的static代码块,如果有的话,给Person.class类进行初始化;

3、在堆内存中开辟空间,分配内存地址;

4、在堆内存中建立对象的特有属性,并进行默认初始化;

5、对属性进行显式初始化(定义属性时,属性赋予了初始值);

6、对对象进行构造代码块初始化;

7、对对象进行对应的构造函数初始化;

8、将内存地址赋给栈内存中的类变量p。

  • 对象调用成员过程

 注意方法区中,一部分为静态成员变量及方法,属于类中的共享成员。

在栈中,首先将main方法压入栈中,新建一个Person类指向p,name=zhangsan,age=20,将该对象存入堆中;

调用setName方法之后,将该方法压入栈,并且将堆中p指向的Person对象的地址传递到调用setName方法的栈中,将当前方法对应的对象的name修改为lisi;

之后又新建一个Person类指向p1,继续修改,整个调用过程就是如此。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值