阿里云【名师课堂】Java面向对象开发44 ~ 47:static关键字

阿里云【名师课堂】Java面向对象开发44 ~ 47:static关键字

44:static属性

在讲解之前首先观察一道程序:

  • 范例:定义一个表示人的类,同时设置他所在的国家
class Person{
	private int age	;
	private String name ;
	String country = "China";  // 为了后面的操作方便,暂时不封装,当然这样是不对的
	
	public Person(String name,int age) {
		this.age = age ;
		this.name = name ;
	}
	
	public String getInfo() {
		return "【PERSON】姓名:" + this.name + 
		",年龄:" + this.age + ",国家:" + this.country;
	}
}

public class TestDemo {
	public static void main(String args[]) {
		Person p1 = new Person("Dexter",20) ;
		Person p2 = new Person("Tsukishima Kei",18) ;
		Person p3 = new Person("Toono Takaki",19) ;
		System.out.println(p1.getInfo()) ;
		System.out.println(p2.getInfo()) ;
		System.out.println(p3.getInfo()) ;
	}
}

在这里插入图片描述
下面对这三个对象进行内存分析:
在这里插入图片描述
既然描述的country都是China,那么理论上这些country属性是相同的,此时可以发现每一个对象的country属性被重复保存了。
那么假如国家的名称要换个表示方法(英文➡中文、简写➡全称之类),按以上的储存方式就会出现一个问题:

  • 假设当前Person类已经产生了十亿个对象,而需要把名称换为中文表示,要通过对象.country = "中文名" ;操作十亿次来改变。
public class TestDemo {
	public static void main(String args[]) {
		······
		p1.country = "中国" ;
		······
	}
}

在这里插入图片描述
现在可以发现传统属性具备的特征:保存在堆内存之中,每一个对象独享此属性。可是同样的概念明显不适合于当前的情况,所以最好的做法是将country属性变为一个共享属性,那么只要一次修改就可以影响到所有的对象。

  • 而如果要将属性变为共享属性,只要在属性前追加一个static关键字即可。
class Person{
	······
	static String country = "China";  // 为了后面的操作方便,暂时不封装
	······
	}
}

public class TestDemo {
	public static void main(String args[]) {
		······
		p1.country = "中国" ;
		······
	}
}

在这里插入图片描述
当程序中使用了static关键字进行定义之后,此属性不会保存在堆内存之中,而是在名为全局数据区的内存空间之中,并且所有对象都可以进行该数据区的访问。
在这里插入图片描述
既然使用的是共享属性,有一个问题:共享属性能通过一个对象修改吗?

  • 虽然上面代码通过对象p1修改static属性country,但实际上正确操作应该是类名.属性 = "修改" ;
  • static实际上可以称为类属性,而所有类属性都可以通过类名称直接调用。
  • 结论:访问static属性使用类名称

所有的非static属性必须在产生实例化对象之后才可以使用,而所有static属性不受实例化的限制,也就是说是否有对象与static属性的操作无关。

  • 选择:关于static属性与非static属性的选择
    • 在定义类时99%的情况下是不会考虑static属性的;
    • 只有在需要描述共享属性的概念或者希望不受实例化控制时使用static

45:static方法

既然通过static定义的属性可以被类名称直接访问,那么static定义的方法也可以被类名称直接访问,同样不受实例化的限制。
范例:观察static定义的方法

class Person{
	private int age	;
	private String name ;
	private static String country = "China";  // 为了后面的操作方便,暂时不封装
	
	public Person(String name,int age) {
		this.age = age ;
		this.name = name ;
	}
	
	public static void setCountry(String c){
		country = c ;
	}
	public String getInfo() {
		return "【PERSON】姓名:" + this.name + 
		",年龄:" + this.age + ",国家:" + this.country;
	}
}

public class TestDemo {
	public static void main(String args[]) {
		Person p1 = new Person("Tsukishima Kei",18) ;
		System.out.println(p1.getInfo()) ;
		Person.setCountry("中国") ;
		System.out.println(p1.getInfo()) ;
	}
}

