为什么java中一切都是对象,还要有static? [复制链接]

2019-11-13 10:09
技术小兵 阅读:390 评论:0 赞:1
Tag:  static

Java是一种面向对象编程的语言,而对象是客观存在的事物,对同类对象抽象出其共性,便是Java中的类,类是对象的模子,具有相同属性和方法的一组对象的集合。有了类的定义,我们就可以用类来描述世上任何东西。然而,有一个特殊的东西不属于对象,它就是static。

1。 static的“由来”

咱们先来分析一下以下代码:

public class Demo {
public static void main(String[] args) {
//实例化一个p1
Person p1=new Person();
p1.name="xiaoming";  
p1.speak();
//实例化一个p2
Person p2=new Person();
p2.name="xiaohong";  
p2.speak();
}
}

class Person{
String name;
//CN是显示初始化值
String country="China";
void speak(){
System.out.println("My name is "+name+",my country is "+country);
}
}

  通过分析上面的代码,不难发现p1和p2两个对象中,存在一个相同的属性值country="China"。接下来我们通过内存示意图来观察下:

为什么java中一切都是对象,还要有static?

  从上图中我们可以注意到红色框中的内容是重复存在于堆中的。倘若对象越建越多,那么堆中的重复数据也会越来越多,这样就会导致内存造成不必要的消耗。既然各个对象中都存在同样的数据,那么何不将这些相同的数据单独拿出来并且单独存放呢?现在将Person类中的country字段加上static,其他不做改动:

class Person{
String name;
//将数据值相同且共用的用static修饰,成为类变量
static String country="CN"; 
void speak(){
System.out.println("My name is "+name+",my country is "+country);
}
}

  于是,我们将相同的数据放到静态存储区内,并让静态存储区中的数据共享给所有对象,这样就可以大大减少了不必要的内存损耗,可见static关键字的作用。

2.static的使用场景

在《Java编程思想》有这样一段话:
  “static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。这实际上正是static方法的主要用途。”
  这段话虽然只是说明了static方法的特殊之处,但是可以看出static关键字的基本作用,简而言之,一句话来描述就是:方便在没有创建对象的情况下来进行调用(方法/变量)。下面我们就来探讨一下static的几个使用场景。

1)修饰成员变量和成员方法

  用static修饰成员变量可以说是该关键字最常用的一个功能,通常将用static修饰的成员变量称为类成员或者静态成员。本文就是通过该使用场景抛砖引玉,描述了static关键字的“由来”。在jvm的内存构造中,会在堆中开辟一块内存空间,专门用来存储用static修饰的成员变量,称为静态存储区,无论我们创建多少个对象,用 static 修饰的成员变量有且只有一份存储在静态存储区中,所以该静态变量的值是以最后创建对象时设置该静态变量的值为准。并且任何对象都可以对静态存储区中的成员变量做出修改,静态存储区中的成员变量的值以最后一次修改为准。值得一提的是,在JDK1.8以前,静态存储区是存放在方法区的,而方法区不属于堆,在JDK1.8之后,方法区中的静态存储区改为到堆中存储。
  用static修饰方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有this指针的,因为它不依附于任何对象,既然都没有对象,就谈不上this了。并且由于这个特性,在静态方法中不能访问类的非静态成员变量和非静态成员方法,因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用。但是要注意的是,虽然在静态方法中不能访问非静态成员方法和非静态成员变量,但是在非静态成员方法中是可以访问静态成员方法/变量的。

2)静态代码块

  静态代码块定义在类中方法外, 静态代码块在非静态代码块之前执行,执行顺序为静态代码块—>非静态代码块—>构造方法—>静态方法。我们来运行以下程序:

Public class Main {
Static {
System.out.println(“静态代码块”);
}
{
System.out.println(“非静态代码块”);
}
public Main(){
System.out.println(“构造方法”);
}
public static void eat(){
System.out.println(“静态方法”);
}
public static void main(String[] args) {
Main main = new Main();
Main.eat();
}
}
运行结果:
静态代码块
非静态代码块
构造方法
静态方法

  而在java继承关系中静态代码块、代码块、构造方法的执行顺序为父类静态代码块—>子类静态代码块—>父类代码块—>父类构造—>子类代码块—>子类构造,可以通过下列代码来判断:

