Java 当实例变量与类同名时
有人能用Java解释一下这句话的意思吗Java 当实例变量与类同名时,java,java-8,Java,Java 8,有人能用Java解释一下这句话的意思吗 public class Test{ // instance variables go here... protected static Test mtest; // methods go here } 我试图理解mtest所代表的领域。我知道在Java中,要创建一个对象的实例,我必须使用new关键字,但是这里没有使用这个关键字 在同一类中,我可以执行以下操作: mtest.someMethod(); 这使我
public class Test{
// instance variables go here...
protected static Test mtest;
// methods go here
}
我试图理解mtest所代表的领域。我知道在Java中,要创建一个对象的实例,我必须使用new关键字,但是这里没有使用这个关键字
在同一类中,我可以执行以下操作:
mtest.someMethod();
这使我相信这与C++中的这个指针的用法类似,例如
this->aMemberFunction();
有人能解释一下受保护的静态测试mtest是什么意思吗
这不是一个问题的重复:“为什么要避免在java中使用受保护的静态”
,正如你所说的,C++中的指针类似。但是,由于您没有初始化它,因此调用它的方法或访问它的字段将导致抛出NullPointerException
编译器允许您编写mtest.someMethod()因为编译器相信您最终会在程序运行时初始化mtest
。如果不这样做,正如我刚才所说,您将得到一个NullPointerException
要避免出现这种NullPointerException
,您需要创建一个新对象,并使用new
关键字将其分配给mtest
:
mtest = new Test();
正如您已经猜到的,这是对定义类测试的一个实例的引用。典型的用例是使用singleton模式,在这种模式中,您只有一个类的实例,并且可以防止私有构造函数创建额外的实例
public class Test {
private static final Test mtest = new Test();
private Test() { ... }
public static void method() { /* do something using mtest */ }
}
由于您声明了一个类,所以可以在其中使用该类的类型。
或者换句话说,您可以将任何测试或其子实例(规则,扩展测试的任何类)分配给mtest
字段:
public class Test{
//default constructor already present when we don't specify our own
protected static Test mtest = new Test();
}
当您不为此字段分配任何内容时,它将为空
public class Test{
protected static Test mtest; // null
}
既然我们已经解决了关于字段类型的问题,那个么让我们来谈谈静态修饰符和受保护修饰符。
静态意味着在jvm加载类之后立即初始化该字段,因为静态
字段属于类本身,我们可以将其与类的名称一起使用,即Test.mtest
当我们定义静态方法时,这里有相同的规则,我们以相同的方式使用它Test.doSomething()
换句话说,类就像是一种特殊的对象,我们可以调用方法或分配它的一个字段,但
还可以像blueprint一样使用它来创建实例。(类似于js中的原型)
但是我们不能从静态内容使用实例方法,因为从静态的角度来看
没有创建任何实例,我们只有类,因为在实例中提供了this
方法。它被传递给每个实例方法,但它对开发人员隐藏,在静态中,这个不存在。
受保护意味着您希望从扩展测试的不同包中进行分类,以便能够访问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,为keynew
调用值(函数)
对于创建新实例,我们需要传递新创建实例所在的对象
当新实例本身找不到方法时,将搜索这些方法
fooCat = Cat.new(Cat, "foo");
barCat = Cat.new(Cat, "bar");
首先,在对象fooCat中,我们试图通过键printName
找到函数并执行它。
为什么我们需要将foocat传递给foocatprintName
函数?因为只有一个地方
出现的名称“foo”是fooCat对象!
第二步,当fooCat在键值对中找不到该键(printName)时,fooCat将查看其原型
(我们之前在构造函数中通过语言setPrototype()
特殊函数指定的行为)
fooCat在Cat中找到函数,并将引用传递给它自身。
在该函数中,从传递的引用函数尝试通过键name
获取字符串值,并将其传递给打印方法。
在fooCat对象中,通过键name
将打印存储值“foo”和“foo”
fooCat.printName(fooCat);
静态
正在尝试从fooCat实例执行averageCatLifeInYears()方法
我们不需要将fooCat传递给函数
就像前面的例子一样,我们甚至可以从Cat类调用它
本身没有任何Cat类实例
Cat.averageCatLifeInYears() // no value passed to method
或者,fooCat尝试按名称查找方法并在Cat类中查找它,因为
该方法是静态的,我们不需要任何实例
传递给它,我们从中检索唯一信息,如前一个示例中所示:
fooCat.averageCatLifeInYears(); // no value passed, this method is static
在我们将这种语言推向世界后,许多开发人员开始抱怨
关于语言的冗长,我们决定添加一些语法糖和隐藏
这个哑函数将自己作为第一个参数传递给每个函数。
我们引入了全新的::操作符,借助于我们传递的对象,我们从中调用方法
作为该方法的第一个参数。
通过这种方式,我们将其隐藏在场景后面,但它仍然保留在原来的位置上,即使我们看不到它
fooCat = Cat::new(Cat, "foo");
fooCat = Cat::new(/*this hides here*/ "foo");
由于我们隐藏了详细信息,所以这些方法现在看起来是一样的,但这存在于printname()方法中
这两个方法具有不同的上下文,在java中,averageCatLifeInYears()将被标记为静态
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()
,而无需任何参数
并试图调用metho