在这里插入图片描述
现在类中既有static方法又有非static方法,那么这时对于两者的互相调用存在两点限制:

  1. 所有static方法不允许调用非static属性或者方法;
	public static void setCountry(String c){
		name = "avasd" ;
		country = c ;
	}
	// 编译报错,错误: 无法从静态上下文中引用非静态 变量 name
	public static void setCountry(String c){
		getInfo() ;
		country = c ;
	}
	// 编译报错,错误: 无法从静态上下文中引用非静态 方法 getInfo()
  1. 所有的非static方法允许访问static属性或方法
	public String getInfo() {
		setCountry("中国中国") ;
		return "【PERSON】姓名:" + this.name + 
		",年龄:" + this.age + ",国家:" + this.country;
	}

在这里插入图片描述
原因:因为所有的static方法可以在没有实例化对象的时候访问,而所有的非static操作必须在有实例化对象之后才可以进行。
使用static属性的目的是共享,因为属性都需要封装。而是用static方法的目的在于:某些方法不希望受到类的限制,即希望可以在没有实例化对象的时候执行。

46:分析主方法组成

如果一个方法定义在主类之中,并且由主方法直接调用,那么该方法的定义语法如下:

  • public static 返回值类型 方法名称(参数列表) {}

后来进行类的学习时没有用到static(非主类中),主要原因是static方法的限制。
观察Java主方法名的组成:

  • public static void main(String args[]) {}
  • public:表示是公用的,因为主方法作为程序起点必须可以随意访问;
  • static:执行Java程序时执行的是一个类名称,所以表示不受实例化对象限制;
  • void:主方法作为程序起点,是栈中最底层的函数,所以并不存在能够接收的值(没有谁能接收main的返回值);
  • main:是一个系统定义好的方法名称(主方法默认名称);
  • String args[]:表示该类执行时所需要的相关参数。
    • 范例:取得执行参数
public class TestDemo {
	public static void main(String args[]) {  // 所有参数类型都是String型
		for(int x = 0 ; x < args.length ; x++){
			System.out.println(args[x]) ;
		}
	}
}
  • 通过如图所示方式进行参数设置,可以看到没有设置参数时没有任何输出。
    在这里插入图片描述

static应用

基于static的共享特性,可以利用static做一个对象产生的计数统计。比如:想要知道一个类在本次操作中产生了多少对象,通过所有对象共享同一个static属性来实现。所有新对象的产生一定要使用构造方法进行实例化,所以可以在构造方法中实现统计。
范例:对象产生个数统计

class Person{
	private static int count = 0 ;
	
	public Person(){
		System.out.println("对象个数:" + ++count) ;
	}
}

public class TestDemo {
	public static void main(String args[]) {
		new Person() ;
		new Person() ;
		new Person() ;
	}
}

在这里插入图片描述
在此基础上做一个简单扩充:

  • 假设现在Person类中有一个name属性以及两个构造方法,其中一个有参构造方法可以接收外部传递的name属性内容,而另一个构造方法是无参构造,一旦使用无参构造就希望可以自动为类中的name属性做一个设置,那么此时就可以使用static的属性控制。
class Person{
	private String name ;
	private static int count = 0 ;
	
	public Person(){  // 自动为类中的name属性做一个设置
		this("改名" + ++count) ;
	}
	public Person(String name){  // 接收外部传递的name属性内容
		this.name = name ;
	}
	
	public String getName(){
		return this.name ;
	}
}

public class TestDemo {
	public static void main(String args[]) {
		System.out.println(new Person().getName()) ;
		System.out.println(new Person("Dexter").getName()) ;
		System.out.println(new Person().getName()) ;
	}
}

在这里插入图片描述

总结

  1. static定义的属性和方法并不是在进行类的设计时的第一选择,常用还是非static属性和方法。
  2. static定义的属性和方法不受一个类的实例化对象限制,可以由类名称直接调用。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值