public class Demo {
public static void main(String[] args) {
new H2();
}
}
//父类H1
class H1{
{
System.out.println("父类代码块");
}
public H1(){
System.out.println("父类构造");
}
static{
System.out.println("父类静态代码块");
}
}
//H2继承H1
class H2 extends H1{
static{
System.out.println("子类静态代码块");
}
{
System.out.println("子类代码块");
}
public H2(){
System.out.println("子类构造");
}
}
运行结果:
父类静态代码块
子类静态代码块
父类代码块
父类构造
子类代码块
子类构造

  static关键字可以利用这些特性,通过形成静态代码块来优化程序性能。静态代码块可以存在于类的任何一个地方,并且一个类可以有多个静态代码块,在类初次被加载的时候,会按照静态代码块声明的顺序来依此执行,并且只会执行一次。那么,我们就可以利用静态代码块只加载一次的特性,将不需要重复加载的数据放入静态代码块中来优化程序。

3)静态内部类

  内部类指的是定义在一个类的内部的类,包含内部类的类成为外部类,而静态内部类指的是用 static 修饰的内部类。定义内部类的好处是外部类可以访问内部类的所有方法和属性,包括私有方法和私有属性。下面通过代码来理解静态内部类的使用:

//定义一个普通外部类
public class OutClass {
//定义一个普通内部类
public class InnerClass{

}
}

北京福彩网  这里我们要想访问普通内部类,就必须先创建外部类的对象,然后通过外部类名.new 创建内部类的实例,例如第一步:OuterClass oc = new OuterClass();第二步:OuterClass.InnerClass in = oc.new InnerClass();。显然,这样的做法不是很友好。

//定义一个普通外部类
public class OutClass {
//定义一个静态内部类
public static class InnerClass{

}
}

  如果将普通内部类改为静态内部类,添加static关键字,我们就不需要创建外部类的对象,而是可以直接通过外部类名。内部类名来创建实例,例如OuterClass。InnerClass sic = new OuterClass。InnerClass();。这样就会显得简单很多。

3。关于static的常见问题

1)static关键字会改变类中成员的访问权限吗?

不会。Java中的static关键字不会影响到变量或者方法的作用域。在Java中能够影响到访问权限的只有private、public、protected(包括包访问权限)这几个关键字。

2)静态变量可以存在于普通方法中吗?

可以。普通方法必须通过对象来调用,静态变量可以直接通过类名来调用,也可以通过对象来调用,所以是可以存在于普通方法中的。

3)静态方法能存在普通变量吗?

不能。因为静态方法可以直接通过类名来直接调用,不用创建对象,而普通变量是必须通过对象来调用的。

4)static 可以用来修饰局部变量吗?

不能。在C/C++中static是可以作用域局部变量的,但是在Java中切记:static是不允许用来修饰局部变量。不要问为什么,这是Java语法的规定。

4.总结

  总的来说,static关键字主要作用就是方便在没有创建对象的情况下进行调用方法/变量。当static修饰成员变量和方法时,该变量就成为了所有对象的公共数据,可以直接通过类名来调用而不用创建对象;当static修饰代码块时,该代码块会在类初次被加载的时候被加载,且只会加载一次,这里需要注意加载顺序的问题;当static修饰内部类时,可以使得操作内部类变得想对简单。另外,根据static的特性,产生了一种重要的设计模式——单例设计模式。这里做个简单介绍,程序实例如下:

class Singleton{
private static Singleton instance = null;
private Singleton(){}
public static getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}

  单例设计模式的特点是该类只能有一个实例,为了实现这一功能,必须隐藏类的构造函数,即把构造函数声明为private,并提供一个创建对象的方法,由于构造对象被声明为private,外界无法直接创建这个类型的对象,这里就可以把创建对象的方法声明为static,通过使用类名来调用方法创建对象,从而完成该模式的设计


我来说两句
您需要登录后才可以评论 登录 | 立即注册
facelist
所有评论(0)
领先的中文移动开发者社区
18620764416
7*24全天服务
意见反馈:1294855032@qq.com

扫一扫关注我们

Powered by X3.2© 2001-2019 ( )

王者彩票开户 甘肃快3 甘肃快3走势图 江西快3 天津福彩网 甘肃快3 重庆快乐十分 吉林体彩网 海南福彩网 青海福彩网