当实例变量与类同名时

时间:2018-02-02 20:28:32

标签: java java-8

有人可以在Java中解释这个含义

 public class Test{
     // instance variables go here...

     protected static Test mtest;

     // methods go here
 }

我试图掌握mtest所代表的内容。我知道在Java中创建一个对象的实例我必须使用new关键字,但是这里没有使用它。

在同一课程中,我可以采取以下行动:

   mtest.someMethod();

这让我相信这类似于在C ++中使用this指针,例如

   this->aMemberFunction();

有人可以解释一下受保护的静态测试mtest的含义吗?

这不是问题的重复:"为什么要避免在Java中使用受保护的静态"

3 个答案:

答案 0 :(得分:1)

正如你所说,它类似于C ++中的指针。但是,由于您没有初始化它,调用方法或访问它的字段将导致NullPointerException被抛出。

编译器允许您编写mtest.someMethod();,因为编译器信任您在程序运行时最终会初始化mtest。如果你不这样做,就像我刚才说的那样,你会得到NullPointerException

要避免此NullPointerException,您需要使用mtest关键字创建新对象并将其分配到new

mtest = new Test();

答案 1 :(得分:0)

正如您已经猜到的那样,这是对定义class Test的实例的引用。典型的用例是单例模式,其中您只有一个类的实例,并且可以防止私有构造函数创建其他实例。

public class Test {
    private static final Test mtest = new Test();
    private Test() { ... }
    public static void method() { /* do something using mtest */ }
}

答案 2 :(得分:0)

由于您声明了一个类,因此您可以在其中使用此类的类型。  或者换句话说,您可以将任何测试或它的子实例(IS-A规则,任何扩展测试的类)分配到mtest字段:

 public class Test{

     //default constructor already present when we don't specify our own 
     protected static Test mtest = new Test();

 }

如果您没有为此字段指定任何内容,则它将为null

public class Test{

     protected static Test mtest; // null

 }

因此,自从我们解决了关于字段类型的问题后,我们来谈谈静态和受保护的修饰符。 静态意味着字段在jvm加载的类之后正确初始化,因为静态 field属于class本身,我们可以使用它的类名Test.mtest 当我们定义静态方法时,同样的规则在这里,我们以相同的方式使用它Test.doSomething()     换句话说,类就像特殊类型的对象我们能够调用方法或指定它的字段但是 也可以像蓝图一样使用它来创建实例。 (像js中的原型)     但是从静态的角度来看,我们无法使用静态内容中的实例方法 没有创建任何一个实例,我们只有类,因为实例方法呈现this。它被传递给每个实例方法,但它隐藏在开发人员和静态this中不存在。 protected意味着您希望从扩展的不同包中进行分类测试能够访问mtest字段 但是测试包之外的任何一个课都没能看到mtest字段。

静态而非静态上下文。

当我们删除所有语法糖并试图理解时 低级别的静态而非静态上下文就像那样(基于原型的oop,它是js,lua等语言处理oop的方式)

对于类和实例的建模,我们只需要一个行为类似Map(键 - 值对)和函数的结构:

让我们定义类型(对象)cat,我们需要生成其中的许多 因为我们想拥有许多猫,所以我们需要把它存放在哪里 独特的特征 这个地方将是单独的对象{}

Cat = {
    new = (this, name) -> {         
        newCat = {};                //create empty object {}
        newCat.name = name;         //assign to key name of this object value name
        setPrototype(newCat, this)  // assign where is newCat will search for keys (Cat object)  
                                    //when it's no able to find it in ourself 
        return newCat;              // return newly created cat
    }

// THIS passed to method, it's method like instance method in java but in java THIS is hidden
    printName = (this) -> {         
        print ("hello " .. this.name)
    },

// no THIS keyword here, same as static methods in java
    averageCatLifeInYears = () -> { 
        print(10);
    }


};

<强>实例

它是如何工作的: 我们有Cat对象,其行为类似于java中的map,为key new调用value(function) 为了创建新实例,我们需要传递新创建实例的对象 将在新实例本身找不到它们时搜索方法

fooCat = Cat.new(Cat, "foo");  
barCat = Cat.new(Cat, "bar");

首先,在对象fooCat中,我们尝试按键printName查找函数并执行它。 为什么我们需要将foocat传递给foocat printName函数?这只是一个地方 名称“foo”存在的是fooCat对象! 第二步当fooCat没有在键值对中找到该键(printName)时fooCat看到它的原型 (我们之前通过语言setPrototype()特殊功能在构造函数中分配的行为) fooCat在Cat中查找函数并将其传递给它自己。 在该函数中,来自传递的引用函数试图通过键name获取字符串值并将其传递给print方法。 在fooCat对象中,按键name将存储值“foo”和“foo”。

 fooCat.printName(fooCat); 

<强> STATIC

尝试从fooCat实例执行averageCatLifeInYears()方法 我们不需要传递fooCat来运行 像前面的例子一样,或者甚至更多我们能够从Cat类调用它 本身没有任何Cat类实例!

Cat.averageCatLifeInYears() // no value passed to method

或者,fooCat尝试按名称查找方法,然后在Cat类中找到它 那个方法STATIC我们不需要任何实例
传递给它,我们从中检索唯一的信息,如上例所示:

 fooCat.averageCatLifeInYears(); // no value passed, this method is static

在我们向世界出现这种语言后,许多开发人员开始抱怨  关于语言详细程度,我们决定添加一些语法糖和隐藏  哑巴将自己传递给每个函数作为第一个参数。 在传递了被称为方法的对象的帮助下介绍全新的::运算符 作为该方法的第一个参数。 通过这种方式,我们将它隐藏在场景背后,但即使我们看不到它,它仍然保留在它的位置。

fooCat = Cat::new(Cat, "foo");  
fooCat = Cat::new(/*this hides here*/ "foo"); 

因为我们隐藏了详细程度,现在方法看起来一样,但是在printnName()方法中存在 这两种方法有不同的上下文,在java中,averageLatLifeInYears()将标记为STATIC

fooCat::printName(); 
Cat::averageCatLifeInYears();

那么为什么在java中我们无法使用静态的实例上下文?  尝试重写我们的Cat类以在java中模拟它

Cat = {
    new = (this, name) -> {         
        newCat = {};                
        newCat.name = name;         
        setPrototype(newCat, this)  
        return newCat;              
    },


    printName = (this) -> {  // need instance where is placed name to work
        print ("hello " .. this.name)
    },

    //tryint to invoke instance context from static
    averageCatLifeInYears = () -> { 
        print(10);
        //lets try to invoke printName from this method...
        printName(?????) // WHAT WE NEED TO PLACE HERE???
    }
};

因为我们可以在没有任何参数的情况下从Cat调用averageCatLifeInYears()             并尝试从我们得到名称调用需要参数(THIS)的方法             我们在运行时遇到错误,或者在java等更智能的语言中出现COMPILE错误。